# vapora-leptos-ui

Glassmorphism UI component library for Leptos 0.8.15+

**Status**: Functional with core components implemented. Suitable for internal use and projects willing to contribute.

## Features

- 🎨 **Glassmorphism design** - Cyan/purple/pink gradients with backdrop blur
- 🔄 **CSR/SSR agnostic** - Components work in both client-side and server-side rendering contexts
- ♿ **Accessible** - ARIA labels, keyboard navigation (Modal), focus management (Modal)
- 📱 **Mobile responsive** - Tailwind-based responsive utilities
- 🎯 **UnoCSS compatible** - Works with build-time CSS generation
- 🧩 **Reusable** - Can be used in any Leptos 0.8+ project

## Installation

```toml
[dependencies]
vapora-leptos-ui = { path = "../vapora-leptos-ui" }
leptos = "0.8.15"
```

**Note**: Not yet published to crates.io. Use as a path dependency or git dependency.

## Quick Start

```rust
use leptos::prelude::*;
use vapora_leptos_ui::{Button, Input, Spinner, Variant, Size};

#[component]
fn App() -> impl IntoView {
    view! {
        <div class="p-6 space-y-4">
            <Button variant=Variant::Primary size=Size::Large>
                "Create Project"
            </Button>

            <Input
                input_type="text"
                placeholder="Enter your name..."
                on_input=Callback::new(|_ev| {
                    // Handle input
                })
            />

            <Spinner size=Size::Medium />
        </div>
    }
}
```

## Available Components

### ✅ Primitives (Fully Functional)

| Component | Description | Variants | Status |
|-----------|-------------|----------|--------|
| **Button** | Glassmorphism button | Primary, Secondary, Danger, Ghost | ✅ Complete |
| **Input** | Text input field | N/A | ✅ Complete |
| **Badge** | Status badge | Custom classes | ✅ Complete |
| **Spinner** | Loading animation | Small, Medium, Large | ✅ Complete |

### ✅ Layout (Fully Functional)

| Component | Description | Features | Status |
|-----------|-------------|----------|--------|
| **Card** | Container card | Glassmorphism, hoverable, glow colors | ✅ Complete |
| **Modal** | Dialog overlay | Portal, keyboard (Escape), focus trap, backdrop click | ✅ Complete |

### ✅ Data (Fully Functional)

| Component | Description | Features | Status |
|-----------|-------------|----------|--------|
| **Table** | Data table | Internal sorting, sortable columns | ✅ Complete |
| **Pagination** | Page controls | Current page, total pages, callbacks | ✅ Complete |
| **StatCard** | Metric display | Label, value, optional trend | ✅ Complete |

### ✅ Forms (Fully Functional)

| Component | Description | Features | Status |
|-----------|-------------|----------|--------|
| **FormField** | Form wrapper | Label, error display, help text, required indicator | ✅ Complete |
| **Validation** | Helper functions | `validate_required`, `validate_email`, `validate_min_length`, `validate_max_length` | ✅ Complete |

### ✅ Feedback (Fully Functional)

| Component | Description | Features | Status |
|-----------|-------------|----------|--------|
| **ToastProvider** | Toast context | Global notifications, auto-dismiss (3s) | ✅ Complete |
| **use_toast()** | Toast hook | Show success/error/info toasts | ✅ Complete |

### ✅ Navigation (Fully Functional)

| Component | Description | Features | Status |
|-----------|-------------|----------|--------|
| **SpaLink** | Client-side link | No page reload, external link detection | ✅ Complete |

### 🔧 Utilities

| Component | Description | Status |
|-----------|-------------|--------|
| **Portal** | DOM portal | ✅ Complete (used by Modal) |

## Theme System

```rust
use vapora_leptos_ui::{Variant, Size, BlurLevel, GlowColor};

// Visual variants
Variant::Primary    // Cyan-purple gradient
Variant::Secondary  // Transparent with border
Variant::Danger     // Red gradient
Variant::Ghost      // Subtle hover

// Size variants
Size::Small   // px-3 py-1.5 text-sm
Size::Medium  // px-4 py-2 text-base (default)
Size::Large   // px-6 py-3 text-lg

// Backdrop blur levels
BlurLevel::None, Sm, Md, Lg, Xl

// Glow colors (for Card)
GlowColor::None, Cyan, Purple, Pink, Blue
```

## Examples

See [cookbook.md](./cookbook.md) for comprehensive examples of each component.

### Modal with Form

```rust
use vapora_leptos_ui::{Modal, FormField, Input, Button};

#[component]
fn CreateProject() -> impl IntoView {
    let (show_modal, set_show_modal) = signal(false);
    let (title, set_title) = signal(String::new());

    view! {
        <Button on_click=Callback::new(move |_| set_show_modal.set(true))>
            "New Project"
        </Button>

        <Show when=move || show_modal.get()>
            <Modal on_close=Callback::new(move |_| set_show_modal.set(false))>
                <h2 class="text-2xl font-bold text-white mb-4">"Create Project"</h2>
                <FormField label="Title".to_string() required=true>
                    <Input
                        placeholder="Project name"
                        on_input=Callback::new(move |ev| {
                            // Extract value from event
                            set_title.set(event_target_value(&ev));
                        })
                    />
                </FormField>
            </Modal>
        </Show>
    }
}
```

### Table with Pagination

```rust
use vapora_leptos_ui::{Table, TableColumn, Pagination};

#[component]
fn DataTable() -> impl IntoView {
    let (current_page, set_current_page) = signal(1usize);
    let items_per_page = 10;

    let columns = vec![
        TableColumn::new("Name", "name").sortable(),
        TableColumn::new("Status", "status").sortable(),
        TableColumn::new("Date", "date"),
    ];

    // Paginate data
    let total_pages = data.len().div_ceil(items_per_page);
    let paginated_data = /* slice data for current page */;

    view! {
        <Table columns=columns rows=paginated_data />

        {move || if total_pages > 1 {
            view! {
                <Pagination
                    current_page=current_page.get()
                    total_pages=total_pages
                    on_page_change=Callback::new(move |page| {
                        set_current_page.set(page);
                    })
                />
            }
        } else {
            view! { <div /> }
        }}
    }
}
```

## Architecture

This library follows the **Rustelo pattern** for CSR/SSR agnostic components:

```
component/
├── mod.rs           # Module exports
├── unified.rs       # Public API (delegates to client/ssr)
├── client.rs        # WASM/interactive implementation
└── ssr.rs           # Server-side static implementation
```

Components automatically select the correct implementation:

- **WASM target (`wasm32-unknown-unknown`)**: Uses `client.rs` with full interactivity
- **Non-WASM target**: Uses `ssr.rs` for static server-side rendering

## Known Limitations

See [limitations.md](./limitations.md) for detailed list of known issues and missing features.

**Summary:**

- No i18n support yet
- Table sorting is client-side only (no server-side sorting)
- Toast auto-dismiss timing is fixed (3 seconds)
- Input is uncontrolled (no `value` prop)
- No Select, Textarea, Checkbox, Radio components yet
- No Dialog, ConfirmDialog components yet

## Development

```bash
# Build component library (WASM target)
cargo build -p vapora-leptos-ui --target wasm32-unknown-unknown

# Run clippy (strict mode)
cargo clippy -p vapora-leptos-ui --target wasm32-unknown-unknown -- -D warnings

# Format code
cargo fmt -p vapora-leptos-ui
```

## Contributing

This library is under active development. Contributions welcome:

1. Check [limitations.md](./limitations.md) for missing features
2. Follow existing component patterns (unified/client/ssr)
3. Ensure clippy passes with `-D warnings`
4. Add examples to [cookbook.md](./cookbook.md)

## License

Licensed under either of:

- Apache License, Version 2.0
- MIT License

at your option.

## Version

Current version: 1.2.0

Compatible with:

- Leptos 0.8.15
- Rust 1.75+
- UnoCSS 0.63+

**Changelog:**

- **1.2.0** (2026-02-08): Core components complete (Button, Input, Table, Modal, Pagination, FormField, Toast, Card, Badge, Spinner, SpaLink, Portal)
- **1.0.0** (2026-01-11): Initial release
