README gets a full Installation section with per-target setup (Babashka, shadow-cljs, Squint) plus CSS linking and updating. AGENTS.md gets a compact summary for agent context.
193 lines
5.5 KiB
Markdown
193 lines
5.5 KiB
Markdown
# clj-ui-framework
|
||
|
||
A cross-target component library for Clojure (Hiccup), ClojureScript (Replicant), and Squint (Eucalypt). Components are `.cljc` files that compile to all three targets using reader conditionals.
|
||
|
||
## Installation
|
||
|
||
Add as a git submodule to your project:
|
||
|
||
```sh
|
||
git submodule add https://gitea.florianschroedl.com/floscr/clj-ui-framework.git lib/ui
|
||
git submodule update --init
|
||
```
|
||
|
||
### Clojure / Babashka
|
||
|
||
Add the submodule's `src` directory to your classpath. In `bb.edn` or `deps.edn`:
|
||
|
||
```edn
|
||
;; bb.edn
|
||
{:paths ["src" "lib/ui/src"]}
|
||
|
||
;; deps.edn
|
||
{:paths ["src" "lib/ui/src"]}
|
||
```
|
||
|
||
Then require components directly:
|
||
|
||
```clojure
|
||
(ns my-app.core
|
||
(:require [ui.button :as button]
|
||
[ui.card :as card]
|
||
[ui.theme :as theme]))
|
||
|
||
(button/button {:variant :primary} "Click me")
|
||
```
|
||
|
||
### ClojureScript (Replicant / shadow-cljs)
|
||
|
||
Add the source path in `shadow-cljs.edn`:
|
||
|
||
```edn
|
||
{:source-paths ["src" "lib/ui/src"]
|
||
:builds {:app {:target :browser
|
||
:modules {:main {:init-fn my-app.core/init}}}}}
|
||
```
|
||
|
||
### Squint
|
||
|
||
Point squint at the submodule source in `squint.edn`:
|
||
|
||
```edn
|
||
{:paths ["src" "lib/ui/src"]}
|
||
```
|
||
|
||
### CSS
|
||
|
||
Copy or link the generated theme CSS into your project:
|
||
|
||
```sh
|
||
# Option A: copy (run after each theme update)
|
||
cp lib/ui/dist/theme.css public/theme.css
|
||
|
||
# Option B: symlink
|
||
ln -s ../../lib/ui/dist/theme.css public/theme.css
|
||
```
|
||
|
||
Then include it in your HTML:
|
||
|
||
```html
|
||
<link rel="stylesheet" href="/theme.css">
|
||
```
|
||
|
||
If you want to customize tokens, edit `lib/ui/src/theme/tokens.edn` and regenerate:
|
||
|
||
```sh
|
||
cd lib/ui && bb build-theme
|
||
```
|
||
|
||
### Updating
|
||
|
||
```sh
|
||
git submodule update --remote lib/ui
|
||
cd lib/ui && bb build-theme # regenerate CSS if tokens changed
|
||
```
|
||
|
||
## Development
|
||
|
||
Requires [Babashka](https://github.com/babashka/babashka).
|
||
|
||
```sh
|
||
bb build-theme # Generate dist/theme.css
|
||
bb test # Run tests
|
||
```
|
||
|
||
For dev servers (Hiccup on :3003, Replicant on :3001, Squint on :3002):
|
||
|
||
```sh
|
||
bb dev-all # Starts all three in a tmux session
|
||
```
|
||
|
||
Replicant and Squint need `npm install` in their dev directories first.
|
||
|
||
## Components
|
||
|
||
Accordion, Alert, Badge, Breadcrumb, Button, Card, Dialog, Form, Icon, Pagination, Progress, Sidebar, Skeleton, Spinner, Switch, Table, Tooltip.
|
||
|
||
Each component is a `.cljc` file in `src/ui/` with a matching `.css` file. The CSS is collected automatically during theme generation.
|
||
|
||
## Color System
|
||
|
||
Colors are generated from OKLCH parameters defined in `src/theme/tokens.edn`. OKLCH is a perceptually uniform color space — equal lightness steps produce equal perceived brightness across all hues, unlike HSL. You define a hue and chroma, and the generator produces an 11-stop scale (50–950) for each color, output as `oklch()` CSS values.
|
||
|
||
Five scales ship by default: `gray`, `accent`, `danger`, `success`, `warning`.
|
||
|
||
### How it works
|
||
|
||
Each scale is defined by a hue, a default chroma, and a list of lightness steps:
|
||
|
||
```edn
|
||
:gray {:hue 285 :chroma 0.025
|
||
:steps [[50 0.975 0.003] ;; [label lightness chroma]
|
||
[100 0.955 0.005]
|
||
[200 0.915 0.010]
|
||
...
|
||
[950 0.145 0.011]]}
|
||
```
|
||
|
||
This generates CSS variables in `:root`:
|
||
|
||
```css
|
||
--gray-50: oklch(0.975 0.003 285);
|
||
--gray-100: oklch(0.955 0.005 285);
|
||
--gray-200: oklch(0.915 0.010 285);
|
||
...
|
||
--gray-950: oklch(0.145 0.011 285);
|
||
```
|
||
|
||
Semantic tokens reference these scales. Light theme points at the light end, dark theme at the dark end:
|
||
|
||
```edn
|
||
;; Light
|
||
:bg-0 "var(--gray-50)"
|
||
:fg-0 "var(--gray-950)"
|
||
|
||
;; Dark
|
||
:bg-0 "var(--gray-950)"
|
||
:fg-0 "var(--gray-50)"
|
||
```
|
||
|
||
The scale variables are generated once and never change between themes. Only the semantic mapping shifts.
|
||
|
||
### Changing the palette
|
||
|
||
The gray hue controls the tint of all neutral surfaces, borders, and text. OKLCH hues differ from HSL — change it to shift the entire feel:
|
||
|
||
| Hue | Result |
|
||
|-----|--------|
|
||
| `285` | Purplish gray (default) |
|
||
| `255` | Blue-gray |
|
||
| `60` | Warm/sandy |
|
||
| any, chroma `0` | Pure neutral |
|
||
|
||
The accent hue controls buttons, focus rings, links:
|
||
|
||
| Hue | Result |
|
||
|-----|--------|
|
||
| `286` | Purple (default) |
|
||
| `255` | Blue |
|
||
| `25` | Red |
|
||
| `165` | Green |
|
||
|
||
After changing values, run `bb build-theme` to regenerate `dist/theme.css`.
|
||
|
||
### Per-step chroma
|
||
|
||
Steps can be `[label lightness]` to use the scale's default chroma, or `[label lightness chroma]` to override it. This is important for chromatic colors where high chroma looks wrong at the extremes — the accent scale peaks at chroma 0.255 in the mid-range and tapers to 0.020 for light tints and 0.130 for dark shades. The gray scale uses very low chroma (0.003–0.035) that peaks in the mid-range for a subtle tint.
|
||
|
||
### Current palette
|
||
|
||
The default ships with a purplish gray (hue 285) and a vivid purple accent (hue 286, `--accent-500: oklch(0.595 0.23 286)`), inspired by the [activity-tracker](https://github.com/user/piui) app. OKLCH ensures the lightness steps are perceptually even — a gray at L=0.5 looks equally bright regardless of hue, unlike HSL where different hues have wildly different perceived brightness.
|
||
|
||
## Theme Tokens
|
||
|
||
Beyond color scales, the theme includes:
|
||
|
||
- **Size scale** — `--size-1` (0.25rem) through `--size-16` (4rem), linear
|
||
- **Font scale** — `--font-xs` through `--font-3xl`, geometric (ratio 1.25)
|
||
- **Borders** — `--border-0/1/2`, referencing gray scale stops
|
||
- **Shadows** — `--shadow-0/1/2/3`, increasing elevation
|
||
- **Radii** — `--radius-sm` (6px), `--radius-md` (10px), `--radius-lg` (16px)
|
||
|
||
Light/dark mode switches automatically via `prefers-color-scheme`, or manually with `data-theme="dark"` on the root element.
|