initiall commit

This commit is contained in:
Tomas Dvorak
2026-04-10 12:03:31 +02:00
commit 7ddfb1f52b
276 changed files with 37629 additions and 0 deletions
+646
View File
@@ -0,0 +1,646 @@
# Primora Frontend Migration Guide
## Overview
This guide helps you migrate from the previous component patterns to the new enhanced component library.
---
## No Breaking Changes! 🎉
Good news: **All enhancements are backward compatible**. Your existing code will continue to work without modifications. This guide shows you how to leverage the new features.
---
## New Components Available
### 1. Replace Custom Modals with Modal Component
**Before:**
```tsx
<Show when={showDialog()}>
<div class="fixed inset-0 bg-black/50 flex items-center justify-center">
<div class="bg-surface-1 rounded-lg p-6 max-w-md">
<h2>Confirm Action</h2>
<p>Are you sure?</p>
<div class="flex gap-3 mt-4">
<button onClick={() => setShowDialog(false)}>Cancel</button>
<button onClick={handleConfirm}>Confirm</button>
</div>
</div>
</div>
</Show>
```
**After:**
```tsx
<Modal
open={showDialog()}
onClose={() => setShowDialog(false)}
title="Confirm Action"
description="Are you sure?"
size="md"
>
<ModalFooter align="right">
<Button variant="secondary" onClick={() => setShowDialog(false)}>
Cancel
</Button>
<Button variant="primary" onClick={handleConfirm}>
Confirm
</Button>
</ModalFooter>
</Modal>
```
**Benefits:**
- Automatic backdrop blur
- ESC key support
- Click outside to close
- Proper z-index management
- Smooth animations
- Accessibility built-in
---
### 2. Add Tooltips to Icon Buttons
**Before:**
```tsx
<Button variant="ghost" icon={<Icons.Trash />} />
```
**After:**
```tsx
<Tooltip content="Delete this item" placement="top">
<Button variant="ghost" icon={<Icons.Trash />} />
</Tooltip>
```
**Benefits:**
- Better UX with contextual help
- Smart positioning
- Keyboard accessible
- Configurable delay
---
### 3. Replace Custom Dropdowns with Dropdown Component
**Before:**
```tsx
<Show when={showMenu()}>
<div class="absolute bg-surface-1 rounded-lg shadow-lg">
<button onClick={handleEdit}>Edit</button>
<button onClick={handleDelete}>Delete</button>
</div>
</Show>
```
**After:**
```tsx
<Dropdown
trigger={<Button variant="secondary">Actions</Button>}
items={[
{ id: "edit", label: "Edit", icon: <Icons.Edit />, onClick: handleEdit },
{ id: "divider", divider: true },
{ id: "delete", label: "Delete", icon: <Icons.Trash />, danger: true, onClick: handleDelete },
]}
/>
```
**Benefits:**
- Smart positioning
- Click outside to close
- Keyboard navigation
- Icon support
- Danger states
- Dividers
---
### 4. Use Toast Instead of Custom Alerts
**Before:**
```tsx
<Show when={message()}>
<div class="fixed bottom-4 right-4 bg-success-muted p-4 rounded-lg">
{message()}
</div>
</Show>
```
**After:**
```tsx
// Add once to app root
<ToastContainer />
// Use anywhere
toast.success("Operation successful!");
toast.error("Something went wrong");
toast.info("New update available");
```
**Benefits:**
- Global API
- Auto-dismiss
- Stacked notifications
- Multiple variants
- Smooth animations
---
### 5. Add Loading States with Progress
**Before:**
```tsx
<Show when={loading()}>
<div class="spinner" />
</Show>
```
**After:**
```tsx
// Spinner
<Spinner size="lg" variant="primary" />
// Progress bar
<Progress value={uploadProgress()} showLabel label="Uploading..." />
// Circular progress
<CircularProgress value={60} showLabel />
```
**Benefits:**
- Multiple variants
- Size options
- Label support
- Smooth animations
---
### 6. Use Tabs for Multi-Section Views
**Before:**
```tsx
<div class="flex gap-2 border-b">
<button
class={activeTab() === "overview" ? "border-b-2 border-accent" : ""}
onClick={() => setActiveTab("overview")}
>
Overview
</button>
<button
class={activeTab() === "settings" ? "border-b-2 border-accent" : ""}
onClick={() => setActiveTab("settings")}
>
Settings
</button>
</div>
<Show when={activeTab() === "overview"}>
<OverviewPanel />
</Show>
<Show when={activeTab() === "settings"}>
<SettingsPanel />
</Show>
```
**After:**
```tsx
<Tabs
variant="underline"
defaultTab="overview"
tabs={[
{ id: "overview", label: "Overview", icon: <Icons.Dashboard />, content: <OverviewPanel /> },
{ id: "settings", label: "Settings", badge: "3", content: <SettingsPanel /> },
]}
onChange={(tabId) => console.log(tabId)}
/>
```
**Benefits:**
- Multiple variants (default, pills, underline)
- Icon and badge support
- Disabled states
- Smooth transitions
- Keyboard navigation
---
## Enhanced Components
### Button Enhancements
**New Features:**
```tsx
// Loading state
<Button variant="primary" loading={submitting()}>
Saving...
</Button>
// Icon positioning
<Button icon={<Icons.Plus />} iconPosition="left">
Create
</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
```
---
### Card Enhancements
**New Features:**
```tsx
// Elevated variant
<Card variant="elevated">
<CardHeader eyebrow="Overview" title="Dashboard" description="Monitor metrics" />
<CardContent>...</CardContent>
<CardFooter align="right">
<Button>Action</Button>
</CardFooter>
</Card>
// Interactive card
<Card variant="interactive" onClick={handleClick}>
Clickable card
</Card>
// Stat card
<StatCard
label="Total Users"
value={1234}
icon={<Icons.Users />}
trend="up"
trendValue="+12%"
/>
// Hover effects
<Card class="card-hover-lift spotlight">
Interactive card with effects
</Card>
```
---
### Input Enhancements
**New Features:**
```tsx
// Error states
<Input
label="Email"
value={email()}
onInput={(e) => setEmail(e.currentTarget.value)}
error={errors().email}
/>
// Sizes
<Input size="sm" placeholder="Small input" />
<Input size="md" placeholder="Medium input" />
<Input size="lg" placeholder="Large input" />
```
---
## New CSS Utilities
### Animations
```tsx
// Fade in
<div class="animate-fade-in">Content</div>
// Slide animations
<div class="animate-slide-up">Slide from bottom</div>
<div class="animate-slide-down">Slide from top</div>
<div class="animate-slide-left">Slide from right</div>
<div class="animate-slide-right">Slide from left</div>
// Scale and bounce
<div class="animate-scale-in">Scale in</div>
<div class="animate-bounce-in">Bounce in</div>
// Stagger children
<div class="stagger-fade-in">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```
---
### Visual Effects
```tsx
// Card effects
<Card class="card-hover-lift">Lifts on hover</Card>
<Card class="spotlight">Shine effect</Card>
// Glass effect
<div class="glass">Frosted glass background</div>
// Text effects
<span class="text-shimmer">Shimmer text</span>
<span class="neon-glow">Neon glow</span>
<span class="gradient-text">Gradient text</span>
// Loading states
<div class="skeleton h-4 w-32" />
<div class="skeleton-wave h-20 w-full" />
<SkeletonCard lines={3} />
```
---
## Common Migration Patterns
### 1. Confirmation Dialogs
**Before:**
```tsx
const [showConfirm, setShowConfirm] = createSignal(false);
<Show when={showConfirm()}>
<div class="fixed inset-0 bg-black/50 flex items-center justify-center">
<div class="bg-surface-1 rounded-lg p-6">
<h3>Confirm Deletion</h3>
<p>This action cannot be undone.</p>
<div class="flex gap-3 mt-4">
<button onClick={() => setShowConfirm(false)}>Cancel</button>
<button onClick={handleDelete}>Delete</button>
</div>
</div>
</div>
</Show>
```
**After:**
```tsx
const [showConfirm, setShowConfirm] = createSignal(false);
<Modal
open={showConfirm()}
onClose={() => setShowConfirm(false)}
title="Confirm Deletion"
description="This action cannot be undone."
size="sm"
>
<ModalFooter align="right">
<Button variant="secondary" onClick={() => setShowConfirm(false)}>
Cancel
</Button>
<Button variant="danger" onClick={handleDelete}>
Delete
</Button>
</ModalFooter>
</Modal>
```
---
### 2. Action Menus
**Before:**
```tsx
<button onClick={() => setShowMenu(!showMenu())}></button>
<Show when={showMenu()}>
<div class="absolute bg-surface-1 rounded-lg shadow-lg">
<button onClick={handleEdit}>Edit</button>
<button onClick={handleDelete}>Delete</button>
</div>
</Show>
```
**After:**
```tsx
<Dropdown
trigger={<Button variant="ghost" size="sm"></Button>}
items={[
{ id: "view", label: "View Details", icon: <Icons.Eye /> },
{ id: "edit", label: "Edit", icon: <Icons.Edit /> },
{ id: "divider", divider: true },
{ id: "delete", label: "Delete", icon: <Icons.Trash />, danger: true },
]}
/>
```
---
### 3. Loading States
**Before:**
```tsx
<Show when={!loading()} fallback={<div class="spinner" />}>
{/* Content */}
</Show>
```
**After:**
```tsx
<Show when={!loading()} fallback={<Spinner size="lg" />}>
{/* Content */}
</Show>
// Or with progress
<Show when={!loading()} fallback={
<div class="flex flex-col items-center gap-4">
<Spinner size="lg" />
<Progress value={progress()} showLabel />
</div>
}>
{/* Content */}
</Show>
```
---
### 4. Form Submissions
**Before:**
```tsx
<form onSubmit={handleSubmit}>
<input
type="text"
value={name()}
onInput={(e) => setName(e.currentTarget.value)}
/>
<button type="submit" disabled={submitting()}>
{submitting() ? "Saving..." : "Save"}
</button>
</form>
```
**After:**
```tsx
<form onSubmit={handleSubmit} class="space-y-4">
<Input
label="Name"
value={name()}
onInput={(e) => setName(e.currentTarget.value)}
error={errors().name}
/>
<Button type="submit" variant="primary" loading={submitting()}>
Save
</Button>
</form>
```
---
### 5. Success/Error Messages
**Before:**
```tsx
<Show when={successMessage()}>
<div class="bg-success-muted text-success p-4 rounded-lg">
{successMessage()}
</div>
</Show>
```
**After:**
```tsx
// Option 1: Message component
<Show when={successMessage()}>
<Message variant="success" dismissible onDismiss={() => setSuccessMessage("")}>
{successMessage()}
</Message>
</Show>
// Option 2: Toast (recommended)
toast.success(successMessage());
```
---
## Step-by-Step Migration
### Phase 1: Add ToastContainer
```tsx
// In your App.tsx or main component
import { ToastContainer } from "./components";
export default function App() {
return (
<>
<ToastContainer />
{/* Rest of your app */}
</>
);
}
```
### Phase 2: Replace Alerts with Toasts
Replace all custom alert/message displays with toast notifications.
### Phase 3: Add Tooltips
Add tooltips to icon-only buttons for better UX.
### Phase 4: Replace Custom Modals
Migrate custom modal implementations to the Modal component.
### Phase 5: Add Dropdowns
Replace custom dropdown menus with the Dropdown component.
### Phase 6: Enhance Forms
Add loading states, error handling, and progress indicators to forms.
### Phase 7: Add Tabs
Replace custom tab implementations with the Tabs component.
---
## Best Practices
### 1. Use Semantic Components
```tsx
// Good
<Button variant="primary" onClick={handleSubmit}>Submit</Button>
// Avoid
<button class="btn btn-primary" onClick={handleSubmit}>Submit</button>
```
### 2. Leverage Loading States
```tsx
// Good
<Button loading={submitting()}>Save</Button>
// Avoid
<Button disabled={submitting()}>
{submitting() ? "Saving..." : "Save"}
</Button>
```
### 3. Use Toast for Notifications
```tsx
// Good
toast.success("Project created!");
// Avoid
setMessage("Project created!");
setTimeout(() => setMessage(""), 3000);
```
### 4. Add Tooltips to Icons
```tsx
// Good
<Tooltip content="Delete">
<Button icon={<Icons.Trash />} />
</Tooltip>
// Avoid
<Button icon={<Icons.Trash />} />
```
### 5. Use Proper Variants
```tsx
// Good
<Button variant="danger" onClick={handleDelete}>Delete</Button>
// Avoid
<Button class="bg-error" onClick={handleDelete}>Delete</Button>
```
---
## Troubleshooting
### Modal Not Showing
Make sure the Modal is rendered and `open` prop is true:
```tsx
<Modal open={show()} onClose={() => setShow(false)}>
```
### Tooltip Not Appearing
Check that the tooltip has a trigger element:
```tsx
<Tooltip content="Help text">
<button>Hover me</button>
</Tooltip>
```
### Toast Not Working
Ensure ToastContainer is added to your app root:
```tsx
<ToastContainer />
```
### Dropdown Not Positioning Correctly
The dropdown uses Portal rendering. Make sure your app has proper z-index management.
---
## Need Help?
- **Quick Reference**: See `COMPONENT_GUIDE.md`
- **Detailed Docs**: See `FRONTEND_ENHANCEMENTS.md`
- **Design System**: See `project_frontend.md`
---
**Happy migrating! 🚀**