From bd5c835708fb131753f3c71e3fa62d5232aa3ac3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:54:15 +0000 Subject: [PATCH 1/6] Initial plan From 43c547e41691b159c496769fc85c65eeb2fc5411 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:02:33 +0000 Subject: [PATCH 2/6] Add comprehensive getting started guides and advanced tutorials Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/guide/custom-components.mdx | 615 +++++++++++++++++++ content/docs/guide/installation.mdx | 413 +++++++++++++ content/docs/guide/meta.json | 4 + content/docs/guide/performance.mdx | 562 +++++++++++++++++ content/docs/guide/plugin-development.mdx | 654 ++++++++++++++++++++ content/docs/guide/quick-start.mdx | 205 +++++++ content/docs/guide/video-tutorials.mdx | 290 +++++++++ content/docs/guide/zero-to-deployment.mdx | 711 ++++++++++++++++++++++ 8 files changed, 3454 insertions(+) create mode 100644 content/docs/guide/custom-components.mdx create mode 100644 content/docs/guide/installation.mdx create mode 100644 content/docs/guide/performance.mdx create mode 100644 content/docs/guide/plugin-development.mdx create mode 100644 content/docs/guide/quick-start.mdx create mode 100644 content/docs/guide/video-tutorials.mdx create mode 100644 content/docs/guide/zero-to-deployment.mdx diff --git a/content/docs/guide/custom-components.mdx b/content/docs/guide/custom-components.mdx new file mode 100644 index 00000000..346fee14 --- /dev/null +++ b/content/docs/guide/custom-components.mdx @@ -0,0 +1,615 @@ +--- +title: "Custom Component Development" +description: "Learn how to create custom components for ObjectUI" +--- + +# Custom Component Development + +Extend ObjectUI with your own custom components. This guide covers everything from basic components to advanced patterns with full TypeScript support. + +## Overview + +Creating custom components in ObjectUI involves three main steps: + +1. **Define the component schema types** - TypeScript interfaces for configuration +2. **Build the React component** - The actual UI implementation +3. **Register the component** - Make it available to the schema renderer + +## Basic Custom Component + +Let's create a simple "Counter" component. + +### Step 1: Define the Schema Type + +```typescript title="src/components/counter/counter.schema.ts" +import { ComponentSchema } from '@object-ui/types'; + +export interface CounterSchema extends ComponentSchema { + type: 'counter'; + initialValue?: number; + step?: number; + min?: number; + max?: number; + label?: string; + onValueChange?: { + type: 'log' | 'notify' | 'api'; + message?: string; + }; +} +``` + +### Step 2: Build the Component + +```tsx title="src/components/counter/Counter.tsx" +import React, { useState } from 'react'; +import { Button } from '@object-ui/components'; +import { CounterSchema } from './counter.schema'; + +export interface CounterProps { + schema: CounterSchema; +} + +export function Counter({ schema }: CounterProps) { + const { + initialValue = 0, + step = 1, + min = -Infinity, + max = Infinity, + label = 'Counter', + className, + } = schema; + + const [value, setValue] = useState(initialValue); + + const increment = () => { + const newValue = Math.min(value + step, max); + setValue(newValue); + handleValueChange(newValue); + }; + + const decrement = () => { + const newValue = Math.max(value - step, min); + setValue(newValue); + handleValueChange(newValue); + }; + + const handleValueChange = (newValue: number) => { + if (schema.onValueChange) { + // Handle the action + if (schema.onValueChange.type === 'log') { + console.log(`Counter value: ${newValue}`); + } + } + }; + + return ( +
+ {label}: +
+ + {value} + +
+
+ ); +} +``` + +### Step 3: Register the Component + +```typescript title="src/components/counter/index.ts" +import { ComponentRegistry } from '@object-ui/core'; +import { Counter } from './Counter'; +import { CounterSchema } from './counter.schema'; + +export function registerCounter() { + ComponentRegistry.register('counter', Counter); +} + +export { Counter, type CounterSchema }; +``` + +### Step 4: Use the Component + +```tsx title="src/App.tsx" +import { SchemaRenderer } from '@object-ui/react'; +import { registerCounter } from './components/counter'; + +// Register your custom component +registerCounter(); + +const schema = { + type: 'page', + children: [ + { + type: 'counter', + label: 'Quantity', + initialValue: 5, + step: 1, + min: 0, + max: 100, + onValueChange: { + type: 'log', + }, + }, + ], +}; + +function App() { + return ; +} +``` + +## Advanced Component with Children + +Create a component that can contain other components: + +```typescript title="src/components/panel/panel.schema.ts" +import { ComponentSchema } from '@object-ui/types'; + +export interface PanelSchema extends ComponentSchema { + type: 'panel'; + title: string; + collapsible?: boolean; + defaultExpanded?: boolean; + icon?: string; + variant?: 'default' | 'bordered' | 'elevated'; + children?: ComponentSchema[]; +} +``` + +```tsx title="src/components/panel/Panel.tsx" +import React, { useState } from 'react'; +import { SchemaRenderer } from '@object-ui/react'; +import { Card, CardHeader, CardTitle, CardContent } from '@object-ui/components'; +import { ChevronDown, ChevronUp } from 'lucide-react'; +import { PanelSchema } from './panel.schema'; + +export interface PanelProps { + schema: PanelSchema; +} + +export function Panel({ schema }: PanelProps) { + const { + title, + collapsible = false, + defaultExpanded = true, + icon, + variant = 'default', + children = [], + className, + } = schema; + + const [expanded, setExpanded] = useState(defaultExpanded); + + const variantClasses = { + default: '', + bordered: 'border-2 border-primary', + elevated: 'shadow-lg', + }; + + return ( + + collapsible && setExpanded(!expanded)} + > + +
+ {icon && {icon}} + {title} +
+ {collapsible && ( + {expanded ? : } + )} +
+
+ {expanded && ( + + {children.map((child, index) => ( + + ))} + + )} +
+ ); +} +``` + +## Component with Data Fetching + +Create a component that fetches and displays data: + +```tsx title="src/components/user-list/UserList.tsx" +import React, { useEffect, useState } from 'react'; +import { Card } from '@object-ui/components'; + +export interface UserListSchema extends ComponentSchema { + type: 'user-list'; + apiUrl: string; + pageSize?: number; +} + +interface User { + id: string; + name: string; + email: string; +} + +export function UserList({ schema }: { schema: UserListSchema }) { + const { apiUrl, pageSize = 10 } = schema; + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + fetch(apiUrl) + .then((res) => res.json()) + .then((data) => { + setUsers(data.slice(0, pageSize)); + setLoading(false); + }) + .catch((error) => { + console.error('Failed to fetch users:', error); + setLoading(false); + }); + }, [apiUrl, pageSize]); + + if (loading) { + return
Loading...
; + } + + return ( +
+ {users.map((user) => ( + +

{user.name}

+

{user.email}

+
+ ))} +
+ ); +} +``` + +## Component with Context + +Share state across multiple components: + +```tsx title="src/components/theme-provider/ThemeProvider.tsx" +import React, { createContext, useContext, useState } from 'react'; +import { ComponentSchema } from '@object-ui/types'; +import { SchemaRenderer } from '@object-ui/react'; + +interface ThemeContextType { + theme: 'light' | 'dark'; + toggleTheme: () => void; +} + +const ThemeContext = createContext(undefined); + +export function useTheme() { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within ThemeProvider'); + } + return context; +} + +export interface ThemeProviderSchema extends ComponentSchema { + type: 'theme-provider'; + defaultTheme?: 'light' | 'dark'; + children?: ComponentSchema[]; +} + +export function ThemeProvider({ schema }: { schema: ThemeProviderSchema }) { + const { defaultTheme = 'light', children = [] } = schema; + const [theme, setTheme] = useState<'light' | 'dark'>(defaultTheme); + + const toggleTheme = () => { + setTheme((prev) => (prev === 'light' ? 'dark' : 'light')); + }; + + return ( + +
+ {children.map((child, index) => ( + + ))} +
+
+ ); +} +``` + +## Best Practices + +### 1. Use TypeScript + +Always define proper types for your schema: + +```typescript +// ✅ Good +export interface MyComponentSchema extends ComponentSchema { + type: 'my-component'; + requiredProp: string; + optionalProp?: number; +} + +// ❌ Bad +export interface MyComponentSchema { + type: string; + [key: string]: any; +} +``` + +### 2. Handle Default Values + +```tsx +// ✅ Good +export function MyComponent({ schema }: MyComponentProps) { + const { + title = 'Default Title', + variant = 'default', + size = 'medium', + } = schema; + // ... +} + +// ❌ Bad +export function MyComponent({ schema }: MyComponentProps) { + // Accessing properties without defaults + return
{schema.title}
; +} +``` + +### 3. Validate Props + +```tsx +export function MyComponent({ schema }: MyComponentProps) { + // Validate required props + if (!schema.dataSource) { + console.error('MyComponent requires a dataSource'); + return null; + } + + // Validate prop values + if (schema.columns && schema.columns.length === 0) { + console.warn('MyComponent has no columns defined'); + } + + // Continue with rendering... +} +``` + +### 4. Use Composition + +Reuse existing components: + +```tsx +import { Card, Button, Badge } from '@object-ui/components'; + +export function ProductCard({ schema }: { schema: ProductCardSchema }) { + return ( + + + {schema.title} + {schema.category} + + +

{schema.description}

+ +
+
+ ); +} +``` + +### 5. Export Everything + +```typescript title="src/components/my-component/index.ts" +export { MyComponent } from './MyComponent'; +export { type MyComponentSchema } from './my-component.schema'; +export { registerMyComponent } from './register'; +``` + +## Component Naming Conventions + +Follow these naming conventions: + +- **Component File**: `MyComponent.tsx` (PascalCase) +- **Schema File**: `my-component.schema.ts` (kebab-case) +- **Schema Type**: `MyComponentSchema` (PascalCase + Schema suffix) +- **Schema Type Value**: `'my-component'` (kebab-case) +- **Register Function**: `registerMyComponent` (camelCase) + +## Testing Custom Components + +```tsx title="src/components/counter/Counter.test.tsx" +import { render, screen, fireEvent } from '@testing-library/react'; +import { Counter } from './Counter'; +import { CounterSchema } from './counter.schema'; + +describe('Counter', () => { + it('renders with initial value', () => { + const schema: CounterSchema = { + type: 'counter', + initialValue: 5, + label: 'Test Counter', + }; + + render(); + expect(screen.getByText('5')).toBeInTheDocument(); + }); + + it('increments value when + button clicked', () => { + const schema: CounterSchema = { + type: 'counter', + initialValue: 0, + step: 1, + }; + + render(); + const incrementButton = screen.getByText('+'); + fireEvent.click(incrementButton); + expect(screen.getByText('1')).toBeInTheDocument(); + }); + + it('respects max value', () => { + const schema: CounterSchema = { + type: 'counter', + initialValue: 9, + max: 10, + step: 1, + }; + + render(); + const incrementButton = screen.getByText('+'); + fireEvent.click(incrementButton); + expect(screen.getByText('10')).toBeInTheDocument(); + + // Should not increment beyond max + fireEvent.click(incrementButton); + expect(screen.getByText('10')).toBeInTheDocument(); + }); +}); +``` + +## Storybook Documentation + +Create stories for your component: + +```tsx title="src/components/counter/Counter.stories.tsx" +import type { Meta, StoryObj } from '@storybook/react'; +import { Counter } from './Counter'; +import { CounterSchema } from './counter.schema'; + +const meta: Meta = { + title: 'Components/Counter', + component: Counter, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + schema: { + type: 'counter', + label: 'Default Counter', + initialValue: 0, + }, + }, +}; + +export const WithMinMax: Story = { + args: { + schema: { + type: 'counter', + label: 'Limited Counter', + initialValue: 5, + min: 0, + max: 10, + step: 1, + }, + }, +}; + +export const LargeStep: Story = { + args: { + schema: { + type: 'counter', + label: 'Count by 5', + initialValue: 0, + step: 5, + }, + }, +}; +``` + +## Component Namespaces + +Avoid naming conflicts with namespaces: + +```typescript +import { ComponentRegistry } from '@object-ui/core'; + +// Register with namespace +ComponentRegistry.register('counter', Counter, { + namespace: 'myapp' +}); + +// Use in schema +const schema = { + type: 'myapp:counter', // Namespace prefix + initialValue: 0, +}; +``` + +## Distribution + +### 1. Create a Plugin Package + +```json title="package.json" +{ + "name": "@myorg/objectui-counter", + "version": "1.0.0", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": ["dist"], + "peerDependencies": { + "@object-ui/core": "^0.4.0", + "@object-ui/react": "^0.4.0", + "react": "^18.0.0" + } +} +``` + +### 2. Build Configuration + +```typescript title="vite.config.ts" +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import { resolve } from 'path'; + +export default defineConfig({ + plugins: [react()], + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'ObjectUICounter', + fileName: 'index', + }, + rollupOptions: { + external: ['react', 'react-dom', '@object-ui/core', '@object-ui/react'], + }, + }, +}); +``` + +### 3. Publish to NPM + +```bash +npm run build +npm publish --access public +``` + +## Next Steps + +- [Plugin Development](/docs/guide/plugin-development) - Package multiple components +- [Performance Optimization](/docs/guide/performance) - Optimize component rendering +- [Component Gallery](/docs/components) - Browse existing components +- [API Reference](/docs/api) - Component API documentation + +## Examples + +See complete examples: +- [Counter Component](https://github.com/objectstack-ai/objectui/tree/main/examples/custom-components/counter) +- [Panel Component](https://github.com/objectstack-ai/objectui/tree/main/examples/custom-components/panel) +- [User List Component](https://github.com/objectstack-ai/objectui/tree/main/examples/custom-components/user-list) diff --git a/content/docs/guide/installation.mdx b/content/docs/guide/installation.mdx new file mode 100644 index 00000000..64a92349 --- /dev/null +++ b/content/docs/guide/installation.mdx @@ -0,0 +1,413 @@ +--- +title: "Installation" +description: "Complete installation guide for ObjectUI" +--- + +# Installation + +This guide covers everything you need to install and configure ObjectUI in your project. + +## System Requirements + +- **Node.js**: 18.0 or later +- **Package Manager**: pnpm (recommended), npm, or yarn +- **React**: 18.0 or later +- **TypeScript**: 5.0 or later (optional but recommended) + +## Installation Methods + +### Method 1: Fresh React Project with Vite + +Create a new React + TypeScript project with Vite: + +```bash +# Create new Vite project +npm create vite@latest my-objectui-app -- --template react-ts +cd my-objectui-app + +# Install ObjectUI packages +npm install @object-ui/react @object-ui/components @object-ui/fields @object-ui/core + +# Install Tailwind CSS +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +### Method 2: Add to Existing Next.js App + +```bash +# Install ObjectUI packages +npm install @object-ui/react @object-ui/components @object-ui/fields @object-ui/core + +# Tailwind CSS (if not already installed) +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +### Method 3: Clone and Use Development Build + +For testing or contributing: + +```bash +git clone https://github.com/objectstack-ai/objectui.git +cd objectui +pnpm install +pnpm build +``` + +## Core Packages + +ObjectUI is split into focused packages for optimal tree-shaking: + +### Required Packages + +| Package | Purpose | Size | +|---------|---------|------| +| `@object-ui/core` | Schema engine and registry | ~15KB | +| `@object-ui/react` | React bindings and renderer | ~8KB | +| `@object-ui/components` | UI component library | ~120KB | +| `@object-ui/fields` | Form field widgets | ~80KB | + +### Optional Packages + +| Package | Purpose | When to Use | +|---------|---------|-------------| +| `@object-ui/layout` | Layout components | Building full applications | +| `@object-ui/plugin-form` | Advanced forms | Multi-step forms, validation | +| `@object-ui/plugin-grid` | Data grids | Tables with sorting/filtering | +| `@object-ui/plugin-kanban` | Kanban boards | Project management UIs | +| `@object-ui/plugin-charts` | Charts & graphs | Data visualization | +| `@object-ui/plugin-dashboard` | Dashboards | Analytics interfaces | +| `@object-ui/plugin-calendar` | Calendar views | Event scheduling | +| `@object-ui/plugin-gantt` | Gantt charts | Project timelines | +| `@object-ui/plugin-map` | Maps | Location-based features | +| `@object-ui/plugin-editor` | Rich text editor | Content editing | +| `@object-ui/plugin-markdown` | Markdown renderer | Documentation | +| `@object-ui/plugin-chatbot` | Chat interface | Conversational UIs | +| `@object-ui/data-objectstack` | ObjectStack integration | Using ObjectStack backend | + +## Tailwind CSS Configuration + +ObjectUI requires Tailwind CSS. Here's the complete setup: + +### 1. Install Tailwind + +```bash +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +### 2. Configure Tailwind + +Update `tailwind.config.js`: + +```js title="tailwind.config.js" +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: ['class'], + content: [ + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', + // Include ObjectUI packages + './node_modules/@object-ui/**/*.{js,ts,jsx,tsx}', + ], + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, + }, + plugins: [require('tailwindcss-animate')], +} +``` + +### 3. Add CSS Variables + +Create or update your global CSS file: + +```css title="src/index.css" +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} +``` + +### 4. Install Required Plugin + +```bash +npm install -D tailwindcss-animate +``` + +## Component Registration + +ObjectUI uses a registry pattern. Components must be registered before use: + +### Option 1: Register All Components (Easiest) + +```tsx +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; + +// Register everything (larger bundle) +registerAllComponents(ComponentRegistry); +registerAllFields(); +``` + +### Option 2: Lazy Registration (Recommended) + +For smaller bundles, register only what you need: + +```tsx +import { ComponentRegistry } from '@object-ui/core'; +import { registerField } from '@object-ui/fields'; + +// Register specific components +ComponentRegistry.register('button', ButtonComponent); +ComponentRegistry.register('card', CardComponent); + +// Register specific fields +registerField('text'); +registerField('number'); +registerField('email'); +``` + +**Bundle size impact**: Lazy registration can reduce bundle size by 30-50%! + +## TypeScript Configuration + +For the best developer experience, configure TypeScript: + +```json title="tsconfig.json" +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + /* Path aliases (optional) */ + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} +``` + +## Verification + +Test your installation: + +```tsx title="src/App.tsx" +import { SchemaRenderer } from '@object-ui/react'; +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; + +registerAllComponents(ComponentRegistry); + +const schema = { + type: 'card', + title: '✅ ObjectUI is installed!', + children: [ + { + type: 'text', + content: 'If you can see this card, everything is working correctly.', + }, + ], +}; + +function App() { + return ; +} + +export default App; +``` + +## Next Steps + +- [Quick Start](/docs/guide/quick-start) - Build your first component +- [Zero to Deployment](/docs/guide/zero-to-deployment) - Complete tutorial +- [Schema Overview](/docs/guide/schema-overview) - Learn the schema structure +- [Component Registry](/docs/guide/component-registry) - Advanced registration + +## Troubleshooting + +### Issue: Styles not applying + +**Solution**: Ensure Tailwind content includes ObjectUI: + +```js +content: [ + "./node_modules/@object-ui/**/*.{js,ts,jsx,tsx}", +] +``` + +### Issue: Module not found + +**Solution**: Check package.json includes all required dependencies: + +```json +{ + "dependencies": { + "@object-ui/react": "latest", + "@object-ui/components": "latest", + "@object-ui/fields": "latest", + "@object-ui/core": "latest" + } +} +``` + +### Issue: TypeScript errors + +**Solution**: Ensure `skipLibCheck: true` in tsconfig.json + +### Issue: Dark mode not working + +**Solution**: Add dark mode toggle: + +```tsx +// Add to your root component +
{/* or light */} + +
+``` + +## Support + +- [GitHub Issues](https://github.com/objectstack-ai/objectui/issues) +- [Discussions](https://github.com/objectstack-ai/objectui/discussions) +- [Documentation](/docs) diff --git a/content/docs/guide/meta.json b/content/docs/guide/meta.json index 7e6fc6cf..4a8385a8 100644 --- a/content/docs/guide/meta.json +++ b/content/docs/guide/meta.json @@ -1,6 +1,10 @@ { "title": "Guide", "pages": [ + "quick-start", + "installation", + "zero-to-deployment", + "video-tutorials", "architecture", "schema-rendering", "layout", diff --git a/content/docs/guide/performance.mdx b/content/docs/guide/performance.mdx new file mode 100644 index 00000000..c29b5ec3 --- /dev/null +++ b/content/docs/guide/performance.mdx @@ -0,0 +1,562 @@ +--- +title: "Performance Optimization" +description: "Optimize your ObjectUI applications for maximum performance" +--- + +# Performance Optimization + +Learn how to build lightning-fast ObjectUI applications with optimal bundle sizes and rendering performance. + +## Bundle Size Optimization + +### 1. Lazy Field Registration + +Register only the fields you need: + +```tsx +import { registerField } from '@object-ui/fields'; + +// ❌ Bad - Registers all 37 fields (~80KB) +import { registerAllFields } from '@object-ui/fields'; +registerAllFields(); + +// ✅ Good - Register only what you use (~20KB) +registerField('text'); +registerField('number'); +registerField('email'); +registerField('select'); +``` + +**Impact**: 60-70% reduction in field bundle size! + +### 2. Selective Component Registration + +```tsx +import { ComponentRegistry } from '@object-ui/core'; +import { Button, Card, Input } from '@object-ui/components'; + +// ❌ Bad - Registers all 47 components +import { registerAllComponents } from '@object-ui/components'; +registerAllComponents(ComponentRegistry); + +// ✅ Good - Register only what you use +ComponentRegistry.register('button', Button); +ComponentRegistry.register('card', Card); +ComponentRegistry.register('input', Input); +``` + +**Impact**: 30-50% reduction in component bundle size! + +### 3. Plugin Code Splitting + +Load plugins only when needed: + +```tsx +import { lazy, Suspense } from 'react'; + +// Lazy load heavy plugins +const KanbanBoard = lazy(() => import('@object-ui/plugin-kanban')); +const DataGrid = lazy(() => import('@object-ui/plugin-grid')); +const ChartDashboard = lazy(() => import('@object-ui/plugin-charts')); + +function App() { + return ( + Loading...}> + + + ); +} +``` + +### 4. Analyze Bundle Size + +Use bundle analyzers to identify bloat: + +```bash +# Install analyzer +npm install -D rollup-plugin-visualizer + +# Add to vite.config.ts +import { visualizer } from 'rollup-plugin-visualizer'; + +export default defineConfig({ + plugins: [ + react(), + visualizer({ + open: true, + gzipSize: true, + brotliSize: true, + }), + ], +}); + +# Build and analyze +npm run build +``` + +## Rendering Performance + +### 1. Memoize Components + +Prevent unnecessary re-renders: + +```tsx +import { memo } from 'react'; + +export const ExpensiveComponent = memo(({ schema }: ExpensiveComponentProps) => { + // Component implementation +}, (prevProps, nextProps) => { + // Custom comparison + return prevProps.schema === nextProps.schema; +}); +``` + +### 2. Use React.memo for Schema Renderer + +```tsx +import { memo } from 'react'; +import { SchemaRenderer } from '@object-ui/react'; + +const MemoizedSchemaRenderer = memo(SchemaRenderer, (prevProps, nextProps) => { + return JSON.stringify(prevProps.schema) === JSON.stringify(nextProps.schema); +}); + +function App() { + return ; +} +``` + +### 3. Virtual Scrolling for Large Lists + +Use virtualization for long lists: + +```tsx +import { FixedSizeList } from 'react-window'; + +export function VirtualList({ schema }: { schema: ListSchema }) { + const { items, height = 400, itemHeight = 50 } = schema; + + return ( + + {({ index, style }) => ( +
+ +
+ )} +
+ ); +} +``` + +### 4. Debounce Expensive Operations + +```tsx +import { useMemo, useState } from 'react'; +import { debounce } from 'lodash-es'; + +export function SearchComponent({ schema }: SearchComponentProps) { + const [query, setQuery] = useState(''); + + const debouncedSearch = useMemo( + () => + debounce((value: string) => { + // Expensive search operation + performSearch(value); + }, 300), + [] + ); + + return ( + { + setQuery(e.target.value); + debouncedSearch(e.target.value); + }} + value={query} + /> + ); +} +``` + +### 5. Optimize Re-renders with Keys + +Always use stable keys: + +```tsx +// ❌ Bad - Index as key causes unnecessary re-renders +{items.map((item, index) => ( + +))} + +// ✅ Good - Stable unique key +{items.map((item) => ( + +))} +``` + +## Data Fetching Optimization + +### 1. Implement Caching + +```tsx +import { useQuery } from '@tanstack/react-query'; + +export function DataComponent({ schema }: DataComponentProps) { + const { data, isLoading } = useQuery({ + queryKey: ['data', schema.dataSource.api], + queryFn: () => fetch(schema.dataSource.api).then(res => res.json()), + staleTime: 5 * 60 * 1000, // Cache for 5 minutes + cacheTime: 10 * 60 * 1000, + }); + + if (isLoading) return
Loading...
; + return
{/* Render data */}
; +} +``` + +### 2. Pagination + +Implement server-side pagination: + +```tsx +const paginatedSchema = { + type: 'data-table', + dataSource: { + api: '/api/users', + method: 'GET', + params: { + page: 1, + pageSize: 20, // Load only 20 items at a time + }, + }, + pagination: { + enabled: true, + pageSize: 20, + showSizeChanger: true, + }, +}; +``` + +### 3. Incremental Loading + +Load data as needed: + +```tsx +import { useInfiniteQuery } from '@tanstack/react-query'; + +export function InfiniteList({ schema }: InfiniteListProps) { + const { + data, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + } = useInfiniteQuery({ + queryKey: ['items'], + queryFn: ({ pageParam = 0 }) => + fetch(`/api/items?page=${pageParam}`).then(res => res.json()), + getNextPageParam: (lastPage, pages) => lastPage.nextPage, + }); + + return ( +
+ {data?.pages.map((page) => + page.items.map((item) => ( + + )) + )} + {hasNextPage && ( + + )} +
+ ); +} +``` + +## Image Optimization + +### 1. Lazy Load Images + +```tsx +export function ImageComponent({ schema }: ImageSchema) { + return ( + {schema.alt} + ); +} +``` + +### 2. Use Modern Formats + +```tsx + + + + {alt} + +``` + +### 3. Responsive Images + +```tsx +export function ResponsiveImage({ schema }: ImageSchema) { + return ( + {schema.alt} + ); +} +``` + +## CSS Optimization + +### 1. Purge Unused Tailwind CSS + +Configure Tailwind to remove unused styles: + +```js title="tailwind.config.js" +export default { + content: [ + './src/**/*.{js,jsx,ts,tsx}', + './node_modules/@object-ui/**/*.{js,ts,jsx,tsx}', + ], + // Tailwind will purge unused classes in production +} +``` + +### 2. Use CSS Containment + +```tsx +export function CardComponent({ schema }: CardSchema) { + return ( +
+ {/* Card content */} +
+ ); +} +``` + +## Runtime Performance + +### 1. Use Production Build + +Always use production builds: + +```bash +# Development (larger, slower) +npm run dev + +# Production (optimized) +npm run build +npm run preview +``` + +### 2. Enable Compression + +Configure your server for gzip/brotli: + +```js title="vite.config.ts" +import { defineConfig } from 'vite'; +import viteCompression from 'vite-plugin-compression'; + +export default defineConfig({ + plugins: [ + viteCompression({ + algorithm: 'brotliCompress', + ext: '.br', + }), + ], +}); +``` + +### 3. Tree Shaking + +Ensure tree shaking is enabled: + +```json title="package.json" +{ + "sideEffects": false +} +``` + +## Monitoring Performance + +### 1. Use React DevTools Profiler + +```tsx +import { Profiler } from 'react'; + +function App() { + const onRenderCallback = ( + id, + phase, + actualDuration, + baseDuration, + startTime, + commitTime + ) => { + console.log(`${id} (${phase}) took ${actualDuration}ms`); + }; + + return ( + + + + ); +} +``` + +### 2. Web Vitals + +Monitor Core Web Vitals: + +```tsx +import { onCLS, onFID, onFCP, onLCP, onTTFB } from 'web-vitals'; + +onCLS(console.log); +onFID(console.log); +onFCP(console.log); +onLCP(console.log); +onTTFB(console.log); +``` + +### 3. Lighthouse Audits + +Run regular Lighthouse audits: + +```bash +# Install Lighthouse +npm install -g @lhci/cli + +# Run audit +lhci autorun --collect.url=http://localhost:3000 +``` + +## Performance Checklist + +✅ **Bundle Size** +- [ ] Use lazy field registration +- [ ] Register only needed components +- [ ] Code split heavy plugins +- [ ] Analyze bundle with visualizer +- [ ] Keep total bundle < 500KB gzipped + +✅ **Rendering** +- [ ] Memoize expensive components +- [ ] Use stable keys for lists +- [ ] Implement virtual scrolling for long lists +- [ ] Debounce expensive operations +- [ ] Avoid inline function creation in render + +✅ **Data Fetching** +- [ ] Implement caching +- [ ] Use pagination for large datasets +- [ ] Implement incremental loading +- [ ] Optimize API responses + +✅ **Images** +- [ ] Use lazy loading +- [ ] Serve modern formats (WebP, AVIF) +- [ ] Implement responsive images +- [ ] Optimize image sizes + +✅ **CSS** +- [ ] Purge unused Tailwind classes +- [ ] Use CSS containment +- [ ] Minimize custom CSS + +✅ **Build** +- [ ] Use production builds +- [ ] Enable compression +- [ ] Configure tree shaking + +✅ **Monitoring** +- [ ] Set up performance monitoring +- [ ] Track Core Web Vitals +- [ ] Run regular Lighthouse audits + +## Performance Targets + +Aim for these metrics: + +| Metric | Target | Good | Needs Improvement | +|--------|--------|------|-------------------| +| **First Contentful Paint (FCP)** | < 1.8s | < 3.0s | > 3.0s | +| **Largest Contentful Paint (LCP)** | < 2.5s | < 4.0s | > 4.0s | +| **Total Blocking Time (TBT)** | < 200ms | < 600ms | > 600ms | +| **Cumulative Layout Shift (CLS)** | < 0.1 | < 0.25 | > 0.25 | +| **Speed Index** | < 3.4s | < 5.8s | > 5.8s | +| **Bundle Size (gzipped)** | < 300KB | < 500KB | > 500KB | + +## Common Performance Issues + +### Issue: Large Bundle Size + +**Diagnosis**: Run `npm run build` and check output size. + +**Solution**: +```tsx +// Before: 500KB +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; + +// After: 200KB +import { registerField } from '@object-ui/fields'; +registerField('text'); +registerField('number'); +``` + +### Issue: Slow Initial Load + +**Diagnosis**: Check Network tab in DevTools. + +**Solution**: Implement code splitting: +```tsx +const Dashboard = lazy(() => import('./pages/Dashboard')); +const Reports = lazy(() => import('./pages/Reports')); +``` + +### Issue: Janky Scrolling + +**Diagnosis**: Use DevTools Performance tab. + +**Solution**: Implement virtual scrolling: +```tsx +import { FixedSizeList } from 'react-window'; +``` + +## Next Steps + +- [Security Best Practices](/docs/guide/security) - Secure your app +- [Custom Components](/docs/guide/custom-components) - Build optimized components +- [Plugin Development](/docs/guide/plugin-development) - Create performant plugins + +## Resources + +- [Web.dev Performance](https://web.dev/performance/) +- [React Performance Optimization](https://react.dev/learn/render-and-commit) +- [Vite Performance](https://vitejs.dev/guide/performance.html) +- [Tailwind CSS Optimization](https://tailwindcss.com/docs/optimizing-for-production) diff --git a/content/docs/guide/plugin-development.mdx b/content/docs/guide/plugin-development.mdx new file mode 100644 index 00000000..247cd7d1 --- /dev/null +++ b/content/docs/guide/plugin-development.mdx @@ -0,0 +1,654 @@ +--- +title: "Plugin Development" +description: "Learn how to create and publish ObjectUI plugins" +--- + +# Plugin Development + +Create reusable plugins to extend ObjectUI with new components, fields, and functionality. This guide covers the complete plugin development workflow. + +## What is a Plugin? + +An ObjectUI plugin is a collection of: +- **Components** - UI building blocks +- **Fields** - Form input widgets +- **Utilities** - Helper functions +- **Styles** - Tailwind CSS configurations +- **Documentation** - Usage guides and examples + +Popular plugins include `plugin-kanban`, `plugin-charts`, `plugin-grid`, and more. + +## Quick Start with CLI + +The fastest way to create a plugin: + +```bash +npx @object-ui/create-plugin my-awesome-plugin +cd my-awesome-plugin +pnpm install +pnpm dev +``` + +This scaffolds a complete plugin structure with: +- TypeScript configuration +- Vite build setup +- Storybook integration +- Testing framework +- Example components + +## Plugin Structure + +``` +my-plugin/ +├── src/ +│ ├── components/ +│ │ ├── MyComponent.tsx +│ │ ├── MyComponent.stories.tsx +│ │ └── my-component.schema.ts +│ ├── fields/ +│ │ ├── MyField.tsx +│ │ └── my-field.schema.ts +│ ├── utils/ +│ │ └── helpers.ts +│ ├── index.ts # Main entry point +│ └── register.ts # Component registration +├── package.json +├── tsconfig.json +├── vite.config.ts +├── tailwind.config.js +└── README.md +``` + +## Step-by-Step: Creating a Chart Plugin + +Let's create a plugin for data visualization charts. + +### Step 1: Initialize Plugin + +```bash +npx @object-ui/create-plugin plugin-charts +cd plugin-charts +``` + +### Step 2: Define Component Schema + +```typescript title="src/components/line-chart/line-chart.schema.ts" +import { ComponentSchema } from '@object-ui/types'; + +export interface LineChartSchema extends ComponentSchema { + type: 'line-chart'; + data: Array<{ + label: string; + value: number; + }>; + title?: string; + xAxisLabel?: string; + yAxisLabel?: string; + color?: string; + showGrid?: boolean; + showLegend?: boolean; + height?: number; + dataSource?: { + api: string; + method?: 'GET' | 'POST'; + transform?: string; // Expression to transform data + }; +} +``` + +### Step 3: Build the Component + +```tsx title="src/components/line-chart/LineChart.tsx" +import React, { useEffect, useState } from 'react'; +import { + LineChart as RechartsLineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from 'recharts'; +import { Card, CardHeader, CardTitle, CardContent } from '@object-ui/components'; +import { LineChartSchema } from './line-chart.schema'; + +export interface LineChartProps { + schema: LineChartSchema; +} + +export function LineChart({ schema }: LineChartProps) { + const { + data: initialData = [], + title, + xAxisLabel = 'X Axis', + yAxisLabel = 'Y Axis', + color = '#8884d8', + showGrid = true, + showLegend = true, + height = 300, + dataSource, + className, + } = schema; + + const [data, setData] = useState(initialData); + const [loading, setLoading] = useState(!!dataSource); + + useEffect(() => { + if (dataSource) { + fetchData(); + } + }, [dataSource]); + + const fetchData = async () => { + try { + const response = await fetch(dataSource!.api, { + method: dataSource!.method || 'GET', + }); + const result = await response.json(); + + // Transform data if transform expression provided + const transformedData = dataSource!.transform + ? transformDataWithExpression(result, dataSource!.transform) + : result; + + setData(transformedData); + } catch (error) { + console.error('Failed to fetch chart data:', error); + } finally { + setLoading(false); + } + }; + + if (loading) { + return
Loading chart...
; + } + + const content = ( + + + {showGrid && } + + + + {showLegend && } + + + + ); + + return title ? ( + + + {title} + + {content} + + ) : ( +
{content}
+ ); +} + +function transformDataWithExpression(data: any, expression: string): any { + // Simple expression evaluation (in production, use a safe evaluator) + // Example: "items.map(item => ({ label: item.name, value: item.count }))" + try { + const fn = new Function('data', `return ${expression}`); + return fn(data); + } catch (error) { + console.error('Failed to transform data:', error); + return data; + } +} +``` + +### Step 4: Add Dependencies + +```json title="package.json" +{ + "name": "@object-ui/plugin-charts", + "version": "1.0.0", + "description": "Chart components for ObjectUI", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": ["dist", "README.md"], + "scripts": { + "dev": "vite build --watch", + "build": "vite build && tsc --emitDeclarationOnly", + "test": "vitest", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "dependencies": { + "recharts": "^2.10.0" + }, + "peerDependencies": { + "@object-ui/core": "^0.4.0", + "@object-ui/react": "^0.4.0", + "@object-ui/components": "^0.4.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@object-ui/types": "^0.4.0", + "@storybook/react": "^8.0.0", + "@storybook/react-vite": "^8.0.0", + "@types/react": "^18.0.0", + "@vitejs/plugin-react": "^4.0.0", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vitest": "^1.0.0" + }, + "keywords": [ + "objectui", + "plugin", + "charts", + "visualization", + "react" + ] +} +``` + +### Step 5: Create Registration Function + +```typescript title="src/register.ts" +import { ComponentRegistry } from '@object-ui/core'; +import { LineChart } from './components/line-chart/LineChart'; +import { BarChart } from './components/bar-chart/BarChart'; +import { PieChart } from './components/pie-chart/PieChart'; + +export function registerChartsPlugin() { + ComponentRegistry.register('line-chart', LineChart, { + namespace: 'charts', + }); + + ComponentRegistry.register('bar-chart', BarChart, { + namespace: 'charts', + }); + + ComponentRegistry.register('pie-chart', PieChart, { + namespace: 'charts', + }); +} +``` + +### Step 6: Export Everything + +```typescript title="src/index.ts" +// Components +export { LineChart } from './components/line-chart/LineChart'; +export { BarChart } from './components/bar-chart/BarChart'; +export { PieChart } from './components/pie-chart/PieChart'; + +// Schemas +export type { LineChartSchema } from './components/line-chart/line-chart.schema'; +export type { BarChartSchema } from './components/bar-chart/bar-chart.schema'; +export type { PieChartSchema } from './components/pie-chart/pie-chart.schema'; + +// Registration +export { registerChartsPlugin } from './register'; +``` + +### Step 7: Configure Build + +```typescript title="vite.config.ts" +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import { resolve } from 'path'; +import dts from 'vite-plugin-dts'; + +export default defineConfig({ + plugins: [ + react(), + dts({ + insertTypesEntry: true, + }), + ], + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'ObjectUIPluginCharts', + formats: ['es', 'umd'], + fileName: (format) => `index.${format}.js`, + }, + rollupOptions: { + external: [ + 'react', + 'react-dom', + '@object-ui/core', + '@object-ui/react', + '@object-ui/components', + ], + output: { + globals: { + react: 'React', + 'react-dom': 'ReactDOM', + '@object-ui/core': 'ObjectUICore', + '@object-ui/react': 'ObjectUIReact', + '@object-ui/components': 'ObjectUIComponents', + }, + }, + }, + }, +}); +``` + +## Testing Your Plugin + +### Unit Tests + +```tsx title="src/components/line-chart/LineChart.test.tsx" +import { render, screen } from '@testing-library/react'; +import { LineChart } from './LineChart'; +import { LineChartSchema } from './line-chart.schema'; + +describe('LineChart', () => { + it('renders with data', () => { + const schema: LineChartSchema = { + type: 'line-chart', + title: 'Sales Data', + data: [ + { label: 'Jan', value: 100 }, + { label: 'Feb', value: 150 }, + { label: 'Mar', value: 200 }, + ], + }; + + render(); + expect(screen.getByText('Sales Data')).toBeInTheDocument(); + }); + + it('fetches data from API', async () => { + const schema: LineChartSchema = { + type: 'line-chart', + dataSource: { + api: '/api/chart-data', + method: 'GET', + }, + }; + + // Mock fetch + global.fetch = vi.fn(() => + Promise.resolve({ + json: () => Promise.resolve([ + { label: 'A', value: 10 }, + { label: 'B', value: 20 }, + ]), + }) + ) as any; + + render(); + + await screen.findByText('A'); + expect(screen.getByText('A')).toBeInTheDocument(); + }); +}); +``` + +### Storybook Stories + +```tsx title="src/components/line-chart/LineChart.stories.tsx" +import type { Meta, StoryObj } from '@storybook/react'; +import { LineChart } from './LineChart'; + +const meta: Meta = { + title: 'Charts/LineChart', + component: LineChart, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + schema: { + type: 'line-chart', + title: 'Monthly Revenue', + data: [ + { label: 'Jan', value: 4000 }, + { label: 'Feb', value: 3000 }, + { label: 'Mar', value: 2000 }, + { label: 'Apr', value: 2780 }, + { label: 'May', value: 1890 }, + { label: 'Jun', value: 2390 }, + ], + xAxisLabel: 'Month', + yAxisLabel: 'Revenue ($)', + color: '#8884d8', + }, + }, +}; + +export const WithoutGrid: Story = { + args: { + schema: { + ...Default.args.schema, + showGrid: false, + }, + }, +}; + +export const CustomColor: Story = { + args: { + schema: { + ...Default.args.schema, + color: '#ff6b6b', + }, + }, +}; +``` + +## Documentation + +Create comprehensive README: + +```markdown title="README.md" +# @object-ui/plugin-charts + +Chart components for ObjectUI - Line, Bar, Pie, and more. + +## Installation + +\`\`\`bash +npm install @object-ui/plugin-charts recharts +\`\`\` + +## Usage + +\`\`\`tsx +import { registerChartsPlugin } from '@object-ui/plugin-charts'; +import { SchemaRenderer } from '@object-ui/react'; + +// Register the plugin +registerChartsPlugin(); + +const schema = { + type: 'line-chart', + title: 'Sales Trend', + data: [ + { label: 'Jan', value: 100 }, + { label: 'Feb', value: 150 }, + { label: 'Mar', value: 200 }, + ], +}; + +function App() { + return ; +} +\`\`\` + +## Components + +### LineChart + +Display data as a line chart. + +**Schema Properties:** +- `data` - Array of {label, value} objects +- `title` - Chart title +- `xAxisLabel` - X-axis label +- `yAxisLabel` - Y-axis label +- `color` - Line color (hex) +- `showGrid` - Show grid lines (default: true) +- `height` - Chart height in pixels (default: 300) + +[More documentation...] + +## License + +MIT +``` + +## Publishing to NPM + +### Step 1: Build + +```bash +pnpm build +``` + +### Step 2: Test Locally + +```bash +# In your plugin directory +npm link + +# In your test project +npm link @object-ui/plugin-charts +``` + +### Step 3: Publish + +```bash +# Login to npm +npm login + +# Publish (with public access for scoped packages) +npm publish --access public +``` + +### Step 4: Version Management + +Use semantic versioning: + +```bash +# Patch release (bug fixes) +npm version patch + +# Minor release (new features) +npm version minor + +# Major release (breaking changes) +npm version major +``` + +## Plugin Best Practices + +### 1. Tree-Shaking Support + +Export individual components: + +```typescript +// ✅ Good - Allows tree-shaking +export { LineChart } from './components/line-chart/LineChart'; +export { BarChart } from './components/bar-chart/BarChart'; + +// ❌ Bad - Bundles everything +export * from './components'; +``` + +### 2. Peer Dependencies + +Don't bundle React or ObjectUI core: + +```json +{ + "peerDependencies": { + "react": "^18.0.0", + "@object-ui/core": "^0.4.0" + } +} +``` + +### 3. Size Optimization + +- Use dynamic imports for large dependencies +- Minimize bundle size +- Provide both ESM and UMD builds + +```typescript +// Lazy load heavy dependencies +const HeavyChart = lazy(() => import('./components/HeavyChart')); +``` + +### 4. TypeScript Support + +Always export types: + +```typescript +export type { LineChartSchema } from './components/line-chart/line-chart.schema'; +``` + +### 5. Documentation + +- Include README with examples +- Add Storybook stories +- Document all schema properties +- Provide migration guides + +## Plugin Examples + +Study these official plugins: + +- **[@object-ui/plugin-kanban](https://github.com/objectstack-ai/objectui/tree/main/packages/plugin-kanban)** - Kanban boards with drag-and-drop +- **[@object-ui/plugin-grid](https://github.com/objectstack-ai/objectui/tree/main/packages/plugin-grid)** - Advanced data grids +- **[@object-ui/plugin-charts](https://github.com/objectstack-ai/objectui/tree/main/packages/plugin-charts)** - Data visualization +- **[@object-ui/plugin-form](https://github.com/objectstack-ai/objectui/tree/main/packages/plugin-form)** - Advanced forms + +## Troubleshooting + +### Peer dependency warnings + +Use `--legacy-peer-deps` when installing: + +```bash +npm install --legacy-peer-deps +``` + +### Build errors + +Clear cache and rebuild: + +```bash +rm -rf dist node_modules +npm install +npm run build +``` + +### TypeScript errors in consumers + +Ensure `types` field points to correct declaration file: + +```json +{ + "types": "dist/index.d.ts" +} +``` + +## Next Steps + +- [Custom Component Development](/docs/guide/custom-components) - Build components +- [Performance Optimization](/docs/guide/performance) - Optimize plugins +- [API Reference](/docs/api) - Component API +- [Publishing Guide](https://docs.npmjs.com/packages-and-modules) - NPM documentation + +## Community Plugins + +Share your plugin: +- [Submit to Plugin Marketplace](https://github.com/objectstack-ai/objectui/discussions) +- [Plugin Directory](/plugins) +- [Awesome ObjectUI](https://github.com/objectstack-ai/awesome-objectui) diff --git a/content/docs/guide/quick-start.mdx b/content/docs/guide/quick-start.mdx new file mode 100644 index 00000000..e0ecdede --- /dev/null +++ b/content/docs/guide/quick-start.mdx @@ -0,0 +1,205 @@ +--- +title: "Quick Start" +description: "Get up and running with ObjectUI in 5 minutes" +--- + +# Quick Start + +Get your first ObjectUI application running in just 5 minutes! This guide will walk you through the fastest path to see ObjectUI in action. + +## Prerequisites + +Before you begin, ensure you have: + +- **Node.js 18+** installed +- **pnpm** package manager (recommended) or npm +- Basic knowledge of React and TypeScript + +## Option 1: Try the Live Demo (0 minutes) + +The fastest way to see ObjectUI in action: + +```bash +# Clone the repository +git clone https://github.com/objectstack-ai/objectui.git +cd objectui + +# Install dependencies +pnpm install + +# Start the development console +pnpm dev +``` + +Open [http://localhost:5173](http://localhost:5173) to see the ObjectUI console with live examples! + +## Option 2: Add to Existing React App (5 minutes) + +### Step 1: Install Core Packages + +```bash +npm install @object-ui/react @object-ui/components @object-ui/fields +``` + +### Step 2: Setup Tailwind CSS + +ObjectUI requires Tailwind CSS. Add it to your project: + +```bash +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +Update your `tailwind.config.js`: + +```js title="tailwind.config.js" +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + // Include ObjectUI components + "./node_modules/@object-ui/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} +``` + +Add Tailwind directives to your CSS: + +```css title="src/index.css" +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +### Step 3: Render Your First Schema + +Create a simple form schema: + +```tsx title="src/App.tsx" +import { SchemaRenderer } from '@object-ui/react'; +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; + +// Register components +registerAllComponents(ComponentRegistry); +registerAllFields(); + +const schema = { + type: 'card', + title: 'Contact Form', + children: [ + { + type: 'field', + fieldType: 'text', + name: 'name', + label: 'Full Name', + placeholder: 'John Doe', + required: true, + }, + { + type: 'field', + fieldType: 'email', + name: 'email', + label: 'Email', + placeholder: 'john@example.com', + required: true, + }, + { + type: 'field', + fieldType: 'textarea', + name: 'message', + label: 'Message', + placeholder: 'Your message here...', + rows: 4, + }, + { + type: 'button', + text: 'Submit', + variant: 'default', + onClick: { + type: 'log', + message: 'Form submitted!', + }, + }, + ], +}; + +function App() { + return ( +
+
+ +
+
+ ); +} + +export default App; +``` + +### Step 4: Run Your App + +```bash +npm run dev +``` + +🎉 **Congratulations!** You've just rendered your first schema-driven UI component! + +## What Just Happened? + +1. **Schema Definition**: You defined a form using plain JSON/JavaScript objects +2. **Component Registration**: You registered ObjectUI's component library +3. **Schema Rendering**: The `` transformed your schema into React components + +## Next Steps + +Now that you have ObjectUI running, explore these guides: + +- [**Installation Guide**](/docs/guide/installation) - Complete setup with all features +- [**Zero to Deployment**](/docs/guide/zero-to-deployment) - Build and deploy a complete app +- [**Schema Overview**](/docs/guide/schema-overview) - Understand the schema structure +- [**Component Gallery**](/docs/components) - Browse all 35+ available components + +## Common Issues + +### Tailwind styles not loading? + +Make sure you've added ObjectUI to your `content` array in `tailwind.config.js`: + +```js +content: [ + "./node_modules/@object-ui/**/*.{js,ts,jsx,tsx}", +] +``` + +### Components not rendering? + +Ensure you've registered the components before rendering: + +```tsx +import { registerAllComponents } from '@object-ui/components'; +import { ComponentRegistry } from '@object-ui/core'; + +registerAllComponents(ComponentRegistry); +``` + +### TypeScript errors? + +Install type definitions: + +```bash +npm install -D @types/react @types/react-dom +``` + +## Resources + +- [GitHub Repository](https://github.com/objectstack-ai/objectui) +- [Component Documentation](/docs/components) +- [API Reference](/docs/core) +- [Examples](https://github.com/objectstack-ai/objectui/tree/main/examples) diff --git a/content/docs/guide/video-tutorials.mdx b/content/docs/guide/video-tutorials.mdx new file mode 100644 index 00000000..5a4d3e1e --- /dev/null +++ b/content/docs/guide/video-tutorials.mdx @@ -0,0 +1,290 @@ +--- +title: "Video Tutorials" +description: "Learn ObjectUI through comprehensive video tutorials" +--- + +# Video Tutorials + +Learn ObjectUI visually with our comprehensive video tutorial series. Available on YouTube and Bilibili for global accessibility. + +## 🎬 Tutorial Series + +### Getting Started Series + +Perfect for beginners who want to understand ObjectUI fundamentals. + +#### 1. Introduction to ObjectUI (10 min) +**Coming Soon** + +- What is ObjectUI and why use it? +- Schema-driven UI concepts +- Comparison with traditional development +- Use cases and success stories + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 2. Quick Start Tutorial (5 min) +**Coming Soon** + +- Install ObjectUI in a new project +- Render your first component +- Understanding the schema structure +- Component registration + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 3. Building Your First Form (15 min) +**Coming Soon** + +- Form field types overview +- Validation and error handling +- Form submission and actions +- Real-time validation + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +### Component Deep Dives + +Master individual components with focused tutorials. + +#### 4. Data Tables and Grids (20 min) +**Coming Soon** + +- Table setup and configuration +- Sorting and filtering +- Pagination +- Custom cell renderers +- Bulk actions + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 5. Building Dashboards (25 min) +**Coming Soon** + +- Dashboard layout patterns +- Metrics and KPIs +- Chart integration +- Real-time updates +- Responsive design + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 6. Kanban Boards (18 min) +**Coming Soon** + +- Kanban setup +- Drag and drop functionality +- Status management +- Card customization +- Workflow automation + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +### Advanced Tutorials + +For developers ready to extend ObjectUI. + +#### 7. Custom Component Development (30 min) +**Coming Soon** + +- Component architecture +- Creating custom components +- Schema type definitions +- Component registration +- Best practices + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 8. Plugin Development (35 min) +**Coming Soon** + +- Plugin architecture +- Creating a new plugin +- Publishing to npm +- Testing plugins +- Documentation + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 9. Performance Optimization (22 min) +**Coming Soon** + +- Bundle size optimization +- Lazy loading strategies +- Component memoization +- Virtual scrolling +- Performance monitoring + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +#### 10. Security Best Practices (20 min) +**Coming Soon** + +- Input validation and sanitization +- XSS prevention +- CSRF protection +- API security +- Authentication patterns + +**Watch on**: [YouTube](#) | [Bilibili](#) + +--- + +### Real-World Projects + +Build complete applications from scratch. + +#### 11. Complete CRM System (60 min) +**Coming Soon** + +Full tutorial series building a production CRM: +- Part 1: Project setup and architecture +- Part 2: Contact management +- Part 3: Deal pipeline +- Part 4: Reporting and analytics +- Part 5: Deployment + +**Watch on**: [YouTube Playlist](#) | [Bilibili Playlist](#) + +--- + +#### 12. E-commerce Backend (45 min) +**Coming Soon** + +Build an e-commerce admin panel: +- Product catalog management +- Order processing +- Inventory tracking +- Customer management +- Analytics dashboard + +**Watch on**: [YouTube Playlist](#) | [Bilibili Playlist](#) + +--- + +#### 13. Analytics Dashboard (40 min) +**Coming Soon** + +Create a data analytics platform: +- Data visualization +- Custom reports +- Export functionality +- Real-time updates +- User permissions + +**Watch on**: [YouTube Playlist](#) | [Bilibili Playlist](#) + +--- + +## 📺 Platform Links + +### YouTube Channel +[**Subscribe to ObjectUI on YouTube**](#) + +Features: +- High-quality 1080p videos +- English subtitles +- Community discussions +- Notifications for new videos + +### Bilibili Channel +[**关注 ObjectUI 在 Bilibili**](#) + +Features: +- 中文字幕 +- 高清视频 +- 弹幕互动 +- 新视频通知 + +## 🎓 Learning Paths + +### Path 1: Beginner +**Total Time**: ~2 hours + +1. Introduction to ObjectUI +2. Quick Start Tutorial +3. Building Your First Form +4. Data Tables and Grids + +### Path 2: Intermediate +**Total Time**: ~3 hours + +1. Building Dashboards +2. Kanban Boards +3. Custom Component Development +4. Performance Optimization + +### Path 3: Advanced +**Total Time**: ~4 hours + +1. Plugin Development +2. Security Best Practices +3. Complete CRM System +4. E-commerce Backend + +## 📝 Video Resources + +All videos include: +- ✅ **Source code** - Available on GitHub +- ✅ **Written transcript** - For accessibility +- ✅ **Timestamps** - Quick navigation +- ✅ **Chapter markers** - Jump to sections +- ✅ **Subtitles** - English and Chinese + +## 🔔 Stay Updated + +Subscribe to get notified when new tutorials are released: + +- [YouTube Channel](#) - English content +- [Bilibili Channel](#) - Chinese content +- [Newsletter](/newsletter) - Weekly updates +- [Twitter/X](https://twitter.com/objectui) - Announcements + +## 💡 Tutorial Requests + +Have a topic you'd like us to cover? Submit your request: + +- [GitHub Discussions](https://github.com/objectstack-ai/objectui/discussions) +- [Vote on existing requests](https://github.com/objectstack-ai/objectui/discussions/categories/tutorial-requests) + +## 📖 Related Resources + +- [Documentation](/docs) - Complete written guides +- [Examples](https://github.com/objectstack-ai/objectui/tree/main/examples) - Sample applications +- [Storybook](https://storybook.objectui.org) - Interactive component explorer +- [API Reference](/docs/api) - Detailed API documentation + +## 🌐 Community Translations + +Help translate video subtitles: +- [Translation Guide](https://github.com/objectstack-ai/objectui/blob/main/TRANSLATION.md) +- [Active translations](https://github.com/objectstack-ai/objectui/tree/main/subtitles) + +Supported languages: +- English (Original) +- 中文 (Chinese) +- 日本語 (Japanese) - Coming Soon +- 한국어 (Korean) - Coming Soon +- Español (Spanish) - Coming Soon + +--- + +**Note**: Video tutorials are currently in production. Check back soon for updates, or [subscribe](#) to be notified when they're released! diff --git a/content/docs/guide/zero-to-deployment.mdx b/content/docs/guide/zero-to-deployment.mdx new file mode 100644 index 00000000..c7a56b28 --- /dev/null +++ b/content/docs/guide/zero-to-deployment.mdx @@ -0,0 +1,711 @@ +--- +title: "Zero to Deployment" +description: "Complete tutorial: Build and deploy a production-ready app with ObjectUI" +--- + +# Zero to Deployment + +Build and deploy a complete task management application using ObjectUI. This tutorial takes you from zero to a production-ready app deployed on Vercel. + +**What you'll build**: A full-featured task manager with: +- ✅ Task creation and editing +- ✅ Status management (Todo, In Progress, Done) +- ✅ Priority levels +- ✅ Filtering and search +- ✅ Responsive design +- ✅ Dark mode support + +**Time to complete**: ~30 minutes + +## Prerequisites + +- Node.js 18+ installed +- Basic React knowledge +- A GitHub account (for deployment) + +## Step 1: Project Setup (3 minutes) + +Create a new Vite project: + +```bash +npm create vite@latest task-manager -- --template react-ts +cd task-manager +npm install +``` + +Install ObjectUI packages: + +```bash +npm install @object-ui/react @object-ui/components @object-ui/fields @object-ui/core +npm install -D tailwindcss postcss autoprefixer tailwindcss-animate +npx tailwindcss init -p +``` + +## Step 2: Configure Tailwind (2 minutes) + +Update `tailwind.config.js`: + +```js title="tailwind.config.js" +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: ['class'], + content: [ + './index.html', + './src/**/*.{js,ts,jsx,tsx}', + './node_modules/@object-ui/**/*.{js,ts,jsx,tsx}', + ], + theme: { + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + }, + }, + plugins: [require('tailwindcss-animate')], +} +``` + +Replace `src/index.css` with: + +```css title="src/index.css" +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} +``` + +## Step 3: Define the Schema (5 minutes) + +Create the task manager schema: + +```tsx title="src/schema.ts" +export const taskManagerSchema = { + type: 'page', + className: 'min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 p-8', + children: [ + { + type: 'container', + className: 'max-w-6xl mx-auto', + children: [ + // Header + { + type: 'flex', + className: 'justify-between items-center mb-8', + children: [ + { + type: 'flex', + direction: 'col', + children: [ + { + type: 'text', + content: 'Task Manager', + className: 'text-4xl font-bold text-gray-900 dark:text-white', + }, + { + type: 'text', + content: 'Stay organized and productive', + className: 'text-gray-600 dark:text-gray-400 mt-2', + }, + ], + }, + { + type: 'button', + text: 'New Task', + variant: 'default', + className: 'shadow-lg', + onClick: { + type: 'dialog', + title: 'Create New Task', + content: { + type: 'form', + fields: [ + { + type: 'field', + fieldType: 'text', + name: 'title', + label: 'Task Title', + placeholder: 'Enter task title', + required: true, + }, + { + type: 'field', + fieldType: 'textarea', + name: 'description', + label: 'Description', + placeholder: 'Task description...', + rows: 3, + }, + { + type: 'field', + fieldType: 'select', + name: 'status', + label: 'Status', + options: [ + { label: 'Todo', value: 'todo' }, + { label: 'In Progress', value: 'in_progress' }, + { label: 'Done', value: 'done' }, + ], + defaultValue: 'todo', + }, + { + type: 'field', + fieldType: 'select', + name: 'priority', + label: 'Priority', + options: [ + { label: 'Low', value: 'low' }, + { label: 'Medium', value: 'medium' }, + { label: 'High', value: 'high' }, + ], + defaultValue: 'medium', + }, + { + type: 'field', + fieldType: 'date', + name: 'dueDate', + label: 'Due Date', + }, + ], + onSubmit: { + type: 'notification', + message: 'Task created successfully!', + }, + }, + }, + }, + ], + }, + + // Filters + { + type: 'card', + className: 'mb-6', + children: [ + { + type: 'flex', + gap: 4, + className: 'flex-wrap', + children: [ + { + type: 'field', + fieldType: 'text', + name: 'search', + placeholder: 'Search tasks...', + className: 'flex-1 min-w-64', + }, + { + type: 'field', + fieldType: 'select', + name: 'statusFilter', + placeholder: 'All Statuses', + options: [ + { label: 'All', value: '' }, + { label: 'Todo', value: 'todo' }, + { label: 'In Progress', value: 'in_progress' }, + { label: 'Done', value: 'done' }, + ], + }, + { + type: 'field', + fieldType: 'select', + name: 'priorityFilter', + placeholder: 'All Priorities', + options: [ + { label: 'All', value: '' }, + { label: 'Low', value: 'low' }, + { label: 'Medium', value: 'medium' }, + { label: 'High', value: 'high' }, + ], + }, + ], + }, + ], + }, + + // Task Grid + { + type: 'grid', + cols: 3, + gap: 6, + className: 'mb-8', + children: [ + // Todo Column + { + type: 'card', + title: 'Todo', + className: 'bg-white dark:bg-gray-800', + children: [ + { + type: 'flex', + direction: 'col', + gap: 3, + children: [ + { + type: 'card', + className: 'bg-gray-50 dark:bg-gray-700 hover:shadow-md transition-shadow cursor-pointer', + children: [ + { + type: 'flex', + justify: 'between', + className: 'mb-2', + children: [ + { + type: 'text', + content: 'Setup project', + className: 'font-semibold', + }, + { + type: 'badge', + text: 'High', + variant: 'destructive', + }, + ], + }, + { + type: 'text', + content: 'Initialize repository and setup CI/CD', + className: 'text-sm text-gray-600 dark:text-gray-400 mb-3', + }, + { + type: 'text', + content: 'Due: Jan 15, 2024', + className: 'text-xs text-gray-500', + }, + ], + }, + ], + }, + ], + }, + + // In Progress Column + { + type: 'card', + title: 'In Progress', + className: 'bg-white dark:bg-gray-800', + children: [ + { + type: 'flex', + direction: 'col', + gap: 3, + children: [ + { + type: 'card', + className: 'bg-blue-50 dark:bg-blue-900/20 hover:shadow-md transition-shadow cursor-pointer', + children: [ + { + type: 'flex', + justify: 'between', + className: 'mb-2', + children: [ + { + type: 'text', + content: 'Build UI components', + className: 'font-semibold', + }, + { + type: 'badge', + text: 'Medium', + variant: 'secondary', + }, + ], + }, + { + type: 'text', + content: 'Create reusable React components', + className: 'text-sm text-gray-600 dark:text-gray-400 mb-3', + }, + { + type: 'progress', + value: 65, + className: 'mb-2', + }, + ], + }, + ], + }, + ], + }, + + // Done Column + { + type: 'card', + title: 'Done', + className: 'bg-white dark:bg-gray-800', + children: [ + { + type: 'flex', + direction: 'col', + gap: 3, + children: [ + { + type: 'card', + className: 'bg-green-50 dark:bg-green-900/20 hover:shadow-md transition-shadow cursor-pointer', + children: [ + { + type: 'flex', + justify: 'between', + className: 'mb-2', + children: [ + { + type: 'text', + content: 'Design mockups', + className: 'font-semibold line-through text-gray-500', + }, + { + type: 'badge', + text: 'Low', + variant: 'outline', + }, + ], + }, + { + type: 'text', + content: 'Completed Jan 10, 2024', + className: 'text-xs text-gray-500', + }, + ], + }, + ], + }, + ], + }, + ], + }, + + // Stats + { + type: 'grid', + cols: 3, + gap: 4, + children: [ + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: '12', + className: 'text-3xl font-bold text-blue-600', + }, + { + type: 'text', + content: 'Total Tasks', + className: 'text-sm text-gray-600 dark:text-gray-400', + }, + ], + }, + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: '5', + className: 'text-3xl font-bold text-green-600', + }, + { + type: 'text', + content: 'Completed', + className: 'text-sm text-gray-600 dark:text-gray-400', + }, + ], + }, + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: '42%', + className: 'text-3xl font-bold text-purple-600', + }, + { + type: 'text', + content: 'Progress', + className: 'text-sm text-gray-600 dark:text-gray-400', + }, + ], + }, + ], + }, + ], + }, + ], +}; +``` + +## Step 4: Build the App (3 minutes) + +Update `src/App.tsx`: + +```tsx title="src/App.tsx" +import { SchemaRenderer } from '@object-ui/react'; +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; +import { taskManagerSchema } from './schema'; +import './index.css'; + +// Register components +registerAllComponents(ComponentRegistry); +registerAllFields(); + +function App() { + return ; +} + +export default App; +``` + +## Step 5: Test Locally (2 minutes) + +```bash +npm run dev +``` + +Open [http://localhost:5173](http://localhost:5173) to see your app! 🎉 + +## Step 6: Add Dark Mode Toggle (5 minutes) + +Create a theme toggle: + +```tsx title="src/App.tsx" +import { useState, useEffect } from 'react'; +import { SchemaRenderer } from '@object-ui/react'; +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; +import { taskManagerSchema } from './schema'; +import './index.css'; + +registerAllComponents(ComponentRegistry); +registerAllFields(); + +function App() { + const [isDark, setIsDark] = useState(false); + + useEffect(() => { + if (isDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }, [isDark]); + + return ( +
+ + +
+ ); +} + +export default App; +``` + +## Step 7: Build for Production (2 minutes) + +```bash +npm run build +``` + +This creates an optimized production build in the `dist` folder. + +## Step 8: Deploy to Vercel (5 minutes) + +### Option A: Deploy via CLI + +```bash +# Install Vercel CLI +npm i -g vercel + +# Deploy +vercel +``` + +### Option B: Deploy via GitHub + +1. Push your code to GitHub: + +```bash +git init +git add . +git commit -m "Initial commit" +git branch -M main +git remote add origin https://github.com/yourusername/task-manager.git +git push -u origin main +``` + +2. Go to [vercel.com](https://vercel.com) +3. Click "New Project" +4. Import your GitHub repository +5. Click "Deploy" + +That's it! Your app is now live! 🚀 + +## Step 9: Add Backend Integration (Optional) + +To connect to a real API: + +```tsx title="src/schema.ts" +// Update the task grid to use a data source +{ + type: 'data-table', + dataSource: { + api: '/api/tasks', + method: 'GET', + }, + columns: [ + { key: 'title', title: 'Task' }, + { key: 'status', title: 'Status' }, + { key: 'priority', title: 'Priority' }, + { key: 'dueDate', title: 'Due Date' }, + ], +} +``` + +## What You've Learned + +✅ Setting up a new ObjectUI project +✅ Configuring Tailwind CSS +✅ Defining schemas for complex UIs +✅ Using components (cards, grids, forms, buttons) +✅ Implementing dark mode +✅ Building and deploying to production + +## Next Steps + +- [Component Documentation](/docs/components) - Explore all available components +- [Advanced Guides](/docs/guide/custom-components) - Build custom components +- [Plugin Development](/docs/guide/plugin-development) - Extend ObjectUI +- [Performance Optimization](/docs/guide/performance) - Optimize your app + +## Complete Example + +The full source code is available at: +- [GitHub Repository](https://github.com/objectstack-ai/objectui/tree/main/examples/todo) +- [Live Demo](https://objectui-todo.vercel.app) + +## Troubleshooting + +### Build fails with "Cannot find module" + +Clear cache and reinstall: + +```bash +rm -rf node_modules package-lock.json +npm install +``` + +### Vercel deployment fails + +Ensure `dist` is in `.gitignore` but build command is set: + +```json title="package.json" +{ + "scripts": { + "build": "vite build" + } +} +``` + +### Styles not loading in production + +Check `tailwind.config.js` includes ObjectUI in content array. + +## Support + +Need help? Check out: +- [Documentation](/docs) +- [GitHub Issues](https://github.com/objectstack-ai/objectui/issues) +- [Community Discussions](https://github.com/objectstack-ai/objectui/discussions) From bb6a54ab284657c6a4ad96f8012a5a868921f579 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:06:03 +0000 Subject: [PATCH 3/6] Add security guide and case studies infrastructure Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/case-studies/crm-system.mdx | 714 ++++++++++++++++++++++ content/docs/case-studies/index.md | 106 ++++ content/docs/guide/meta.json | 6 +- content/docs/guide/security.mdx | 726 +++++++++++++++++++++++ 4 files changed, 1551 insertions(+), 1 deletion(-) create mode 100644 content/docs/case-studies/crm-system.mdx create mode 100644 content/docs/case-studies/index.md create mode 100644 content/docs/guide/security.mdx diff --git a/content/docs/case-studies/crm-system.mdx b/content/docs/case-studies/crm-system.mdx new file mode 100644 index 00000000..e570faef --- /dev/null +++ b/content/docs/case-studies/crm-system.mdx @@ -0,0 +1,714 @@ +--- +title: "CRM System Case Study" +description: "Build a complete Customer Relationship Management system with ObjectUI" +--- + +# Complete CRM System + +Build a production-ready Customer Relationship Management system using ObjectUI. This comprehensive case study walks through creating a full-featured CRM from scratch. + +## Overview + +### The Challenge + +Modern businesses need powerful CRM systems to manage customer relationships, track sales pipelines, and analyze business performance. Traditional custom development takes months and significant resources. + +### The Solution + +Using ObjectUI's schema-driven approach, we built a complete CRM system in 2-3 weeks with: +- 📇 Contact and company management +- 💼 Visual deal pipeline (drag-and-drop Kanban) +- 📊 Sales analytics and reporting +- 📧 Activity timeline and communications +- 👥 Role-based access control +- 🔍 Advanced search and filtering + +### Tech Stack + +- **Frontend**: ObjectUI + React 18 + TypeScript +- **Backend**: Next.js API Routes +- **Database**: PostgreSQL with Prisma ORM +- **Authentication**: NextAuth.js +- **Deployment**: Vercel + +### Demo + +- [**Live Demo**](https://crm-demo.objectui.org) (Coming Soon) +- [**Source Code**](https://github.com/objectstack-ai/objectui/tree/main/examples/crm) + +--- + +## System Architecture + +### Data Model + +```prisma +// schema.prisma +model Contact { + id String @id @default(cuid()) + firstName String + lastName String + email String @unique + phone String? + position String? + companyId String? + company Company? @relation(fields: [companyId], references: [id]) + deals Deal[] + activities Activity[] + tags Tag[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Company { + id String @id @default(cuid()) + name String + industry String? + website String? + size String? // "1-10", "11-50", "51-200", "201-500", "500+" + contacts Contact[] + deals Deal[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Deal { + id String @id @default(cuid()) + title String + amount Decimal + stage String // "lead", "qualified", "proposal", "negotiation", "closed-won", "closed-lost" + probability Int // 0-100 + expectedClose DateTime? + contactId String? + contact Contact? @relation(fields: [contactId], references: [id]) + companyId String? + company Company? @relation(fields: [companyId], references: [id]) + ownerId String + owner User @relation(fields: [ownerId], references: [id]) + activities Activity[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Activity { + id String @id @default(cuid()) + type String // "call", "email", "meeting", "note", "task" + subject String + content String? + dueDate DateTime? + completed Boolean @default(false) + contactId String? + contact Contact? @relation(fields: [contactId], references: [id]) + dealId String? + deal Deal? @relation(fields: [dealId], references: [id]) + userId String + user User @relation(fields: [userId], references: [id]) + createdAt DateTime @default(now()) +} + +model User { + id String @id @default(cuid()) + email String @unique + name String + role String // "admin", "manager", "sales-rep" + deals Deal[] + activities Activity[] + createdAt DateTime @default(now()) +} + +model Tag { + id String @id @default(cuid()) + name String @unique + color String + contacts Contact[] +} +``` + +### Application Structure + +``` +crm/ +├── src/ +│ ├── schemas/ +│ │ ├── dashboard.schema.ts # Main dashboard +│ │ ├── contacts.schema.ts # Contacts list & detail +│ │ ├── companies.schema.ts # Companies management +│ │ ├── deals.schema.ts # Deal pipeline (Kanban) +│ │ ├── activities.schema.ts # Activity timeline +│ │ └── reports.schema.ts # Analytics & reports +│ ├── api/ +│ │ ├── contacts/ +│ │ ├── companies/ +│ │ ├── deals/ +│ │ ├── activities/ +│ │ └── reports/ +│ ├── components/ +│ │ ├── DealCard.tsx # Custom deal card component +│ │ ├── ActivityTimeline.tsx # Activity visualization +│ │ └── MetricsCard.tsx # KPI display +│ └── lib/ +│ ├── prisma.ts # Database client +│ └── auth.ts # Authentication +├── prisma/ +│ └── schema.prisma +└── package.json +``` + +--- + +## Implementation Guide + +### Part 1: Project Setup (30 minutes) + +#### 1. Initialize Project + +```bash +# Create Next.js app +npx create-next-app@latest crm-app --typescript --tailwind --app +cd crm-app + +# Install dependencies +npm install @object-ui/react @object-ui/components @object-ui/fields @object-ui/plugin-kanban +npm install @prisma/client next-auth +npm install -D prisma +``` + +#### 2. Setup Database + +```bash +# Initialize Prisma +npx prisma init + +# Update .env +DATABASE_URL="postgresql://user:password@localhost:5432/crm?schema=public" + +# Create schema and migrate +npx prisma db push +npx prisma generate +``` + +#### 3. Configure ObjectUI + +```tsx title="src/app/providers.tsx" +'use client'; + +import { ComponentRegistry } from '@object-ui/core'; +import { registerAllComponents } from '@object-ui/components'; +import { registerAllFields } from '@object-ui/fields'; +import { registerKanbanPlugin } from '@object-ui/plugin-kanban'; + +export function Providers({ children }: { children: React.ReactNode }) { + // Register components once + React.useEffect(() => { + registerAllComponents(ComponentRegistry); + registerAllFields(); + registerKanbanPlugin(); + }, []); + + return <>{children}; +} +``` + +### Part 2: Dashboard Schema (1 hour) + +```typescript title="src/schemas/dashboard.schema.ts" +export const dashboardSchema = { + type: 'page', + className: 'min-h-screen bg-gray-50 dark:bg-gray-900', + children: [ + { + type: 'app-shell', + header: { + type: 'header-bar', + title: 'CRM Dashboard', + logo: '/logo.svg', + navigation: [ + { label: 'Dashboard', href: '/', icon: 'Home' }, + { label: 'Contacts', href: '/contacts', icon: 'Users' }, + { label: 'Companies', href: '/companies', icon: 'Building2' }, + { label: 'Deals', href: '/deals', icon: 'TrendingUp' }, + { label: 'Reports', href: '/reports', icon: 'BarChart3' }, + ], + userMenu: { + name: '{{user.name}}', + email: '{{user.email}}', + avatar: '{{user.avatar}}', + items: [ + { label: 'Profile', href: '/profile' }, + { label: 'Settings', href: '/settings' }, + { label: 'Logout', action: { type: 'logout' } }, + ], + }, + }, + children: [ + { + type: 'container', + className: 'p-8', + children: [ + // KPI Metrics + { + type: 'grid', + cols: 4, + gap: 6, + className: 'mb-8', + children: [ + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: 'Total Revenue', + className: 'text-sm text-gray-600 mb-2', + }, + { + type: 'text', + content: '$1,234,567', + className: 'text-3xl font-bold text-green-600', + }, + { + type: 'text', + content: '+12.5% from last month', + className: 'text-xs text-gray-500 mt-1', + }, + ], + }, + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: 'Active Deals', + className: 'text-sm text-gray-600 mb-2', + }, + { + type: 'text', + content: '47', + className: 'text-3xl font-bold text-blue-600', + }, + { + type: 'text', + content: '8 closing this week', + className: 'text-xs text-gray-500 mt-1', + }, + ], + }, + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: 'Win Rate', + className: 'text-sm text-gray-600 mb-2', + }, + { + type: 'text', + content: '68%', + className: 'text-3xl font-bold text-purple-600', + }, + { + type: 'text', + content: '+5% improvement', + className: 'text-xs text-gray-500 mt-1', + }, + ], + }, + { + type: 'card', + className: 'text-center', + children: [ + { + type: 'text', + content: 'New Contacts', + className: 'text-sm text-gray-600 mb-2', + }, + { + type: 'text', + content: '156', + className: 'text-3xl font-bold text-orange-600', + }, + { + type: 'text', + content: 'This month', + className: 'text-xs text-gray-500 mt-1', + }, + ], + }, + ], + }, + + // Charts Section + { + type: 'grid', + cols: 2, + gap: 6, + className: 'mb-8', + children: [ + { + type: 'card', + title: 'Revenue Trend', + children: [ + { + type: 'line-chart', + height: 300, + dataSource: { + api: '/api/reports/revenue-trend', + method: 'GET', + }, + }, + ], + }, + { + type: 'card', + title: 'Deals by Stage', + children: [ + { + type: 'bar-chart', + height: 300, + dataSource: { + api: '/api/reports/deals-by-stage', + method: 'GET', + }, + }, + ], + }, + ], + }, + + // Recent Activities + { + type: 'card', + title: 'Recent Activities', + children: [ + { + type: 'data-table', + dataSource: { + api: '/api/activities/recent', + method: 'GET', + }, + columns: [ + { key: 'type', title: 'Type', width: 100 }, + { key: 'subject', title: 'Subject' }, + { key: 'contact', title: 'Contact' }, + { key: 'user', title: 'User' }, + { key: 'createdAt', title: 'Date', type: 'datetime' }, + ], + pageSize: 10, + }, + ], + }, + ], + }, + ], + }, + ], +}; +``` + +### Part 3: Deal Pipeline (Kanban) (2 hours) + +```typescript title="src/schemas/deals.schema.ts" +export const dealsSchema = { + type: 'page', + children: [ + { + type: 'container', + className: 'p-8', + children: [ + { + type: 'flex', + justify: 'between', + className: 'mb-6', + children: [ + { + type: 'text', + content: 'Sales Pipeline', + className: 'text-2xl font-bold', + }, + { + type: 'button', + text: 'New Deal', + onClick: { + type: 'dialog', + title: 'Create Deal', + content: { + type: 'form', + fields: [ + { + type: 'field', + fieldType: 'text', + name: 'title', + label: 'Deal Title', + required: true, + }, + { + type: 'field', + fieldType: 'currency', + name: 'amount', + label: 'Deal Amount', + required: true, + }, + { + type: 'field', + fieldType: 'select', + name: 'contactId', + label: 'Contact', + dataSource: { + api: '/api/contacts', + method: 'GET', + }, + }, + { + type: 'field', + fieldType: 'date', + name: 'expectedClose', + label: 'Expected Close Date', + }, + ], + onSubmit: { + type: 'api', + method: 'POST', + url: '/api/deals', + onSuccess: { + type: 'notification', + message: 'Deal created successfully!', + }, + }, + }, + }, + }, + ], + }, + + { + type: 'kanban', + dataSource: { + api: '/api/deals', + method: 'GET', + }, + columns: [ + { id: 'lead', title: 'Lead', color: 'gray' }, + { id: 'qualified', title: 'Qualified', color: 'blue' }, + { id: 'proposal', title: 'Proposal', color: 'yellow' }, + { id: 'negotiation', title: 'Negotiation', color: 'orange' }, + { id: 'closed-won', title: 'Closed Won', color: 'green' }, + { id: 'closed-lost', title: 'Closed Lost', color: 'red' }, + ], + cardTemplate: { + type: 'card', + className: 'cursor-move hover:shadow-lg transition-shadow', + children: [ + { + type: 'flex', + justify: 'between', + className: 'mb-2', + children: [ + { + type: 'text', + content: '{{title}}', + className: 'font-semibold', + }, + { + type: 'badge', + text: '{{probability}}%', + }, + ], + }, + { + type: 'text', + content: '${{amount}}', + className: 'text-2xl font-bold text-green-600 mb-2', + }, + { + type: 'text', + content: '{{contact.name}}', + className: 'text-sm text-gray-600 mb-1', + }, + { + type: 'text', + content: 'Expected: {{expectedClose}}', + className: 'text-xs text-gray-500', + }, + ], + }, + onCardMove: { + type: 'api', + method: 'PATCH', + url: '/api/deals/{{id}}/stage', + }, + }, + ], + }, + ], +}; +``` + +### Part 4: API Routes (2 hours) + +```typescript title="src/app/api/deals/route.ts" +import { NextRequest, NextResponse } from 'next/server'; +import { prisma } from '@/lib/prisma'; +import { getServerSession } from 'next-auth'; + +export async function GET(request: NextRequest) { + const session = await getServerSession(); + + if (!session) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const deals = await prisma.deal.findMany({ + include: { + contact: true, + company: true, + owner: true, + }, + orderBy: { + createdAt: 'desc', + }, + }); + + return NextResponse.json(deals); +} + +export async function POST(request: NextRequest) { + const session = await getServerSession(); + + if (!session?.user?.id) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const body = await request.json(); + + const deal = await prisma.deal.create({ + data: { + title: body.title, + amount: body.amount, + stage: 'lead', + probability: 10, + expectedClose: body.expectedClose, + contactId: body.contactId, + ownerId: session.user.id, + }, + }); + + return NextResponse.json(deal); +} +``` + +--- + +## Key Features Implementation + +### 1. Contact Management + +**Schema**: [View contacts.schema.ts](https://github.com/objectstack-ai/objectui/tree/main/examples/crm/src/schemas/contacts.schema.ts) + +Features: +- Grid view with search/filter +- Detail view with activity timeline +- Quick actions (call, email, note) +- Tag management + +### 2. Deal Pipeline + +**Schema**: [View deals.schema.ts](https://github.com/objectstack-ai/objectui/tree/main/examples/crm/src/schemas/deals.schema.ts) + +Features: +- Drag-and-drop Kanban board +- Deal probability tracking +- Expected close dates +- Revenue forecasting + +### 3. Activity Timeline + +**Schema**: [View activities.schema.ts](https://github.com/objectstack-ai/objectui/tree/main/examples/crm/src/schemas/activities.schema.ts) + +Features: +- Chronological activity feed +- Filter by type (call, email, meeting) +- Quick add actions +- Reminders and tasks + +### 4. Analytics & Reporting + +**Schema**: [View reports.schema.ts](https://github.com/objectstack-ai/objectui/tree/main/examples/crm/src/schemas/reports.schema.ts) + +Features: +- Revenue metrics +- Win/loss analysis +- Sales rep performance +- Export to PDF/Excel + +--- + +## Deployment + +### 1. Build for Production + +```bash +npm run build +``` + +### 2. Deploy to Vercel + +```bash +# Install Vercel CLI +npm i -g vercel + +# Deploy +vercel --prod +``` + +### 3. Configure Environment + +```env +DATABASE_URL=postgresql://... +NEXTAUTH_URL=https://your-domain.com +NEXTAUTH_SECRET=your-secret-key +``` + +--- + +## Next Steps + +### Feature Enhancements + +- [ ] Email integration (Gmail, Outlook) +- [ ] Calendar sync +- [ ] Mobile app +- [ ] AI-powered lead scoring +- [ ] Advanced reporting + +### Performance Optimizations + +- [ ] Implement caching (Redis) +- [ ] Database query optimization +- [ ] Image optimization +- [ ] Code splitting + +### Scaling + +- [ ] Multi-tenancy +- [ ] Horizontal scaling +- [ ] CDN integration +- [ ] Monitoring & alerts + +--- + +## Resources + +- [**Source Code**](https://github.com/objectstack-ai/objectui/tree/main/examples/crm) +- [**Live Demo**](https://crm-demo.objectui.org) +- [**API Documentation**](https://crm-demo.objectui.org/api-docs) +- [**Video Tutorial**](/docs/guide/video-tutorials#crm-system) + +--- + +## Community + +Share your CRM customizations: +- [GitHub Discussions](https://github.com/objectstack-ai/objectui/discussions) +- [Discord](https://discord.gg/objectui) diff --git a/content/docs/case-studies/index.md b/content/docs/case-studies/index.md new file mode 100644 index 00000000..a59abaf9 --- /dev/null +++ b/content/docs/case-studies/index.md @@ -0,0 +1,106 @@ +--- +title: "Case Studies" +description: "Real-world applications built with ObjectUI" +--- + +# Case Studies + +Learn from complete, production-ready applications built with ObjectUI. Each case study includes full source code, architecture decisions, and implementation details. + +## Featured Case Studies + +### 🏢 [Complete CRM System](/docs/case-studies/crm-system) + +Build a full-featured Customer Relationship Management system. + +**Features:** +- Contact and company management +- Deal pipeline with drag-and-drop +- Activity tracking and timeline +- Email integration +- Reporting and analytics +- Role-based access control + +**Tech Stack:** ObjectUI + Next.js + PostgreSQL + Prisma + +**Time to Build:** 2-3 weeks + +[**View Case Study →**](/docs/case-studies/crm-system) + +--- + +### 🛒 [E-commerce Backend](/docs/case-studies/ecommerce-backend) + +Create a comprehensive e-commerce admin panel. + +**Features:** +- Product catalog management +- Order processing and fulfillment +- Inventory tracking +- Customer management +- Analytics dashboard +- Payment integration + +**Tech Stack:** ObjectUI + React + Node.js + MongoDB + +**Time to Build:** 2-3 weeks + +[**View Case Study →**](/docs/case-studies/ecommerce-backend) + +--- + +### 📊 [Data Analytics Dashboard](/docs/case-studies/analytics-dashboard) + +Build a powerful data visualization platform. + +**Features:** +- Real-time metrics and KPIs +- Custom chart builder +- Report generation (PDF/Excel) +- Data filtering and aggregation +- User segmentation +- Export functionality + +**Tech Stack:** ObjectUI + React + PostgreSQL + Redis + +**Time to Build:** 1-2 weeks + +[**View Case Study →**](/docs/case-studies/analytics-dashboard) + +--- + +### ⚙️ [Workflow Engine](/docs/case-studies/workflow-engine) + +Implement a visual workflow automation system. + +**Features:** +- Drag-and-drop workflow builder +- Custom task types +- Conditional logic +- Parallel execution +- Error handling and retry +- Audit logging + +**Tech Stack:** ObjectUI + React + Node.js + BullMQ + +**Time to Build:** 3-4 weeks + +[**View Case Study →**](/docs/case-studies/workflow-engine) + +--- + +## Getting Started + +Choose a case study that matches your experience level: + +### Beginner to Intermediate + +Start with the **Analytics Dashboard** - it covers core ObjectUI concepts without overwhelming complexity. + +### Intermediate to Advanced + +Try the **E-commerce Backend** or **CRM System** - these demonstrate complex data relationships and user workflows. + +### Advanced + +Dive into the **Workflow Engine** - explores advanced patterns like dynamic schemas, custom execution engines, and real-time updates. diff --git a/content/docs/guide/meta.json b/content/docs/guide/meta.json index 4a8385a8..14e01aac 100644 --- a/content/docs/guide/meta.json +++ b/content/docs/guide/meta.json @@ -13,6 +13,10 @@ "fields", "component-registry", "plugins", - "schema-overview" + "schema-overview", + "custom-components", + "plugin-development", + "performance", + "security" ] } diff --git a/content/docs/guide/security.mdx b/content/docs/guide/security.mdx new file mode 100644 index 00000000..f4f9982a --- /dev/null +++ b/content/docs/guide/security.mdx @@ -0,0 +1,726 @@ +--- +title: "Security Best Practices" +description: "Build secure ObjectUI applications with industry best practices" +--- + +# Security Best Practices + +Protect your ObjectUI applications from common security vulnerabilities. This guide covers input validation, XSS prevention, authentication, and more. + +## Input Validation and Sanitization + +### 1. Validate User Input + +Always validate data before processing: + +```tsx +import { z } from 'zod'; + +// Define validation schema +const userSchema = z.object({ + name: z.string().min(1).max(100), + email: z.string().email(), + age: z.number().min(18).max(120), + role: z.enum(['user', 'admin', 'moderator']), +}); + +export function UserForm({ schema }: FormSchema) { + const handleSubmit = (data: unknown) => { + try { + // Validate input + const validated = userSchema.parse(data); + + // Safe to use validated data + processUser(validated); + } catch (error) { + if (error instanceof z.ZodError) { + console.error('Validation failed:', error.errors); + showErrors(error.errors); + } + } + }; + + return
{/* Form fields */}
; +} +``` + +### 2. Sanitize HTML Content + +Prevent XSS attacks by sanitizing HTML: + +```tsx +import DOMPurify from 'dompurify'; + +export function RichTextDisplay({ schema }: RichTextSchema) { + const { content } = schema; + + // ❌ Dangerous - Direct HTML injection + // return
; + + // ✅ Safe - Sanitized HTML + const sanitized = DOMPurify.sanitize(content, { + ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'a'], + ALLOWED_ATTR: ['href', 'title'], + }); + + return
; +} +``` + +### 3. Validate Schema Structure + +```tsx +import { ComponentSchema } from '@object-ui/types'; + +export function validateSchema(schema: unknown): schema is ComponentSchema { + if (!schema || typeof schema !== 'object') { + throw new Error('Schema must be an object'); + } + + const s = schema as Record; + + if (!s.type || typeof s.type !== 'string') { + throw new Error('Schema must have a valid type'); + } + + // Prevent script injection + if (s.type.includes('