Tailwind classes in OCaml

Update README to showcase GADT-based Tailwind_html interface

- Rewrite README to focus on the new GADT heterogeneous list interface
- Add comprehensive examples from layout_and_spacing_03.ml and other demos
- Showcase CSS Grid support, built-in components, and type safety benefits
- Include detailed API reference for all GADT property categories
- Update installation and getting started sections for the new interface
- Remove outdated verbose Tailwind syntax examples in favor of succinct GADT syntax

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

+276 -148
+276 -148
README.md
··· 1 1 # Tailwind OCaml 2 2 3 - An OCaml library for generating Tailwind CSS classes with compile-time 4 - validation and a companion HTML generation library using Htmlit. 3 + Type-safe Tailwind CSS generation for OCaml with a revolutionary GADT-based interface for succinct, compile-time validated styling. 5 4 6 5 This project provides two main libraries: 7 6 8 7 - **`tailwind`**: Core library for type-safe Tailwind CSS class generation 9 - - **`tailwind-html`**: HTML component library built on top of [Htmlit](https://github.com/dbuenzli/htmlit) 8 + - **`tailwind-html`**: High-level HTML component library with GADT-based heterogeneous list interface built on [Htmlit](https://github.com/dbuenzli/htmlit) 10 9 11 10 ## Features 12 11 13 - - Compile-time validation of Tailwind classes 14 - - Type-safe color variants and sizes 15 - - Exhaustive pattern matching for all utility classes 12 + - **GADT-based Interface**: Succinct heterogeneous list syntax with compile-time type safety 13 + - **Zero Runtime Cost**: All CSS generation happens at compile time 14 + - **Comprehensive Grid Support**: Full CSS Grid integration with type-safe properties 15 + - **Type-Safe Colors & Spacing**: Exhaustive variants with compile-time validation 16 + - **Built-in Components**: Pre-styled buttons, cards, and layout helpers 16 17 17 - ### Comprehensive Coverage 18 - - **Typography**: Font sizes, weights, line heights, text alignment, decorations 19 - - **Layout**: Display, position, flexbox, grid, spacing 20 - - **Colors**: Full color palette with variants 18 + ### Complete Tailwind Coverage 19 + - **Typography**: Font sizes, weights, text alignment with type-safe variants 20 + - **Layout**: CSS Grid, Flexbox, spacing with compile-time validation 21 + - **Colors**: Full palette (gray, blue, red, green, etc.) with variant checking 21 22 - **Effects**: Shadows, borders, rounded corners, transitions 22 - - **Responsive**: Breakpoint-based responsive utilities 23 - - **Variants**: Hover, focus, and other state variants 23 + - **Components**: Pre-built buttons, cards, and layout helpers 24 + - **Type Safety**: GADT-based heterogeneous lists prevent invalid combinations 24 25 25 - ### Using Dune 26 + ## Quick Start 26 27 27 - Add to your `dune-project`: 28 - 29 - ```dune 30 - (package 31 - (name myproject) 32 - (depends 33 - ocaml 34 - dune 35 - tailwind 36 - tailwind-html 37 - htmlit)) 38 - ``` 39 - 40 - ## Quick Start 28 + ### GADT Interface (Recommended) 41 29 42 - ### Basic Usage 30 + The new GADT-based interface provides succinct, type-safe styling with heterogeneous lists: 43 31 44 32 ```ocaml 45 - open Tailwind 33 + open Htmlit 34 + open Tailwind_html 46 35 47 - (* Create a styled div *) 48 - let styled_div = 49 - let classes = tw [ 50 - Display.flex; 51 - Flexbox.(to_class (justify `Center)); 52 - Flexbox.(to_class (align_items `Center)); 53 - Color.bg (Color.make `Gray ~variant:`V100 ()); 54 - Spacing.(to_class (p (Size.rem 2.0))); 55 - ] in 56 - Printf.sprintf "<div class=\"%s\">Content</div>" (to_string classes) 36 + (* Create a centered card with CSS Grid *) 37 + let create_hero_section () = 38 + div ~styles:[ 39 + grid; 40 + grid_cols 1; 41 + gap (rem 2.0); 42 + padding (rem 3.0); 43 + text_center; 44 + ] [ 45 + h1 ~styles:[ 46 + font_size `Xl3; 47 + font_weight `Bold; 48 + text_color (blue 600); 49 + margin_bottom (rem 1.5); 50 + ] [txt "Welcome to Tailwind OCaml"]; 51 + 52 + p ~styles:[ 53 + font_size `Lg; 54 + text_color (gray 600); 55 + margin_bottom (rem 2.0); 56 + ] [txt "Type-safe CSS with compile-time guarantees"]; 57 + 58 + (* Built-in button components *) 59 + btn_primary ~size:`Lg [txt "Get Started"]; 60 + ] 57 61 ``` 58 62 59 - ### With Htmlit Integration 63 + ### CSS Grid Layouts 60 64 61 65 ```ocaml 62 - open Htmlit 63 - open Tailwind 66 + (* Three-column responsive grid *) 67 + div ~styles:[ 68 + grid; 69 + grid_cols 3; 70 + gap (rem 1.5); 71 + ] [ 72 + card [h3 [txt "Feature 1"]; p [txt "Description"]]; 73 + card [h3 [txt "Feature 2"]; p [txt "Description"]]; 74 + card [h3 [txt "Feature 3"]; p [txt "Description"]]; 75 + ] 76 + ``` 64 77 65 - let classes_attr tailwind_classes = 66 - At.class' (Tailwind.to_string tailwind_classes) 78 + ### Built-in Components 67 79 68 - let create_card title content = 69 - El.div ~at:[classes_attr (tw [ 70 - Patterns.card; 71 - Spacing.(to_class (p (Size.rem 1.5))); 72 - Effects.shadow_md; 73 - ])] [ 74 - El.h2 ~at:[classes_attr (tw [ 75 - Typography.(to_class (font_size `Xl)); 76 - Typography.(to_class (font_weight `Bold)); 77 - Spacing.(to_class (mb (Size.rem 1.0))); 78 - ])] [El.txt title]; 79 - El.p [El.txt content]; 80 - ] 80 + ```ocaml 81 + (* Pre-styled components with size variants *) 82 + btn_primary ~size:`Lg [txt "Primary Action"]; 83 + btn_secondary [txt "Secondary Action"]; 84 + btn_outline ~size:`Sm [txt "Outline Button"]; 85 + 86 + (* Layout helpers *) 87 + container [ 88 + card [ 89 + h2 ~styles:[font_size `Xl; margin_bottom (rem 1.0)] [txt "Card Title"]; 90 + p ~styles:[text_color (gray 600)] [txt "Card content with automatic styling"]; 91 + ]; 92 + ] 81 93 ``` 82 94 83 95 ## Examples 84 96 85 - The `examples/` directory contains several demonstration files: 97 + The `examples/` directory showcases the GADT interface across various use cases: 86 98 87 - ### Running Examples 99 + ### Available Examples 88 100 89 101 ```bash 90 102 # Build all examples 91 103 dune build examples/ 92 104 93 - # Run comprehensive showcase (generates HTML + CSS) 94 - dune exec examples/comprehensive_showcase.exe 105 + # Hello World with GADT interface 106 + dune exec examples/hello_tailwind_01.exe > hello.html 107 + 108 + # Colors and Typography showcase 109 + dune exec examples/colors_and_typography_02.exe > colors.html 110 + 111 + # CSS Grid and Layout demonstrations 112 + dune exec examples/layout_and_spacing_03.exe > layout.html 95 113 96 - # Run basic usage example 97 - dune exec examples/basic_usage.exe 114 + # Responsive design patterns 115 + dune exec examples/responsive_design_04.exe > responsive.html 98 116 99 - # Run HTML integration example 100 - dune exec examples/tailwind_html_example.exe 117 + # Visual effects and styling 118 + dune exec examples/effects_and_variants_05.exe > effects.html 119 + 120 + # Component patterns and reusable elements 121 + dune exec examples/patterns_and_components_06.exe > patterns.html 122 + 123 + # Complete application showcase 124 + dune exec examples/comprehensive_showcase_07.exe > showcase.html 125 + 126 + # Button component demonstration 127 + dune exec examples/button_demo.exe > buttons.html 128 + 129 + # Generate index page linking all examples 130 + dune exec examples/index_html_generator.exe > index.html 101 131 ``` 102 132 103 - ### Comprehensive Showcase 133 + ### Example Highlights 134 + 135 + **CSS Grid Layout (`layout_and_spacing_03.ml`)**: 136 + ```ocaml 137 + (* Three-column grid with gap variations *) 138 + div ~styles:[ 139 + grid; 140 + grid_cols 3; 141 + gap (rem 1.0); 142 + ] [ 143 + div ~styles:[bg_color (blue 100); padding (rem 1.0)] [txt "Item 1"]; 144 + div ~styles:[bg_color (green 100); padding (rem 1.0)] [txt "Item 2"]; 145 + div ~styles:[bg_color (purple 100); padding (rem 1.0)] [txt "Item 3"]; 146 + ] 104 147 105 - The comprehensive showcase demonstrates all library features and generates: 106 - - `showcase.html` - Complete HTML page with all Tailwind classes 107 - - `input.css` - Tailwind v4 CSS with custom theme extensions 148 + (* Asymmetric grid gaps *) 149 + div ~styles:[ 150 + grid; 151 + grid_cols 2; 152 + gap_x (rem 2.0); 153 + gap_y (rem 0.5); 154 + ] (List.init 4 (fun i -> 155 + div ~styles:[bg_color (purple 200); text_center] [ 156 + txt (Printf.sprintf "Box %d" (i + 1)) 157 + ] 158 + )) 159 + ``` 108 160 109 - ```bash 110 - dune exec examples/comprehensive_showcase.exe 111 - # Then open showcase.html in your browser 161 + **Built-in Components (`button_demo.ml`)**: 162 + ```ocaml 163 + (* Size variants with consistent styling *) 164 + div ~styles:[flex; flex_col; gap (rem 1.0)] [ 165 + btn_primary ~size:`Sm [txt "Small Primary"]; 166 + btn_primary [txt "Default Primary"]; 167 + btn_primary ~size:`Lg [txt "Large Primary"]; 168 + btn_secondary [txt "Secondary Button"]; 169 + btn_outline [txt "Outline Button"]; 170 + ] 171 + ``` 172 + 173 + **Responsive Cards (`comprehensive_showcase_07.ml`)**: 174 + ```ocaml 175 + section ~styles:[margin_bottom (rem 4.0)] [ 176 + h3 ~styles:[font_size `Xl2; text_center; margin_bottom (rem 3.0)] [ 177 + txt "Features" 178 + ]; 179 + 180 + div ~styles:[grid; grid_cols 1; gap (rem 2.0)] [ 181 + card [ 182 + h4 ~styles:[font_size `Xl; font_weight `Semibold; text_color (blue 600)] [ 183 + txt "🎯 Type Safety" 184 + ]; 185 + p ~styles:[text_color (gray 600)] [ 186 + txt "Catch styling errors at compile time with GADT-based type checking." 187 + ]; 188 + ]; 189 + card [ 190 + h4 ~styles:[font_size `Xl; font_weight `Semibold; text_color (green 600)] [ 191 + txt "⚡ Performance" 192 + ]; 193 + p ~styles:[text_color (gray 600)] [ 194 + txt "Zero runtime overhead with compile-time CSS generation." 195 + ]; 196 + ]; 197 + ]; 198 + ] 112 199 ``` 113 200 114 201 ## Tailwind v4 Support ··· 131 218 npx tailwindcss@next -i input.css -o output.css 132 219 ``` 133 220 134 - ## Module Documentation 221 + ## API Reference 135 222 136 - ### Core Modules 223 + ### `Tailwind_html` (GADT Interface) 137 224 138 - #### `Tailwind` 139 - Main module that exports all utilities and provides the `tw` function for composing classes. 225 + The high-level GADT interface provides succinct, type-safe styling with heterogeneous lists: 140 226 141 - #### `Color` 142 - Type-safe color system with variants: 227 + #### Layout Properties 143 228 ```ocaml 144 - Color.bg (Color.make `Blue ~variant:`V600 ()) 145 - Color.text Color.white 146 - Color.border (Color.make `Gray ~variant:`V200 ()) 229 + ~styles:[ 230 + (* Display *) 231 + grid | flex | block | inline | hidden; 232 + 233 + (* Grid System *) 234 + grid_cols 3 | grid_rows 2; 235 + gap (rem 1.0) | gap_x (rem 1.5) | gap_y (rem 0.5); 236 + 237 + (* Flexbox *) 238 + flex_col | flex_row; 239 + justify_center | justify_between | justify_end; 240 + items_center | items_start | items_end; 241 + 242 + (* Sizing *) 243 + width full | height screen; 244 + min_height screen | max_width (rem 64.0); 245 + ] 147 246 ``` 148 247 149 - #### `Typography` 150 - Font utilities: 248 + #### Typography Properties 151 249 ```ocaml 152 - Typography.(to_class (font_size `Xl2)) 153 - Typography.(to_class (font_weight `Bold)) 154 - Typography.(to_class (line_height `Relaxed)) 250 + ~styles:[ 251 + (* Font Sizes *) 252 + font_size `Xs | font_size `Sm | font_size `Base | font_size `Lg; 253 + font_size `Xl | font_size `Xl2 | font_size `Xl3; 254 + 255 + (* Font Weights *) 256 + font_weight `Light | font_weight `Normal | font_weight `Medium; 257 + font_weight `Semibold | font_weight `Bold; 258 + 259 + (* Text Styling *) 260 + text_center | text_left | text_right; 261 + text_color (blue 600) | text_color (gray 500); 262 + ] 155 263 ``` 156 264 157 - #### `Spacing` 158 - Margin and padding utilities: 265 + #### Color System 159 266 ```ocaml 160 - Spacing.(to_class (p (Size.rem 1.0))) (* padding *) 161 - Spacing.(to_class (mx Size.auto)) (* margin-x auto *) 162 - Spacing.(to_class (gap `All (Size.px 16.0))) (* gap *) 267 + ~styles:[ 268 + (* Background Colors *) 269 + bg_color (blue 50) | bg_color (gray 100) | bg_color (red 500); 270 + bg_color (Tailwind.Color.white) | bg_color (green 600); 271 + 272 + (* Text Colors *) 273 + text_color (gray 800) | text_color (blue 600) | text_color (red 500); 274 + 275 + (* Border Colors *) 276 + border_color (gray 200) | border_color (blue 300); 277 + ] 163 278 ``` 164 279 165 - #### `Layout` 166 - Layout utilities: 280 + #### Spacing Properties 167 281 ```ocaml 168 - Layout.(to_class (width (Size.percent 100.0))) 169 - Layout.(to_class (height Size.screen)) 170 - Layout.(to_class (max_width (Size.rem 64.0))) 282 + ~styles:[ 283 + (* Padding *) 284 + padding (rem 1.0) | padding_x (rem 1.5) | padding_y (rem 2.0); 285 + 286 + (* Margin *) 287 + margin (rem 1.0) | margin_x auto | margin_bottom (rem 2.0); 288 + margin_top (rem 1.5) | margin_left (rem 0.5); 289 + ] 171 290 ``` 172 291 173 - #### `Flexbox` 174 - Flexbox utilities: 292 + #### Visual Effects 175 293 ```ocaml 176 - Display.flex 177 - Flexbox.(to_class (justify `Between)) 178 - Flexbox.(to_class (align_items `Center)) 179 - Flexbox.(to_class (direction `Col)) 294 + ~styles:[ 295 + (* Shadows *) 296 + shadow `Sm | shadow `Md | shadow `Lg | shadow `Xl; 297 + 298 + (* Borders *) 299 + border | rounded `Sm | rounded `Md | rounded `Lg | rounded `Full; 300 + 301 + (* Transitions *) 302 + transition; 303 + ] 180 304 ``` 181 305 182 - #### `Grid` 183 - CSS Grid utilities: 306 + #### Built-in Components 184 307 ```ocaml 185 - Display.grid 186 - Grid.(to_class (template_cols (`Cols 3))) 187 - Grid.(to_class (gap (Size.rem 1.0))) 188 - ``` 308 + (* Button Components *) 309 + btn_primary ~size:`Lg [txt "Primary Button"]; 310 + btn_secondary ~size:`Sm [txt "Secondary Button"]; 311 + btn_outline [txt "Outline Button"]; 312 + 313 + (* Layout Components *) 314 + container [content]; (* Max-width container with auto margins *) 315 + card [content]; (* Pre-styled card with padding and shadow *) 189 316 190 - #### `Effects` 191 - Visual effects: 192 - ```ocaml 193 - Effects.shadow_lg 194 - Effects.rounded_md 195 - Effects.border 196 - Effects.transition `All 317 + (* HTML Elements with Styling *) 318 + h1 ~styles:[font_size `Xl3; font_weight `Bold] [txt "Heading"]; 319 + p ~styles:[text_color (gray 600); margin_bottom (rem 1.0)] [txt "Paragraph"]; 320 + div ~styles:[grid; grid_cols 2; gap (rem 1.0)] [content]; 321 + section ~styles:[margin_bottom (rem 2.0)] [content]; 197 322 ``` 198 323 199 - #### `Responsive` 200 - Responsive utilities: 201 - ```ocaml 202 - Responsive.(to_class (at_breakpoint `Md Display.flex)) 203 - Responsive.(to_class (at_breakpoint `Lg (Grid.(to_class (template_cols (`Cols 4)))))) 204 - ``` 324 + ### Low-Level `Tailwind` Module 205 325 206 - #### `Variants` 207 - State variants: 208 - ```ocaml 209 - Variants.hover (Color.bg (Color.make `Blue ~variant:`V700 ())) 210 - Variants.focus Effects.ring 211 - ``` 326 + For advanced use cases, the core `Tailwind` module provides detailed control: 212 327 213 - #### `Patterns` 214 - Common layout patterns: 215 328 ```ocaml 216 - Patterns.container () 217 - Patterns.card 218 - Patterns.flex_center 219 - Patterns.stack ~gap:(Size.rem 1.0) () 220 - Patterns.sticky_header 329 + open Tailwind 330 + 331 + let classes = Css.tw [ 332 + Display.grid; 333 + Grid.(to_class (template_cols (`Cols 3))); 334 + Spacing.(to_class (gap `All (Size.rem 1.0))); 335 + Color.bg (Color.make `Blue ~variant:`V50 ()); 336 + ] 337 + 338 + let html_class = to_string classes (* "grid grid-cols-3 gap-4 bg-blue-50" *) 221 339 ``` 222 340 223 - ### HTML Components (`tailwind-html`) 341 + ### Getting Started 224 342 225 - Pre-built components using Htmlit: 343 + Add to your `dune-project`: 344 + ```dune 345 + (package 346 + (name myproject) 347 + (depends 348 + ocaml 349 + dune 350 + tailwind 351 + tailwind-html 352 + htmlit)) 353 + ``` 226 354 355 + Then in your OCaml code: 227 356 ```ocaml 357 + open Htmlit 228 358 open Tailwind_html 229 359 230 - (* Button component *) 231 - Button.primary ~text:"Click me" ~onclick:"handleClick()" 232 - 233 - (* Card component *) 234 - Card.simple ~title:"Card Title" ~content:"Card content here" 235 - 236 - (* Layout components *) 237 - Layout.container [ 238 - Layout.row [ 239 - Layout.col ~span:6 [content]; 240 - Layout.col ~span:6 [content]; 241 - ] 360 + let my_page = El.html [ 361 + El.head [El.title [txt "My App"]]; 362 + El.body ~at:[classes_attr [min_height screen; bg_color (gray 50)]] [ 363 + container [ 364 + h1 ~styles:[font_size `Xl3; text_center; margin_bottom (rem 2.0)] [ 365 + txt "Welcome to Type-Safe CSS!" 366 + ]; 367 + btn_primary [txt "Get Started"]; 368 + ]; 369 + ]; 242 370 ] 243 371 ``` 244 372