Skip to content

damourlabs/ui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

82 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@damourlabs/ui

A comprehensive Vue 3 + Nuxt 3 UI component library with advanced form generation capabilities, built with TypeScript, TailwindCSS, and modern web technologies.

✨ Features

  • 🎨 Modern UI Components - Built with shadcn/ui and TailwindCSS
  • πŸ”§ Dynamic Form Generation - Automatic form creation from Zod schemas
  • πŸ“Š Chart Components - Data visualization with vue-charts
  • πŸŒ™ Dark Mode Support - Built-in theme switching
  • 🧩 Modular Architecture - Import only what you need
  • πŸ”’ Type Safety - Full TypeScript support
  • 🎯 Form Validation - Advanced validation with vee-validate and Zod
  • πŸ”— Resource Management - Smart resource field handling and linking
  • πŸ“± Responsive Design - Mobile-first approach
  • β™Ώ Accessibility - ARIA compliant components

πŸš€ Quick Start

Installation

Add the layer to your Nuxt project:

npm install @damourlabs/ui
# or
pnpm add @damourlabs/ui
# or
yarn add @damourlabs/ui

Setup

Add the layer to your nuxt.config.ts:

export default defineNuxtConfig({
  extends: ['@damourlabs/ui'],
  // your config
})

That's it! The layer will automatically configure:

  • TailwindCSS with custom theme
  • Component auto-imports with Ui prefix
  • Dark mode support
  • Form validation setup
  • Chart components

πŸ“š Core Components

🎯 Dynamic Form System

The crown jewel of this library is the dynamic form generation system that automatically creates forms from Zod schemas.

Basic Usage

<template>
  <div>
    <UiDynamicForm 
      :schema="formSchema" 
      :submit-fn="handleSubmit"
      :sections="true"
    />
  </div>
</template>

<script setup lang="ts">
import { z } from 'zod'
import { createDynamicForm } from '@damourlabs/ui/utils/form'

// Define your schema
const userSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  age: z.number().min(18, 'Must be at least 18 years old'),
  isActive: z.boolean().default(true),
  role: z.enum(['admin', 'user', 'moderator']),
  profile: z.object({
    bio: z.string().optional(),
    website: z.string().url().optional(),
  })
})

// Generate the form
const formSchema = createDynamicForm(userSchema)

const handleSubmit = (values: any) => {
  console.log('Form submitted:', values)
}
</script>

Advanced Form Configuration

import { createDynamicForm, type CreateDynamicFormOptions } from '@damourlabs/ui/utils/form'

const options: CreateDynamicFormOptions = {
  // Configure resource fields for foreign key relationships
  resourceFields: [
    { 
      field: 'user', 
      store: 'users', 
      displayField: 'email',
      searchFields: ['name', 'email']
    },
    { 
      field: 'project', 
      store: 'projects', 
      displayField: 'name' 
    }
  ],
  
  // Fields to exclude from form generation
  fieldsToIgnore: ['id', 'createdAt', 'updatedAt'],
  
  // Custom field type mappings
  fieldTypeMapping: {
    [z.ZodFirstPartyTypeKind.ZodString]: {
      as: 'textarea',
      inputType: 'text',
      handler: (fieldSchema, field, context) => {
        if (context.key === 'description') {
          field.as = 'textarea'
        }
      }
    }
  }
}

const formSchema = createDynamicForm(userSchema, options)

🎨 UI Components

All components are built with accessibility and customization in mind:

Buttons

<template>
  <UiButton variant="default">Default Button</UiButton>
  <UiButton variant="destructive">Delete</UiButton>
  <UiButton variant="outline">Outlined</UiButton>
  <UiButton variant="ghost">Ghost</UiButton>
  <UiButton variant="success">Success</UiButton>
</template>

Cards

<template>
  <UiCard>
    <UiCardHeader>
      <UiCardTitle>Card Title</UiCardTitle>
      <UiCardDescription>Card description</UiCardDescription>
    </UiCardHeader>
    <UiCardContent>
      <!-- Your content -->
    </UiCardContent>
    <UiCardFooter>
      <!-- Footer actions -->
    </UiCardFooter>
  </UiCard>
</template>

Data Tables

<template>
  <UiDataTable 
    :data="tableData" 
    :columns="columns"
    :pagination="true"
    :sorting="true"
    :filtering="true"
  />
</template>

πŸ“Š Chart Components

Built-in chart components for data visualization:

<template>
  <UiBarChart 
    :data="chartData"
    :categories="['sales', 'revenue']"
    :index="'month'"
    :colors="['#3b82f6', '#ef4444']"
  />
  
  <UiLineChart 
    :data="timeSeriesData"
    :categories="['users', 'sessions']"
    :index="'date'"
  />
</template>

πŸ”§ Form Field Types

The dynamic form system supports all Zod schema types with intelligent field mapping:

String Fields

const schema = z.object({
  name: z.string(),                    // β†’ text input
  email: z.string().email(),           // β†’ email input
  website: z.string().url(),           // β†’ url input
  birthday: z.string().date(),         // β†’ date picker
  userId: z.string().uuid(),           // β†’ resource finder (if configured)
  description: z.string(),             // β†’ textarea (with custom mapping)
})

Number Fields

const schema = z.object({
  age: z.number(),                     // β†’ number input with steppers
  price: z.number().min(0),            // β†’ number input with validation
  rating: z.number().min(1).max(5),    // β†’ range slider (with custom mapping)
})

Boolean Fields

const schema = z.object({
  isActive: z.boolean(),               // β†’ checkbox
  agreeToTerms: z.boolean(),           // β†’ checkbox with label
})

Enum Fields

const schema = z.object({
  status: z.enum(['active', 'inactive', 'pending']), // β†’ select dropdown
  priority: z.enum(['low', 'medium', 'high']),       // β†’ select dropdown
})

Date Fields

const schema = z.object({
  createdAt: z.date(),                 // β†’ date input
  scheduledFor: z.date(),              // β†’ calendar date picker
})

Array Fields

const schema = z.object({
  tags: z.array(z.string()),           // β†’ dynamic array of text inputs
  members: z.array(z.object({          // β†’ dynamic array of nested forms
    name: z.string(),
    role: z.enum(['admin', 'user'])
  })),
  userIds: z.array(z.string().uuid()), // β†’ resource finder (multi-select)
})

Nested Objects

const schema = z.object({
  address: z.object({                  // β†’ collapsible nested form section
    street: z.string(),
    city: z.string(),
    country: z.string(),
  }),
  preferences: z.record(z.string()),   // β†’ dynamic key-value pairs
})

πŸ”— Resource Field Management

The library includes a powerful resource field system for handling relationships and foreign keys:

Basic Resource Configuration

const options: CreateDynamicFormOptions = {
  resourceFields: [
    {
      field: 'user',           // Field name (without 'Id' suffix)
      store: 'usersStore',     // Pinia store for data fetching
      displayField: 'email',   // Field to display in the UI
      searchFields: ['name', 'email'] // Fields to search in
    }
  ]
}

// This will automatically convert:
// userId: z.string().uuid() β†’ Resource finder component

Resource Finder Component

<template>
  <UiResourceFinder
    v-model="selectedUserId"
    :resource-store="usersStore"
    :display-field="'email'"
    :search-fields="['name', 'email']"
    :allow-clear="true"
    placeholder="Search for a user..."
  />
</template>

Creating Custom Resource Fields

import { createResourceFinderField } from '@damourlabs/ui/utils/form'

const userField = createResourceFinderField(
  'userId',
  'User',
  'users',
  {
    description: 'Select the user for this record',
    displayField: 'email',
    subTextField: 'name',
    searchFields: ['name', 'email', 'username'],
    rules: z.string().uuid().optional()
  }
)

🎨 Theming and Customization

TailwindCSS Configuration

The library uses TailwindCSS v4 with a custom configuration. You can extend the theme in your project:

// tailwind.config.js
import { damourTheme } from '@damourlabs/ui/tailwind.config'

export default {
  extends: [damourTheme],
  theme: {
    extend: {
      colors: {
        // Your custom colors
      }
    }
  }
}

Dark Mode

Dark mode is automatically configured and can be toggled:

<template>
  <UiDarkModeToggleSwitch />
</template>

Component Customization

All components accept custom classes and can be styled:

<template>
  <UiButton 
    class="bg-gradient-to-r from-purple-500 to-pink-500"
    variant="outline"
  >
    Custom Styled Button
  </UiButton>
</template>

πŸ“± Layout Components

Navigation

<template>
  <UiNavMain>
    <UiNavTopLevel>
      <UiNavLinks :links="navigationLinks" />
      <UiNavUser :user="currentUser" />
    </UiNavTopLevel>
    
    <UiNavSideBar>
      <UiNavQuickSettings />
    </UiNavSideBar>
  </UiNavMain>
</template>

Hero Section

<template>
  <UiHero :actions="heroActions">
    <template #title>
      Welcome to Our Platform
    </template>
    <template #description>
      Build amazing applications with our comprehensive UI library
    </template>
  </UiHero>
</template>

πŸ§ͺ Form Validation

Built-in Validation

const schema = z.object({
  email: z.string()
    .email('Please enter a valid email')
    .min(1, 'Email is required'),
  
  password: z.string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain uppercase, lowercase and number'),
  
  age: z.number()
    .min(18, 'Must be at least 18 years old')
    .max(120, 'Please enter a valid age')
})

Custom Validation Rules

import { createFieldHandler } from '@damourlabs/ui/utils/form'

const customEmailHandler = createFieldHandler<z.ZodString>((fieldSchema, field, context) => {
  if (context.key.includes('email')) {
    field.inputType = 'email'
    field.rules = z.string().email().refine(async (email) => {
      // Custom async validation
      const exists = await checkEmailExists(email)
      return !exists
    }, 'Email already exists')
  }
})

πŸ“Š Advanced Examples

Complete User Management Form

<template>
  <div class="container mx-auto p-6">
    <UiDynamicForm 
      :schema="userFormSchema" 
      :submit-fn="handleUserSubmit"
      :sections="true"
    />
  </div>
</template>

<script setup lang="ts">
import { z } from 'zod'
import { createDynamicForm } from '@damourlabs/ui/utils/form'

const userSchema = z.object({
  // Basic Information
  firstName: z.string().min(2, 'First name must be at least 2 characters'),
  lastName: z.string().min(2, 'Last name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  phone: z.string().optional(),
  
  // Account Settings
  role: z.enum(['admin', 'user', 'moderator']).default('user'),
  isActive: z.boolean().default(true),
  departmentId: z.string().uuid().optional(),
  managerId: z.string().uuid().optional(),
  
  // Profile Information
  profile: z.object({
    bio: z.string().max(500, 'Bio must be less than 500 characters').optional(),
    website: z.string().url('Invalid website URL').optional(),
    avatar: z.string().url().optional(),
    socialLinks: z.array(z.object({
      platform: z.enum(['twitter', 'linkedin', 'github']),
      url: z.string().url()
    })).optional()
  }),
  
  // Preferences
  preferences: z.object({
    emailNotifications: z.boolean().default(true),
    theme: z.enum(['light', 'dark', 'system']).default('system'),
    language: z.enum(['en', 'es', 'fr']).default('en')
  }),
  
  // Permissions
  permissions: z.array(z.enum(['read', 'write', 'delete', 'admin'])).default(['read']),
  
  // Projects
  projects: z.array(z.object({
    projectId: z.string().uuid(),
    role: z.enum(['owner', 'collaborator', 'viewer']),
    joinedAt: z.date().default(() => new Date())
  })).optional()
})

const userFormSchema = createDynamicForm(userSchema, {
  resourceFields: [
    { 
      field: 'department', 
      store: 'departments', 
      displayField: 'name',
      searchFields: ['name', 'code']
    },
    { 
      field: 'manager', 
      store: 'users', 
      displayField: 'email',
      searchFields: ['firstName', 'lastName', 'email']
    },
    { 
      field: 'project', 
      store: 'projects', 
      displayField: 'name',
      searchFields: ['name', 'description']
    }
  ],
  fieldsToIgnore: ['id', 'createdAt', 'updatedAt']
})

const handleUserSubmit = async (values: any) => {
  try {
    await $fetch('/api/users', {
      method: 'POST',
      body: values
    })
    // Handle success
  } catch (error) {
    // Handle error
  }
}
</script>

E-commerce Product Form

const productSchema = z.object({
  name: z.string().min(3, 'Product name must be at least 3 characters'),
  description: z.string().min(10, 'Description must be at least 10 characters'),
  price: z.number().min(0.01, 'Price must be greater than 0'),
  categoryId: z.string().uuid(),
  
  // Product variants
  variants: z.array(z.object({
    name: z.string(),
    sku: z.string(),
    price: z.number().min(0),
    inventory: z.number().min(0).int(),
    attributes: z.record(z.string())
  })),
  
  // SEO
  seo: z.object({
    title: z.string().max(60, 'SEO title must be less than 60 characters').optional(),
    description: z.string().max(160, 'SEO description must be less than 160 characters').optional(),
    keywords: z.array(z.string()).optional()
  }),
  
  // Media
  images: z.array(z.string().url()),
  
  // Shipping
  shipping: z.object({
    weight: z.number().min(0),
    dimensions: z.object({
      length: z.number().min(0),
      width: z.number().min(0),
      height: z.number().min(0)
    }),
    freeShipping: z.boolean().default(false)
  })
})

const productFormSchema = createDynamicForm(productSchema, {
  resourceFields: [
    { field: 'category', store: 'categories', displayField: 'name' }
  ]
})

πŸ”§ Development

Setup

# Clone the repository
git clone https://github.com/damourlabs/ui.git
cd ui

# Install dependencies
pnpm install

# Start development server
pnpm dev

Testing

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Run tests with coverage
pnpm test:coverage

Building

# Build for production
pnpm build

# Generate static files
pnpm generate

πŸ“„ API Reference

Form Generation Functions

createDynamicForm(schema, options?)

Generates a dynamic form from a Zod schema.

Parameters:

  • schema: z.ZodObject - The Zod schema to generate the form from
  • options?: CreateDynamicFormOptions - Configuration options

Returns: FormSchema<RuleExpression<unknown>>

createResourceFinderField(name, label, storeKey, options?)

Creates a resource finder field configuration.

Parameters:

  • name: string - Field name
  • label: string - Field label
  • storeKey: string - Pinia store key for data fetching
  • options?: object - Additional configuration

createFieldHandler<T>(handler)

Creates a custom field handler for specific field types.

Parameters:

  • handler: FieldHandler<T> - The handler function

createFieldTypeMapping(mapping)

Creates custom field type mappings.

Parameters:

  • mapping: Partial<FieldTypeMapping> - The mapping configuration

Component Props

See individual component documentation for detailed prop specifications.

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments


Made with ❀️ by DamourLabs

Production

Build the application for production:

pnpm build

Or statically generate it with:

pnpm generate

Locally preview production build:

pnpm preview

Checkout the deployment documentation for more information.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •