website-htmx-rustelo-code/README.md
2026-07-10 03:44:13 +01:00

12 KiB
Raw Permalink Blame History

Website Implementation - Rustelo Framework

A complete content website with code highlighting built using the Rustelo framework, demonstrating modern multi-crate architecture and PAP compliance.

🎯 Project Overview

This implementation validates Rustelo's project generation capabilities and serves as a reference for content websites that need code display features.

Key Features

  • Multi-crate architecture: Client, server, shared, pages with build.rs integration
  • Type-safe configuration: Nickel (NCL) for routes, themes, menus with compile-time validation
  • Bilingual single-source: Zero duplication - EN/ES in one file
  • Code highlighting: Complete syntax highlighting with copy functionality
  • Language-agnostic: Supports any language without code changes
  • Smart caching: Multi-layer cache system for incremental builds
  • PAP compliant: Follows Rustelo's Project Architecture Principles

🚀 Quick Start

Prerequisites

  • Rust 1.75+ - Core language and toolchain
  • Node.js 18+ - Frontend tooling
  • Nickel (Configuration language) - REQUIRED for type-safe configuration
  • Site content in ../site/ directory

Note

: This project uses Nickel (NCL) for all configuration files (routes, themes, menus, content types). See NCL Configuration section below.

Setup & Development

# Install dependencies
just setup

# Start development server with hot reload
just dev

# Build for production
just build-prod

Development Commands

# Development
just dev              # Hot reload with CSS watching
just dev-server       # Rust only (no CSS watching)
just dev-css          # CSS watching only

# Building
just build            # Development build
just build-prod       # Production build
just build-rust       # Rust components only
just build-css        # CSS only

# Quality & Testing
just quality          # All quality checks
just test             # Run tests
just format           # Format code
just lint             # Lint code

# Content & Deployment
just validate-content # Validate site content
just deploy-staging   # Deploy to staging
just status           # Project status

🏗️ Architecture

Multi-Crate Structure

website-impl/
├── crates/
│   ├── shared/         # Route generation & shared types
│   ├── pages/          # Custom page component generation
│   ├── client/         # WASM frontend with asset processing
│   ├── server/         # Axum backend with configuration
│   └── plugin-example-theme/   # Example plugin (theme + i18n)
├── config.toml         # Application configuration
├── uno.config.ts       # UnoCSS configuration (synced with @website)
├── package.json        # Code highlighting & build tools
├── justfile           # Development automation
└── scripts/           # Build scripts for themes & highlighting

🔌 Plugin System

This implementation demonstrates Rustelo's Level 5 Plugin Architecture - a trait-based plugin system for unlimited extensibility without framework coupling.

Included Plugins

  • WebsiteResourceContributor (core): Provides themes, menus, and i18n
  • plugin-example-theme (example): Complete working theme plugin with tests

Plugin Features

  • ResourceContributor Trait: Contribute themes, menus, translations
  • Type-Safe Registration: Compile-time validation
  • Zero Conditional Compilation: Framework code is pure Rust
  • Configuration-Driven: Resources from TOML/FTL files
  • Self-Contained: Plugins are independent crates

Creating Custom Plugins

Step 1: Create plugin crate

cd crates/
cargo new --lib my-custom-plugin

Step 2: Implement ResourceContributor

use rustelo_core_lib::registration::ResourceContributor;

pub struct MyPlugin;

impl ResourceContributor for MyPlugin {
    fn contribute_themes(&self) -> HashMap<String, String> {
        let mut themes = HashMap::new();
        themes.insert("my-theme".to_string(),
            include_str!("../config/themes/my-theme.toml").to_string());
        themes
    }

    fn name(&self) -> &str {
        "my-plugin"
    }
}

Step 3: Add to workspace

  • Add to main Cargo.toml workspace members
  • Create configuration files in config/themes/ and config/i18n/

Step 4: Register at startup

// In crates/server/src/resources.rs
rustelo_core_lib::register_contributor(&MyPlugin)?;

Plugin Types

Type Purpose Example
Resource-Only Themes, menus, translations Custom theme plugin
Page Provider Custom page components Analytics dashboard
Composite Resources + pages Feature module

Example Plugin Walkthrough

See crates/plugin-example-theme/ for a complete, production-ready example:

  • Analytics dashboard theme configuration
  • English and Spanish translations
  • 10/10 passing unit tests
  • Comprehensive documentation

Plugin Documentation

🎨 Code Highlighting Features

Syntax Highlighting

  • highlight.js: Multi-language syntax highlighting
  • highlightjs-copy: One-click code copying
  • Theme system: Light/dark mode with custom themes
  • UnoCSS integration: Built-in code styling with design system

Design System Integration

Uses complete design system from @website:

  • ds-* prefixed utility classes
  • Theme variables for consistent styling
  • Built-in dark mode support
  • Code block styling with proper contrast

📝 NCL Configuration

This project uses Nickel (NCL) for type-safe, DRY configuration. All configuration files use .ncl format with TOML fallback support.

Why NCL?

Type Safety: Compile-time validation catches errors before runtime Zero Duplication: Bilingual configs in single file (no separate en.toml/es.toml) DRY Principles: Shared defaults and helper functions Better Tooling: Syntax highlighting, LSP support, validation

Configuration Files

site/
├── schemas/              # Reusable NCL type definitions
│   ├── content/
│   │   ├── contracts.ncl    # Type contracts for content
│   │   └── defaults.ncl     # Shared defaults + helpers
│   ├── menus/
│   │   ├── contracts.ncl
│   │   └── defaults.ncl
│   ├── footer/
│   │   ├── contracts.ncl
│   │   └── defaults.ncl
│   └── themes/
│       ├── contracts.ncl
│       └── defaults.ncl
├── config/
│   └── themes/
│       ├── default.ncl      # Default theme
│       └── dark.ncl         # Dark theme variant
├── content/
│   └── content-kinds.ncl    # Content type definitions
└── ui/
    ├── menus/
    │   └── menu.ncl         # Navigation menu (bilingual)
    └── footer/
        └── footer.ncl       # Footer config (bilingual)

Example: Bilingual Menu (Before vs After)

Before (TOML - 130 lines across 2 files):

# en.toml
[[items]]
route = "/services"
label = "Services"

# es.toml
[[items]]
route = "/servicios"
label = "Servicios"

After (NCL - 115 lines, single file):

{
  items = [
    make_menu_item {
      routes = { en = "/services", es = "/servicios" },
      labels = { en = "Services", es = "Servicios" },
    },
  ]
}

Working with NCL Configs

Export to JSON:

nickel export --format json site/ui/menus/menu.ncl | jq '.'

Validate:

nickel typecheck site/ui/menus/menu.ncl

Auto-Detection: Build system automatically prefers .ncl files over .toml:

site/config/themes/dark.ncl  ✅ Used
site/config/themes/dark.toml ⏭️  Ignored (fallback)

Documentation

Metrics

Config Type Lines Duplication Reduced
Content-Kinds 29 ~60% less
Menus 115 100% (bilingual)
Footers 63 29% smaller
Themes 4 × 14 Variants from base

Total: ~140 lines of config + ~920 lines of reusable schemas


🔧 Configuration

Site Integration

# Links to site content structure
[content]
root_path = "../site"                    # Site content directory
public_path = "../site/public"           # Static assets
content_url = "/content"                  # Content API URL
types = ["blog", "recipes"]              # Available content types
languages = ["en", "es"]                 # Supported languages
default_language = "en"                  # Default language

🧪 PAP Compliance

Configuration-driven: All routes, themes, menus from NCL files with type-safety Language-agnostic: No hardcoded languages, bilingual single-source configs Custom routing: Uses Rustelo routing, NOT Leptos router Error handling: Proper Result<T, E> patterns, no unwrap() Modular design: Feature-based architecture with plugin system Type-safe configuration: Nickel contracts validate at compile-time No hardcoding: All paths and routes configurable Self-describing: Architecture tracked via on+re protocol — .ontology/ + adrs/

🔍 Architecture Self-Description (on+re)

This project implements the Ontoref on+re protocol. The .ontology/ and adrs/ directories provide a machine- and agent-readable description of the project's architecture, current state, and invariants as a Rustelo consumer (Service kind).

.ontology/ files

File Contents
core.ncl Knowledge graph: axioms (rustelo-consumer, bilingual-content), tensions (hydration complexity, build-time vs runtime), project nodes
state.ncl State dimensions: deployment-readiness (pre-production), hydration-stability (zero-mismatch), auth-system (operational), css-pipeline (correct)
gate.ncl Membranes: hydration-parity (Low permeability), content-integrity (Medium), rbac-correctness (Low)
manifest.ncl Service manifest: EndUser, Developer, Agent consumption modes; implementation, content, self-description layers

ADR System (adrs/)

ADR Decision
adr-001 NCL (Nickel) over TOML for site configuration
adr-002 SsrTranslator in both SSR and WASM targets for hydration parity — 4 hard constraints
adr-003 WebSocket broadcast for RBAC hot-reload without server restart

Browsing the architecture

# What this project is and how it can be consumed
nickel export .ontology/manifest.ncl

# Current state across all tracked dimensions
nickel export .ontology/state.ncl

# Active architecture constraints and gates
nickel export .ontology/gate.ncl

# Cross-project: browse Rustelo framework capabilities
# (rustelo-browse operational mode in manifest.ncl)
nickel export ../../rustelo/.ontology/core.ncl

📖 Documentation

  • Setup Guide: info/setup_from_rustelo_plan.md - Complete implementation journey
  • Enhancements: info/enhancements/ - Proposed improvements for Rustelo

📄 License

MIT License - Part of the Rustelo framework ecosystem.