Skip to content

ijadux2/nixi

Repository files navigation

Nixi

Lua HTMX License

Nixi is a high-performance Lua web framework that ships zero-byte logic to the client using HTMX. Built for production with native CSS DSL, pre-built UI components, and excellent developer experience.

Why Nixi?

Feature React Vue Next.js Nixi
Zero build step npm build
Pure Lua
HTMX-native
Web + Desktop windows or macOS
Native CSS DSL
CLI tool ⚠️ ⚠️ ⚠️

Features

  • Zero Client JavaScript: HTMX for reactive UIs without writing JS
  • Pure Lua CSS: Define styles in Lua with the CSS DSL
  • UI Component Library: Pre-built components (Button, Input, Card, Modal, Toast, etc.)
  • Theme Support: Tokyo Night, Dracula, Catppuccin, and custom themes
  • Type Safety: LuaLS annotations for IDE autocompletion
  • GTK Desktop: Same code, desktop GUI with GTK4 bindings
  • Production Ready: Security headers, static file serving, production server
  • Standalone: No external dependencies required (uses FFI when libraries unavailable)

Quick Start

Installation

# Option 1: Via Nix (recommended)
git clone https://github.com/ijadux2/nixi.git
cd nixi
nix develop  # Enter dev environment

# Option 2: Via Luarocks
luarocks install nixi

# Option 3: Manual
git clone https://github.com/ijadux2/nixi.git
cd nixi
./install.sh  # Install globally

Create Your First App

# Create new project
nixi new myapp
cd myapp

# Start development server
nixi dev

# Or run directly
lua server.lua

Visit http://127.0.0.1:3000

Usage

Basic App

---@meta
package.path = "src/nixi/?.lua;" .. package.path

local Nixi = require("init")
_G.Nixi = Nixi

local app = Nixi.new({
    host = "127.0.0.1",
    port = 3000,
})

app:get("/", function(ctx)
    return Nixi.html([[
        <html>
        <head><title>Hello</title></head>
        <body>
            <h1>Hello from Nixi!</h1>
        </body>
        </html>
    ]])
end)

return app

CSS DSL

local style = require("style")
Nixi.style = style

-- Define CSS variables
Nixi.style.variable("primary", "#7aa2f7")
Nixi.style.variable("bg", "#1a1b26")

-- Define rules
Nixi.style.rule("body", {
    backgroundColor = "var(--bg)",
    color = "#fff",
})

Nixi.style.rule(".btn", {
    padding = "10px 20px",
    borderRadius = "8px",
    backgroundColor = "var(--primary)",
})

-- Apply full theme config
Nixi.style.applyTheme({
    colors = {
        background = "#1a1b26",
        primary = "#7aa2f7",
    },
    fonts = {
        sans = "system-ui, sans-serif",
    },
})

-- Generate CSS
local css = Nixi.style.toCSS()

Generate Utilities with Lua For-Loops

-- Generate spacing utilities (margin: 0.25rem to 4rem)
for i = 1, 16 do
    Nixi.style.rule(".m-" .. i, {
        margin = (i * 0.25) .. "rem"
    })
    Nixi.style.rule(".p-" .. i, {
        padding = (i * 0.25) .. "rem"
    })
end

-- Generate flexbox utilities
for _, align in ipairs({"start", "center", "end", "stretch", "baseline"}) do
    Nixi.style.rule(".items-" .. align, {
        alignItems = align == "start" and "flex-start" or align == "end" and "flex-end" or align
    })
end

-- Generate color utilities
local colors = {
    { name = "primary", value = "#7aa2f7" },
    { name = "danger", value = "#f7768e" },
    { name = "success", value = "#9ece6a" },
}
for _, color in ipairs(colors) do
    Nixi.style.rule(".text-" .. color.name, { color = color.value })
    Nixi.style.rule(".bg-" .. color.name, { backgroundColor = color.value })
end

-- Generate responsive width utilities
for _, width in ipairs({25, 50, 75, 100}) do
    Nixi.style.rule(".w-" .. width, { width = width .. "%" })
end

This generates hundreds of utility classes from just a few lines of Lua code!

UI Components

local UI = require("nixi.ui")

-- Button with variants
UI.Button.render({ variant = "primary", children = "Click Me" })
UI.Button.render({ variant = "outline", children = "Cancel" })

-- Form inputs
UI.Input.render({ label = "Email", type = "email", placeholder = "you@example.com" })
UI.Select.render({ label = "Language", options = {{ value = "lua", label = "Lua" }} })

-- Cards
UI.Card.render({
    title = "Feature",
    children = "Some content",
    footer = UI.Button.render({ variant = "primary", children = "Learn More" })
})

-- Modals, Tabs, Toast notifications...

HTMX Integration

app:get("/api/counter", function(ctx)
    local count = (ctx.session.count or 0) + 1
    ctx.session.count = count
    return Nixi.html('<span id="count">' .. count .. '</span>')
end)
<button hx-get="/api/counter" hx-target="#count" hx-swap="innerHTML">
  Increment
</button>

HTML Components (Native Lua DSL)

-- Tables
Nixi.table({'Name', 'Age'}, {{'John', '25'}, {'Jane', '30'}})

-- From data (auto-generates headers)
local data = {
    {name = 'John', age = '25', city = 'NYC'},
    {name = 'Jane', age = '30', city = 'LA'},
}
Nixi.tableFromData(data)  -- Auto-generates headers from keys

-- Images
Nixi.img('photo.jpg', 'A photo')
Nixi.figure('photo.jpg', 'Caption text')

-- Gallery
Nixi.gallery({
    {src = 'img1.jpg', alt = 'Image 1', title = 'First'},
    {src = 'img2.jpg', alt = 'Image 2', title = 'Second'},
})

-- Navigation
Nixi.nav({
    {href = '/', text = 'Home', active = true},
    {href = '/about', text = 'About'},
})

-- Forms
Nixi.form('/submit', 'post', 
    Nixi.label('email', 'Email:') ..
    Nixi.input({type = 'email', name = 'email'}) ..
    Nixi.select('country', {
        {value = 'us', label = 'USA'},
        {value = 'uk', label = 'UK'},
    })
)

Static Site Generation (SSG)

-- nixi.lua config
return {
    name = "My Site",
    theme = { name = "tokyoNight" },
    build = {
        output = "dist",
        skipRoutes = {"/api/*"},
    },
}
# Build static site
nixi build
# Output goes to dist/

CLI Commands

nixi new <name>       # Create new project
nixi dev [port]       # Start development server
nixi build [out]     # Build static site (default: dist/)
nixi build -c        # Clean build
nixi style [file]    # Compile CSS to file
nixi generate c <n>  # Generate component
nixi generate r <p>  # Generate route
nixi generate m <n>  # Generate middleware
nixi doctor           # Check system requirements
nixi add <package>   # Install luarocks package
nixi init             # Initialize in current folder
nixi clean            # Clean build artifacts
nixi gtk              # Run GTK desktop app

Project Structure

myapp/
├── src/
│   ├── nixi/              # Framework (symlinked)
│   │   ├── init.lua       # Core router
│   │   ├── style.lua      # CSS DSL
│   │   ├── htmx.lua       # HTMX bindings
│   │   ├── ui/            # UI components
│   │   │   ├── button.lua
│   │   │   ├── input.lua
│   │   │   ├── card.lua
│   │   │   └── ...
│   │   └── gtk.lua        # Desktop bindings
│   └── app.lua            # Your application
├── routes/                # File-based routes
├── layouts/              # Layout templates
├── public/               # Static files
├── server.lua            # Development server
└── prod-server.lua      # Production server

UI Components

Component Description
Button Primary, Secondary, Outline, Ghost, Danger variants
Input Text, Email, Password with labels and validation
Select Dropdown with placeholder support
Checkbox Styled checkboxes with labels
Radio Radio button groups
Card Default, Bordered, Elevated with hover effects
Modal Dialog with header, body, footer
Toast Success, Error, Warning, Info notifications
Loader Spinner, Dots, Bars, Pulse animations
ProgressBar Progress indicators with variants
Tabs Default, Pills, Underline variants
Badge Status indicators with variants
Tag Removable tags

Themes

local theme = require("nixi.ui.theme")

-- Use predefined theme
local colors = theme.getTheme("tokyoNight").colors
theme.applyTheme(colors)

-- Inject all component styles
theme.injectAllStyles(colors)

Available themes:

  • Tokyo Night - Dark blue theme
  • Dracula - Purple accent theme
  • GitHub Dark - GitHub's dark mode
  • Catppuccin Mocha - Soft pastel theme

Environment Variables

Variable Default Description
NIXI_HOST 127.0.0.1 Server bind address
NIXI_PORT 3000 Server port
NIXI_ENV development Environment mode

Documentation

Requirements

  • Lua 5.1+ or LuaJIT

Optional Dependencies

Nixi works standalone using LuaJIT FFI, but these improve functionality:

# Optional - for better compatibility
luarocks install luasocket luafilesystem

Without these, Nixi uses native FFI calls for:

  • File operations: Directory scanning, file attributes, mkdir
  • HTTP server: TCP sockets, binding, accepting connections

License

MIT License - see LICENSE for details.

Copyright (c) 2024 ijadux2


Made with ❤️ by ijadux2

About

web framework built in lua

Topics

Resources

License

Stars

Watchers

Forks

Contributors