Jesús Pérez b6a4d77421
Some checks are pending
Documentation Lint & Validation / Markdown Linting (push) Waiting to run
Documentation Lint & Validation / Validate mdBook Configuration (push) Waiting to run
Documentation Lint & Validation / Content & Structure Validation (push) Waiting to run
Documentation Lint & Validation / Lint & Validation Summary (push) Blocked by required conditions
mdBook Build & Deploy / Build mdBook (push) Waiting to run
mdBook Build & Deploy / Documentation Quality Check (push) Blocked by required conditions
mdBook Build & Deploy / Deploy to GitHub Pages (push) Blocked by required conditions
mdBook Build & Deploy / Notification (push) Blocked by required conditions
Rust CI / Security Audit (push) Waiting to run
Rust CI / Check + Test + Lint (nightly) (push) Waiting to run
Rust CI / Check + Test + Lint (stable) (push) Waiting to run
feat: add Leptos UI library and modularize MCP server
2026-02-14 20:10:55 +00:00

8.2 KiB

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

[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

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

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 for comprehensive examples of each component.

Modal with Form

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

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 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

# 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 for missing features
  2. Follow existing component patterns (unified/client/ssr)
  3. Ensure clippy passes with -D warnings
  4. Add examples to 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