Tailwind classes in OCaml

Extend GADT interface with CSS Grid support and port all examples

- Add Grid support to GADT interface: Display_grid, Grid_cols, Grid_rows, Gap, Gap_x, Gap_y
- Convert all examples from verbose Tailwind syntax to succinct GADT heterogeneous lists
- Remove obsolete gadt_demo.ml and type_safety_test.ml examples
- Update index generator to showcase Grid functionality across all examples
- Ensure comprehensive Grid usage in layout, spacing, and component demos

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

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

+71 -98
examples/button_demo.ml
···
-
(* Button Demo - Showcasing new button combinators *)
+
(* Button Demo - Showcasing GADT-based button interface *)
open Htmlit
open Tailwind_html
···
El.title [txt "Button Demo"];
El.link ~at:[At.rel "stylesheet"; At.href "button_demo.css"] ();
];
-
El.body ~at:[classes_attr (Tailwind.Css.tw [
-
Tailwind.Layout.(to_class (min_height screen));
-
Tailwind.Color.bg (gray 50);
-
Tailwind.Spacing.(to_class (p (rem 2.0)));
-
])] [
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
container [
-
h1 ~size:`Xl3 ~weight:`Bold ~color:(gray 800) ~align:`Center ~mb:(rem 2.0) [
-
txt "Button Combinator Demo"
-
];
+
h1 ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Button Component Demo"];
-
p_styled ~size:`Lg ~color:(gray 600) ~align:`Center ~mb:(rem 3.0) [
-
txt "Showcasing succinct button creation with the new Tailwind_html API"
-
];
+
p ~styles:[
+
font_size `Lg;
+
text_color (gray 600);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Showcase of built-in button components using GADT interface"];
-
(* Button examples section *)
-
div ~classes:(Tailwind.Css.tw [
-
Tailwind.Spacing.(to_class (gap `All (rem 2.0)));
-
flex;
-
Tailwind.Flexbox.(to_class (direction `Col));
-
]) [
-
(* Primary buttons *)
-
card [
-
h2 ~size:`Xl ~weight:`Semibold ~color:(gray 700) ~mb:(rem 1.5) [
-
txt "Primary Buttons"
-
];
-
div ~classes:(Tailwind.Css.tw [
-
flex;
-
Tailwind.Flexbox.(to_class (wrap `Wrap));
-
Tailwind.Spacing.(to_class (gap `All (rem 1.0)));
-
]) [
-
btn_primary ~size:`Sm [txt "Small Primary"];
-
btn_primary [txt "Default Primary"];
-
btn_primary ~size:`Lg [txt "Large Primary"];
-
btn_primary ~disabled:true [txt "Disabled Primary"];
-
];
+
(* Primary buttons section *)
+
card [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Primary Buttons"];
+
+
div ~styles:[
+
flex;
+
flex_col;
+
margin_bottom (rem 1.0);
+
] [
+
btn_primary ~size:`Sm [txt "Small Primary"];
+
btn_primary [txt "Default Primary"];
+
btn_primary ~size:`Lg [txt "Large Primary"];
];
+
];
-
(* Secondary buttons *)
-
card [
-
h2 ~size:`Xl ~weight:`Semibold ~color:(gray 700) ~mb:(rem 1.5) [
-
txt "Secondary Buttons"
-
];
-
div ~classes:(Tailwind.Css.tw [
-
flex;
-
Tailwind.Flexbox.(to_class (wrap `Wrap));
-
Tailwind.Spacing.(to_class (gap `All (rem 1.0)));
-
]) [
-
btn_secondary ~size:`Sm [txt "Small Secondary"];
-
btn_secondary [txt "Default Secondary"];
-
btn_secondary ~size:`Lg [txt "Large Secondary"];
-
btn_secondary ~disabled:true [txt "Disabled Secondary"];
-
];
+
(* Secondary buttons section *)
+
card [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Secondary Buttons"];
+
+
div ~styles:[
+
flex;
+
flex_col;
+
margin_bottom (rem 1.0);
+
] [
+
btn_secondary ~size:`Sm [txt "Small Secondary"];
+
btn_secondary [txt "Default Secondary"];
+
btn_secondary ~size:`Lg [txt "Large Secondary"];
];
+
];
-
(* Comparison section *)
-
card [
-
h2 ~size:`Xl ~weight:`Semibold ~color:(gray 700) ~mb:(rem 1.5) [
-
txt "Before vs After"
-
];
-
div ~classes:(Tailwind.Css.tw [
-
Tailwind.Display.grid;
-
Tailwind.Grid.(to_class (template_cols (`Cols 1)));
-
Tailwind.Responsive.(to_class (at_breakpoint `Md (Tailwind.Grid.(to_class (template_cols (`Cols 2))))));
-
Tailwind.Spacing.(to_class (gap `All (rem 2.0)));
-
]) [
-
div [
-
h2 ~size:`Lg ~weight:`Medium ~color:(red 600) ~mb:(rem 1.0) [
-
txt "❌ Old Verbose Way"
-
];
-
El.pre ~at:[classes_attr (Tailwind.Css.tw [
-
Tailwind.Color.bg (gray 100);
-
Tailwind.Spacing.(to_class (p (rem 1.0)));
-
Tailwind.Effects.rounded_md;
-
Tailwind.Typography.(to_class (font_size `Sm));
-
Tailwind.Layout.(to_class (overflow `X `Auto));
-
])] [
-
El.code [txt {|let btn_classes = Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V600 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.0)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Medium));
-
] in
-
El.button ~at:[classes_attr btn_classes] [
-
El.txt "Click me!"
-
]|}];
-
];
-
];
-
div [
-
h2 ~size:`Lg ~weight:`Medium ~color:(green 600) ~mb:(rem 1.0) [
-
txt "✅ New Succinct Way"
-
];
-
El.pre ~at:[classes_attr (Tailwind.Css.tw [
-
Tailwind.Color.bg (gray 100);
-
Tailwind.Spacing.(to_class (p (rem 1.0)));
-
Tailwind.Effects.rounded_md;
-
Tailwind.Typography.(to_class (font_size `Sm));
-
Tailwind.Layout.(to_class (overflow `X `Auto));
-
])] [
-
El.code [txt {|btn_primary [txt "Click me!"]|}];
-
];
-
];
-
];
+
(* Outline buttons section *)
+
card [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Outline Buttons"];
+
+
div ~styles:[
+
flex;
+
flex_col;
+
] [
+
btn_outline ~size:`Sm [txt "Small Outline"];
+
btn_outline [txt "Default Outline"];
+
btn_outline ~size:`Lg [txt "Large Outline"];
];
];
];
+73 -174
examples/colors_and_typography_02.ml
···
-
(* Example 02: Colors and Typography - Exploring the Type System *)
+
(* Example 02: Colors and Typography - GADT interface showcase *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let create_color_demo () =
-
(* Color variants demonstration *)
-
let color_examples = [
-
("Blue 400", Color.make `Blue ~variant:`V400 ());
-
("Blue 600", Color.make `Blue ~variant:`V600 ());
-
("Green 500", Color.make `Green ~variant:`V500 ());
-
("Red 500", Color.make `Red ~variant:`V500 ());
-
("Purple 600", Color.make `Purple ~variant:`V600 ());
-
("Gray 700", Color.make `Gray ~variant:`V700 ());
-
] in
-
-
let typography_examples = [
-
("Extra Small", Typography.(to_class (font_size `Xs)));
-
("Small", Typography.(to_class (font_size `Sm)));
-
("Base", Typography.(to_class (font_size `Base)));
-
("Large", Typography.(to_class (font_size `Lg)));
-
("Extra Large", Typography.(to_class (font_size `Xl)));
-
("2X Large", Typography.(to_class (font_size `Xl2)));
-
] in
-
-
(* Create HTML demonstration *)
-
let html_doc = El.html [
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Colors and Typography"];
+
El.title [txt "Colors and Typography"];
El.link ~at:[At.rel "stylesheet"; At.href "colors_and_typography_02.css"] ();
];
-
El.body ~at:[At.class' "min-h-screen bg-gray-50 p-8"] [
-
El.div ~at:[At.class' "max-w-4xl mx-auto"] [
-
El.h1 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-8 text-center"] [El.txt "Colors and Typography Demo"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
+
container [
+
h1 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Colors and Typography Demo"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
]); At.class' "text-center mb-12"] [
-
El.txt "Explore the type-safe color system and typography utilities in Tailwind OCaml."
-
];
+
p ~styles:[
+
font_size `Lg;
+
text_color (gray 600);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Explore type-safe colors and typography with the GADT interface"];
-
(* Color Palette Section *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "Color Palette"];
+
(* Color demonstrations *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Color Palette"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 2))))));
-
Responsive.(to_class (at_breakpoint `Lg (Grid.(to_class (template_cols (`Cols 3))))));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] (List.map (fun (name, color) ->
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
Effects.shadow_sm;
-
]); At.class' "text-center"] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.text color;
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
]); At.class' "mb-4"] [El.txt "Aa"];
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt name];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V500 ());
-
]); At.class' "mb-3"] [El.txt (to_string (Css.tw [Color.text color]))];
-
El.p ~at:[classes_attr (Css.tw [Color.text color])] [
-
El.txt "The quick brown fox jumps over the lazy dog"
-
];
-
]
-
) color_examples);
+
(* Using CSS Grid for color cards *)
+
div ~styles:[
+
grid;
+
grid_cols 2;
+
gap (rem 1.0);
+
] [
+
card [
+
p ~styles:[text_color (blue 600); font_size `Lg]
+
[txt "Blue 600 - Primary color"];
+
];
+
card [
+
p ~styles:[text_color (green 500); font_size `Lg]
+
[txt "Green 500 - Success color"];
+
];
+
card [
+
p ~styles:[text_color (red 500); font_size `Lg]
+
[txt "Red 500 - Error color"];
+
];
+
card [
+
p ~styles:[text_color (purple 600); font_size `Lg]
+
[txt "Purple 600 - Accent color"];
+
];
+
];
];
-
(* Typography Scale Section *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "Typography Scale"];
+
(* Typography scale *)
+
section [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Typography Scale"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 2.0)));
-
Effects.rounded_lg;
-
Effects.shadow_sm;
-
]); At.class' "mb-8"] (List.map (fun (name, typ_class) ->
-
El.div ~at:[At.class' "mb-6 last:mb-0"] [
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (align_items `Center));
-
Flexbox.(to_class (justify `Between));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
]); At.class' "mb-2"] [
-
El.span ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Typography.(to_class (font_weight `Medium));
-
Color.text (Color.make `Gray ~variant:`V500 ());
-
])] [El.txt name];
-
El.code ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xs));
-
Color.bg (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (px (Size.rem 0.5)));
-
Spacing.(to_class (py (Size.rem 0.25)));
-
Effects.rounded_sm;
-
])] [El.txt (to_string (Css.tw [typ_class]))];
-
];
-
El.p ~at:[classes_attr (Css.tw [typ_class])] [
-
El.txt "The quick brown fox jumps over the lazy dog"
-
];
-
]
-
) typography_examples);
-
];
-
-
(* Font Weights Section *)
-
El.section [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "Font Weights"];
-
-
let weight_examples = [
-
("Light", Typography.(to_class (font_weight `Light)));
-
("Normal", Typography.(to_class (font_weight `Normal)));
-
("Medium", Typography.(to_class (font_weight `Medium)));
-
("Semibold", Typography.(to_class (font_weight `Semibold)));
-
("Bold", Typography.(to_class (font_weight `Bold)));
-
("Extrabold", Typography.(to_class (font_weight `Extrabold)));
-
] in
-
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 2.0)));
-
Effects.rounded_lg;
-
Effects.shadow_sm;
-
])] (List.map (fun (name, weight_class) ->
-
El.div ~at:[At.class' "mb-6 last:mb-0"] [
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (align_items `Center));
-
Flexbox.(to_class (justify `Between));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
]); At.class' "mb-2"] [
-
El.span ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Typography.(to_class (font_weight `Medium));
-
Color.text (Color.make `Gray ~variant:`V500 ());
-
])] [El.txt name];
-
El.code ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xs));
-
Color.bg (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (px (Size.rem 0.5)));
-
Spacing.(to_class (py (Size.rem 0.25)));
-
Effects.rounded_sm;
-
])] [El.txt (to_string (Css.tw [weight_class]))];
-
];
-
El.p ~at:[classes_attr (Css.tw [
-
weight_class;
-
Typography.(to_class (font_size `Lg));
-
])] [
-
El.txt "The quick brown fox jumps over the lazy dog"
-
];
-
]
-
) weight_examples);
+
card [
+
p ~styles:[font_size `Xs; margin_bottom (rem 1.0)] [txt "Extra Small (xs) - Supporting text"];
+
p ~styles:[font_size `Sm; margin_bottom (rem 1.0)] [txt "Small (sm) - Caption text"];
+
p ~styles:[font_size `Base; margin_bottom (rem 1.0)] [txt "Base - Body text"];
+
p ~styles:[font_size `Lg; margin_bottom (rem 1.0)] [txt "Large (lg) - Lead text"];
+
p ~styles:[font_size `Xl; margin_bottom (rem 1.0)] [txt "Extra Large (xl) - Heading"];
+
p ~styles:[font_size `Xl2] [txt "2XL - Large heading"];
+
];
];
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_color_demo () in
-
print_string (El.to_string ~doctype:true html_doc)
+
let html = create_color_demo () in
+
print_string (El.to_string ~doctype:true html)
+189 -203
examples/comprehensive_showcase_07.ml
···
-
(* Example 07: Comprehensive Showcase - Full Application Demo *)
+
(* Example 07: Comprehensive Showcase - Full application demo with GADT *)
open Htmlit
-
open Tailwind
+
open Tailwind_html
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
-
-
let create_comprehensive_html_page () =
-
(* Document structure with all features demonstrated *)
-
let html_doc = El.html [
+
let create_showcase () =
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Tailwind OCaml - Complete Feature Showcase"];
+
El.title [txt "Comprehensive Showcase"];
El.link ~at:[At.rel "stylesheet"; At.href "comprehensive_showcase_07.css"] ();
];
-
-
El.body ~at:[classes_attr (Tailwind.Css.tw [
-
Color.bg (Color.make `Gray ~variant:`V50 ());
-
Typography.(to_class (font_size `Base));
-
Typography.(to_class (line_height `Normal));
-
])] [
-
(* Header with navigation *)
-
El.header ~at:[classes_attr (Tailwind.Css.tw [
-
Color.bg Color.white;
-
Effects.shadow_lg;
-
Effects.border;
-
Color.border (Color.make `Gray ~variant:`V200 ());
-
Patterns.sticky_header;
-
])] [
-
El.div ~at:[classes_attr (Tailwind.Css.tw [
-
Patterns.container ();
-
Spacing.(to_class (px (Size.rem 1.0)));
-
])] [
-
El.div ~at:[classes_attr (Tailwind.Css.tw [
-
Display.flex;
-
Flexbox.(to_class (justify `Between));
-
Flexbox.(to_class (align_items `Center));
-
Layout.(to_class (height (Size.rem 4.0)));
-
])] [
-
(* Brand with gradient text *)
-
El.h1 ~at:[classes_attr (Tailwind.Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
])] [El.txt "Tailwind OCaml"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
]] [
+
(* Header *)
+
header ~styles:[
+
bg_color (Tailwind.Color.white);
+
shadow `Md;
+
padding (rem 1.0);
+
] [
+
container [
+
div ~styles:[
+
flex;
+
justify_between;
+
items_center;
+
] [
+
h1 ~styles:[
+
font_size `Xl;
+
font_weight `Bold;
+
text_color (blue 600);
+
] [txt "TailwindOCaml"];
-
(* Navigation items with hover effects *)
-
El.nav ~at:[classes_attr (Tailwind.Css.tw [
-
Display.flex;
-
Spacing.(to_class (gap `All (Size.rem 2.0)));
-
Flexbox.(to_class (align_items `Center));
-
])] [
-
El.a ~at:[At.href "#typography"; classes_attr (Tailwind.Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Variants.hover (Color.text (Color.make `Gray ~variant:`V900 ()));
-
Effects.transition `All;
-
])] [El.txt "Typography"];
-
El.a ~at:[At.href "#layout"; classes_attr (Tailwind.Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Variants.hover (Color.text (Color.make `Gray ~variant:`V900 ()));
-
Effects.transition `All;
-
])] [El.txt "Layout"];
-
El.a ~at:[At.href "#components"; classes_attr (Tailwind.Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Variants.hover (Color.text (Color.make `Gray ~variant:`V900 ()));
-
Effects.transition `All;
-
])] [El.txt "Components"];
-
-
(* CTA Button *)
-
El.button ~at:[classes_attr (Tailwind.Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V600 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.0)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_md;
-
Typography.(to_class (font_size `Sm));
-
Typography.(to_class (font_weight `Medium));
-
Variants.hover (Color.bg (Color.make `Blue ~variant:`V700 ()));
-
Effects.transition `All;
-
])] [El.txt "Get Started"];
+
nav ~styles:[flex] [
+
a ~styles:[
+
padding_x (rem 1.0);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#features" [txt "Features"];
+
a ~styles:[
+
padding_x (rem 1.0);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#demo" [txt "Demo"];
+
a ~styles:[
+
padding_x (rem 1.0);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#contact" [txt "Contact"];
];
];
];
];
-
(* Main Content *)
-
El.main [
-
(* Hero Section *)
-
El.section ~at:[At.id "hero"; classes_attr (Tailwind.Css.tw [
-
Layout.(to_class (min_height Size.screen));
-
Display.flex;
-
Flexbox.(to_class (align_items `Center));
-
Flexbox.(to_class (justify `Center));
-
Color.bg (Color.make `Gray ~variant:`V900 ());
-
Color.text Color.white;
-
])] [
-
El.div ~at:[At.class' "text-center container px-8"] [
-
El.h1 ~at:[classes_attr (Tailwind.Css.tw [
-
Typography.(to_class (font_size `Xl5));
-
Typography.(to_class (font_weight `Extrabold));
-
Spacing.(to_class (mb (Size.rem 1.5)));
-
])] [El.txt "Type-Safe Tailwind CSS"];
+
(* Hero Section *)
+
main ~styles:[padding_y (rem 4.0)] [
+
container [
+
div ~styles:[text_center; margin_bottom (rem 4.0)] [
+
h2 ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (gray 800);
+
margin_bottom (rem 1.5);
+
] [txt "Type-Safe CSS with GADT Interface"];
-
El.p ~at:[classes_attr (Tailwind.Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Color.text (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (mb (Size.rem 2.0)));
-
Typography.(to_class (line_height `Relaxed));
-
])] [El.txt "Build beautiful, responsive web interfaces with OCaml's type system and Tailwind's utility classes."];
+
p ~styles:[
+
font_size `Xl;
+
text_color (gray 600);
+
margin_bottom (rem 2.0);
+
] [txt "Build beautiful, maintainable UIs with compile-time guarantees"];
-
El.div ~at:[At.class' "flex flex-wrap gap-4 justify-center"] [
-
El.button ~at:[At.class' "btn-primary"] [El.txt "🚀 Get Started"];
-
El.button ~at:[At.class' "btn-ghost text-white hover:bg-white hover:text-gray-900"] [El.txt "📖 View Docs"];
+
div ~styles:[flex; justify_center] [
+
btn_primary ~size:`Lg [txt "Get Started"];
+
btn_outline ~size:`Lg [txt "Learn More"];
];
];
-
];
-
-
(* Features Grid *)
-
El.section ~at:[At.class' "section bg-white"] [
-
El.div ~at:[At.class' "container"] [
-
El.h2 ~at:[At.class' "text-3xl font-bold text-center mb-12"] [El.txt "Features"];
+
+
(* Features Grid *)
+
section ~styles:[margin_bottom (rem 4.0)] [
+
h3 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Features"];
-
El.div ~at:[At.class' "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"] [
-
(* Feature cards *)
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "🎨"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Type-Safe Classes"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Compile-time validation ensures your Tailwind classes are always correct."
-
];
-
];
-
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "⚡"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Fast Development"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Autocomplete and type hints speed up your development workflow."
+
div ~styles:[
+
grid;
+
grid_cols 1;
+
gap (rem 2.0);
+
] [
+
card [
+
h4 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (blue 600);
+
margin_bottom (rem 1.0);
+
] [txt "🎯 Type Safety"];
+
p ~styles:[text_color (gray 600)] [
+
txt "Catch styling errors at compile time with GADT-based type checking."
];
];
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "🔧"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Modular Design"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Organized modules for colors, typography, layout, and more."
+
card [
+
h4 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (green 600);
+
margin_bottom (rem 1.0);
+
] [txt "⚡ Performance"];
+
p ~styles:[text_color (gray 600)] [
+
txt "Zero runtime overhead with compile-time CSS generation."
];
];
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-red-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "📱"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Responsive Design"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Built-in responsive utilities for all screen sizes."
+
card [
+
h4 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (purple 600);
+
margin_bottom (rem 1.0);
+
] [txt "🔧 Developer Experience"];
+
p ~styles:[text_color (gray 600)] [
+
txt "Succinct syntax with heterogeneous lists and type inference."
];
];
+
];
+
];
+
+
(* Demo Section *)
+
section ~styles:[margin_bottom (rem 4.0)] [
+
h3 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Live Demo"];
+
+
card ~elevated:true [
+
h4 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.5);
+
] [txt "Interactive Component"];
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-yellow-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "🎯"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Production Ready"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Generate optimized CSS with Tailwind v4 CLI integration."
-
];
+
div ~styles:[margin_bottom (rem 2.0)] [
+
El.label ~at:[At.for' "demo-input"; classes_attr [
+
block;
+
font_weight `Medium;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
]] [txt "Try it out:"];
+
El.input ~at:[At.type' "text"; At.id "demo-input"; At.placeholder "Type something..."; classes_attr [
+
width full;
+
padding (rem 0.75);
+
border;
+
border_color (gray 300);
+
rounded `Md;
+
]] ();
];
-
El.div ~at:[At.class' "card p-6"] [
-
El.div ~at:[At.class' "w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4"] [
-
El.span ~at:[At.class' "text-2xl"] [El.txt "🚀"];
-
];
-
El.h3 ~at:[At.class' "text-lg font-semibold mb-2"] [El.txt "Modern Workflow"];
-
El.p ~at:[At.class' "text-gray-600"] [
-
El.txt "Integrates seamlessly with dune and modern OCaml tooling."
-
];
+
div ~styles:[flex; justify_end] [
+
btn_secondary [txt "Cancel"];
+
btn_primary [txt "Submit"];
];
];
];
-
];
-
-
(* Code Example Section *)
-
El.section ~at:[At.class' "section bg-gray-50"] [
-
El.div ~at:[At.class' "container"] [
-
El.h2 ~at:[At.class' "text-3xl font-bold text-center mb-12"] [El.txt "Simple & Intuitive"];
+
+
(* Statistics *)
+
section ~styles:[margin_bottom (rem 4.0)] [
+
h3 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "By the Numbers"];
-
El.div ~at:[At.class' "max-w-4xl mx-auto"] [
-
El.div ~at:[At.class' "bg-gray-900 rounded-lg p-6 text-white"] [
-
El.pre ~at:[At.class' "text-sm overflow-x-auto"] [
-
El.code [El.txt {|open Tailwind
-
-
let button_classes = Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V600 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.0)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Semibold));
-
Variants.hover (Color.bg (Color.make `Blue ~variant:`V700 ()));
-
]
-
-
let button =
-
El.button ~at:[At.class' (to_string button_classes)] [
-
El.txt "Click me!"
-
]|}];
-
];
+
div ~styles:[flex; justify_between; text_center] [
+
div [
+
p ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (blue 600);
+
] [txt "100%"];
+
p ~styles:[text_color (gray 600)] [txt "Type Safe"];
+
];
+
+
div [
+
p ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (green 600);
+
] [txt "0ms"];
+
p ~styles:[text_color (gray 600)] [txt "Runtime Cost"];
+
];
+
+
div [
+
p ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (purple 600);
+
] [txt "∞"];
+
p ~styles:[text_color (gray 600)] [txt "Possibilities"];
];
];
];
···
];
(* Footer *)
-
El.footer ~at:[At.class' "bg-gray-800 text-white py-12"] [
-
El.div ~at:[At.class' "container text-center"] [
-
El.p ~at:[At.class' "text-lg font-semibold mb-4"] [El.txt "Tailwind OCaml"];
-
El.p ~at:[At.class' "text-gray-300 mb-6"] [
-
El.txt "Type-safe Tailwind CSS for OCaml applications"
+
footer ~styles:[
+
bg_color (gray 800);
+
text_color (gray 200);
+
padding_y (rem 2.0);
+
text_center;
+
] [
+
container [
+
p ~styles:[margin_bottom (rem 1.0)] [
+
txt "© 2024 TailwindOCaml. Built with type-safe GADT interface."
];
-
El.div ~at:[At.class' "flex flex-wrap gap-8 justify-center"] [
-
El.a ~at:[At.href "#"; At.class' "text-gray-300 hover:text-white transition-colors"] [
-
El.txt "Documentation"
-
];
-
El.a ~at:[At.href "#"; At.class' "text-gray-300 hover:text-white transition-colors"] [
-
El.txt "GitHub"
-
];
-
El.a ~at:[At.href "#"; At.class' "text-gray-300 hover:text-white transition-colors"] [
-
El.txt "Examples"
-
];
-
El.a ~at:[At.href "#"; At.class' "text-gray-300 hover:text-white transition-colors"] [
-
El.txt "Support"
-
];
+
p ~styles:[font_size `Sm; text_color (gray 400)] [
+
txt "Powered by OCaml, Tailwind CSS, and compile-time guarantees."
];
];
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_comprehensive_html_page () in
-
let html_string = El.to_string ~doctype:true html_doc in
-
print_string html_string
+
let html = create_showcase () in
+
print_string (El.to_string ~doctype:true html)
+29 -12
examples/dune
···
-
;; Notebook-style examples - progressive learning path
+
;; Examples demonstrating GADT-based Tailwind interface
(executables
(public_names
index
hello_tailwind
colors_and_typography
layout_and_spacing
-
responsive_design
-
effects_and_variants
-
patterns_and_components
-
comprehensive_showcase)
+
responsive_design
+
effects_and_variants
+
patterns_and_components
+
comprehensive_showcase
+
button_demo)
(names
index_00
hello_tailwind_01
···
responsive_design_04
effects_and_variants_05
patterns_and_components_06
-
comprehensive_showcase_07)
+
comprehensive_showcase_07
+
button_demo)
(package tailwind)
(libraries tailwind tailwind-html htmlit unix))
···
(public_name index_html_generator)
(name index_html_generator)
(package tailwind)
-
(libraries tailwind htmlit))
-
+
(libraries tailwind tailwind-html htmlit))
;; Generate HTML files from examples
(rule
···
(deps (:exe comprehensive_showcase_07.exe))
(action (with-stdout-to %{target} (run %{exe}))))
+
(rule
+
(target button_demo.html)
+
(deps (:exe button_demo.exe))
+
(action (with-stdout-to %{target} (run %{exe}))))
+
;; Generate CSS files using Tailwind CLI
(rule
(targets hello_tailwind_01.css)
···
(action
(run tailwindcss --input input.css --output %{targets} --minify)))
+
(rule
+
(targets button_demo.css)
+
(deps
+
input.css
+
button_demo.html)
+
(action
+
(run tailwindcss --input input.css --output %{targets} --minify)))
+
;; Generate index.html page
(rule
(target index.html)
···
responsive_design_04.html
effects_and_variants_05.html
patterns_and_components_06.html
-
comprehensive_showcase_07.html))
+
comprehensive_showcase_07.html
+
button_demo.html))
;; Alias to build all CSS files (requires Tailwind CLI)
-
;; Run: npm install -D @tailwindcss/cli
(alias
(name examples-css)
(deps
···
responsive_design_04.css
effects_and_variants_05.css
patterns_and_components_06.css
-
comprehensive_showcase_07.css))
+
comprehensive_showcase_07.css
+
button_demo.css))
;; Install generated files
(install
···
(patterns_and_components_06.html as examples/patterns_and_components_06.html)
(patterns_and_components_06.css as examples/patterns_and_components_06.css)
(comprehensive_showcase_07.html as examples/comprehensive_showcase_07.html)
-
(comprehensive_showcase_07.css as examples/comprehensive_showcase_07.css)))
+
(comprehensive_showcase_07.css as examples/comprehensive_showcase_07.css)
+
(button_demo.html as examples/button_demo.html)
+
(button_demo.css as examples/button_demo.css)))
+183 -279
examples/effects_and_variants_05.ml
···
-
(* Example 05: Effects and Variants - Interactive Elements and Visual Effects *)
+
(* Example 05: Effects and Variants - Visual effects with GADT *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let create_effects_demo () =
-
-
(* Create comprehensive effects demonstration *)
-
let html_doc = El.html [
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Effects and Variants"];
+
El.title [txt "Effects and Variants"];
El.link ~at:[At.rel "stylesheet"; At.href "effects_and_variants_05.css"] ();
];
-
El.body ~at:[At.class' "min-h-screen bg-gray-50 p-8"] [
-
El.div ~at:[At.class' "max-w-6xl mx-auto"] [
-
El.h1 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-8 text-center"] [El.txt "Effects and Variants Demo"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
+
container [
+
h1 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Effects and Variants Demo"];
(* Shadow Effects *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Shadow Effects"];
+
section ~styles:[margin_bottom (rem 2.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Shadow Effects"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 3))))));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.shadow_sm;
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-2"] [El.txt "Small Shadow"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "shadow-sm"];
+
div ~styles:[
+
grid;
+
grid_cols 1;
+
gap (rem 1.0);
+
] [
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
shadow `Sm;
+
rounded `Lg;
+
margin_bottom (rem 1.0);
+
text_center;
+
] [
+
h3 ~styles:[
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
] [txt "Small Shadow"];
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 600);
+
] [txt "shadow-sm"];
];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.shadow_md;
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-2"] [El.txt "Medium Shadow"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "shadow-md"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
shadow `Md;
+
rounded `Lg;
+
margin_bottom (rem 1.0);
+
text_center;
+
] [
+
h3 ~styles:[
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
] [txt "Medium Shadow"];
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 600);
+
] [txt "shadow-md"];
];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.shadow_lg;
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-2"] [El.txt "Large Shadow"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "shadow-lg"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
shadow `Lg;
+
rounded `Lg;
+
text_center;
+
] [
+
h3 ~styles:[
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
] [txt "Large Shadow"];
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 600);
+
] [txt "shadow-lg"];
];
];
];
(* Rounded Corners *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Border Radius"];
+
section ~styles:[margin_bottom (rem 2.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Border Radius"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (wrap `Wrap));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
Flexbox.(to_class (justify `Center));
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
(* No rounded corners *)
-
]); At.class' "text-center"] [El.txt "No Radius"];
+
div ~styles:[
+
grid;
+
grid_cols 2;
+
gap (rem 1.0);
+
] [
+
div ~styles:[
+
bg_color (blue 100);
+
padding (rem 1.0);
+
rounded `Sm;
+
text_center;
+
margin_bottom (rem 1.0);
+
] [txt "Small Radius"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Green ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_sm;
-
]); At.class' "text-center"] [El.txt "Small"];
+
div ~styles:[
+
bg_color (green 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
margin_bottom (rem 1.0);
+
] [txt "Medium Radius"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Purple ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
]); At.class' "text-center"] [El.txt "Medium"];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Red ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [El.txt "Large"];
+
div ~styles:[
+
bg_color (purple 100);
+
padding (rem 1.0);
+
rounded `Lg;
+
text_center;
+
margin_bottom (rem 1.0);
+
] [txt "Large Radius"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Yellow ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_full;
-
]); At.class' "text-center"] [El.txt "Full"];
+
div ~styles:[
+
bg_color (yellow 100);
+
padding (rem 1.0);
+
rounded `Full;
+
text_center;
+
] [txt "Full Radius"];
];
];
(* Interactive Buttons *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Interactive Buttons"];
+
section ~styles:[margin_bottom (rem 2.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Interactive Buttons"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (wrap `Wrap));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
Flexbox.(to_class (justify `Center));
-
])] [
-
(* Hover color change *)
-
El.button ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V500 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.5)));
-
Spacing.(to_class (py (Size.rem 0.75)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Medium));
-
Effects.transition `All;
-
Variants.hover (Color.bg (Color.make `Blue ~variant:`V600 ()));
-
])] [El.txt "Hover Color"];
-
-
(* Hover shadow *)
-
El.button ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Green ~variant:`V500 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.5)));
-
Spacing.(to_class (py (Size.rem 0.75)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Medium));
-
Effects.shadow_md;
-
Effects.transition `All;
-
Variants.hover Effects.shadow_lg;
-
])] [El.txt "Hover Shadow"];
-
-
(* Scale effect *)
-
El.button ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Purple ~variant:`V500 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.5)));
-
Spacing.(to_class (py (Size.rem 0.75)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Medium));
-
Effects.transition `All;
-
]); At.class' "hover:scale-105 active:scale-95"] [El.txt "Scale Effect"];
-
-
(* Focus ring *)
-
El.button ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Red ~variant:`V500 ());
-
Color.text Color.white;
-
Spacing.(to_class (px (Size.rem 1.5)));
-
Spacing.(to_class (py (Size.rem 0.75)));
-
Effects.rounded_md;
-
Typography.(to_class (font_weight `Medium));
-
Effects.transition `All;
-
Variants.focus Effects.shadow_md;
-
])] [El.txt "Focus Ring"];
-
];
-
];
-
-
(* Card Hover Effects *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Card Hover Effects"];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 2))))));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] [
-
(* Hover shadow card *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
Effects.shadow_md;
-
Effects.transition `All;
-
Variants.hover Effects.shadow_lg;
-
]); At.class' "cursor-pointer"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt "Shadow Lift"];
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "Hover to see the shadow increase. This creates a lifting effect."];
-
];
-
-
(* Scale and shadow card *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
Effects.shadow_md;
-
Effects.transition `All;
-
]); At.class' "cursor-pointer hover:scale-105 hover:shadow-xl"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt "Scale + Shadow"];
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "This card both scales up and increases shadow on hover."];
-
];
+
div ~styles:[
+
grid;
+
grid_cols 1;
+
gap (rem 1.0);
+
] [
+
btn_primary [txt "Primary Button with Hover"];
+
btn_secondary [txt "Secondary Button"];
+
btn_outline [txt "Outline Button"];
];
];
(* Border Effects *)
-
El.section [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Border Effects"];
+
section [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Border Effects"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 3))))));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] [
+
div ~styles:[
+
grid;
+
grid_cols 1;
+
gap (rem 1.0);
+
] [
(* Regular border *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.border;
-
Color.border (Color.make `Gray ~variant:`V200 ());
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-2"] [El.txt "Regular Border"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "border border-gray-200"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
border;
+
border_color (gray 200);
+
rounded `Lg;
+
text_center;
+
margin_bottom (rem 1.0);
+
] [
+
h3 ~styles:[
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
] [txt "Regular Border"];
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 600);
+
] [txt "border border-gray-200"];
];
(* Colored border *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.border;
-
Color.border (Color.make `Blue ~variant:`V300 ());
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
]); At.class' "mb-2"] [El.txt "Colored Border"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "border border-blue-300"];
-
];
-
-
(* Thick border *)
-
El.div ~at:[At.class' "bg-white p-6 border-2 border-purple-300 rounded-lg text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Purple ~variant:`V600 ());
-
]); At.class' "mb-2"] [El.txt "Thick Border"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "border-2 border-purple-300"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
border;
+
border_color (blue 300);
+
rounded `Lg;
+
text_center;
+
] [
+
h3 ~styles:[
+
font_weight `Semibold;
+
text_color (blue 600);
+
margin_bottom (rem 0.5);
+
] [txt "Colored Border"];
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 600);
+
] [txt "border border-blue-300"];
];
];
];
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_effects_demo () in
-
let html_string = El.to_string ~doctype:true html_doc in
-
print_string html_string
+
let html = create_effects_demo () in
+
print_string (El.to_string ~doctype:true html)
-213
examples/gadt_demo.ml
···
-
(* GADT Heterogeneous List Demo - Revolutionary Tailwind interface *)
-
-
open Htmlit
-
open Tailwind_html
-
-
let create_gadt_demo () =
-
let html = El.html [
-
El.head [
-
El.meta ~at:[At.charset "utf-8"] ();
-
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [txt "GADT Tailwind Demo"];
-
El.link ~at:[At.rel "stylesheet"; At.href "gadt_demo.css"] ();
-
];
-
-
El.body ~at:[classes_attr [
-
bg_color (gray 50);
-
padding (rem 2.0);
-
]] [
-
(* Hero Section *)
-
h1 ~styles:[
-
text_color (blue 600);
-
font_size `Xl4;
-
font_weight `Bold;
-
text_center;
-
margin_bottom (rem 2.0);
-
] [txt "🚀 GADT Heterogeneous Lists for Tailwind"];
-
-
p ~styles:[
-
text_color (gray 700);
-
font_size `Lg;
-
text_center;
-
margin_bottom (rem 3.0);
-
] [txt "Type-safe, conflict-preventing, succinct Tailwind class composition"];
-
-
(* Feature Cards Grid *)
-
div ~styles:[
-
flex;
-
justify_center;
-
margin_bottom (rem 3.0);
-
] [
-
div ~styles:[
-
bg_color (gray 50);
-
rounded `Lg;
-
shadow `Lg;
-
padding (rem 2.0);
-
text_center;
-
] [
-
h2 ~styles:[
-
font_size `Xl2;
-
font_weight `Semibold;
-
text_color (gray 800);
-
margin_bottom (rem 1.0);
-
] [txt "✨ Magic of GADTs"];
-
-
p ~styles:[
-
text_color (gray 600);
-
margin_bottom (rem 1.5);
-
] [txt "Each property is type-categorized and validated at compile time"];
-
];
-
];
-
-
(* Before/After Comparison *)
-
div ~styles:[
-
bg_color (Tailwind.Color.white);
-
rounded `Lg;
-
shadow `Md;
-
padding (rem 2.0);
-
margin_bottom (rem 3.0);
-
] [
-
h2 ~styles:[
-
font_size `Xl2;
-
font_weight `Bold;
-
text_color (gray 800);
-
margin_bottom (rem 1.5);
-
] [txt "🔄 Before vs After"];
-
-
div ~styles:[
-
flex;
-
justify_between;
-
] [
-
(* Old Way *)
-
div ~styles:[
-
bg_color (red 50);
-
rounded `Md;
-
padding (rem 1.5);
-
margin_right (rem 1.0);
-
] [
-
h3 ~styles:[
-
font_size `Lg;
-
font_weight `Medium;
-
text_color (red 700);
-
margin_bottom (rem 1.0);
-
] [txt "❌ Old Verbose Way"];
-
-
El.pre ~at:[classes_attr [
-
bg_color (gray 100);
-
padding (rem 1.0);
-
rounded `Sm;
-
font_size `Sm;
-
]] [
-
El.code [txt {|Css.tw [
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Spacing.(to_class (mb (Size.rem 1.0)));
-
]|}];
-
];
-
];
-
-
(* New Way *)
-
div ~styles:[
-
bg_color (green 50);
-
rounded `Md;
-
padding (rem 1.5);
-
] [
-
h3 ~styles:[
-
font_size `Lg;
-
font_weight `Medium;
-
text_color (green 700);
-
margin_bottom (rem 1.0);
-
] [txt "✅ New GADT Way"];
-
-
El.pre ~at:[classes_attr [
-
bg_color (gray 100);
-
padding (rem 1.0);
-
rounded `Sm;
-
font_size `Sm;
-
]] [
-
El.code [txt {|[
-
text_color (blue 600);
-
font_size `Xl2;
-
font_weight `Bold;
-
margin_bottom (rem 1.0);
-
]|}];
-
];
-
];
-
];
-
];
-
-
(* Interactive Example *)
-
div ~styles:[
-
bg_color (Tailwind.Color.white);
-
rounded `Lg;
-
shadow `Md;
-
padding (rem 2.0);
-
margin_bottom (rem 2.0);
-
] [
-
h2 ~styles:[
-
font_size `Xl2;
-
font_weight `Bold;
-
text_color (gray 800);
-
margin_bottom (rem 1.5);
-
] [txt "🎯 Type Safety in Action"];
-
-
p ~styles:[
-
text_color (gray 600);
-
margin_bottom (rem 2.0);
-
] [txt "Each property category can only appear once, preventing conflicts:"];
-
-
(* Sample buttons with different styles *)
-
div ~styles:[
-
flex;
-
justify_between;
-
margin_bottom (rem 2.0);
-
] [
-
button ~styles:[
-
bg_color (blue 600);
-
text_color (Tailwind.Color.white);
-
padding (rem 1.0);
-
rounded `Md;
-
font_weight `Medium;
-
] [txt "Primary Button"];
-
-
button ~styles:[
-
bg_color (green 600);
-
text_color (Tailwind.Color.white);
-
padding (rem 1.0);
-
rounded `Md;
-
font_weight `Medium;
-
] [txt "Success Button"];
-
-
button ~styles:[
-
bg_color (red 600);
-
text_color (Tailwind.Color.white);
-
padding (rem 1.0);
-
rounded `Md;
-
font_weight `Medium;
-
] [txt "Danger Button"];
-
];
-
-
p ~styles:[
-
text_color (gray 500);
-
font_size `Sm;
-
] [txt "Try adding two text_color entries - the compiler will prevent conflicts!"];
-
];
-
-
(* Footer *)
-
div ~styles:[
-
text_center;
-
padding_y (rem 2.0);
-
] [
-
p ~styles:[
-
text_color (gray 500);
-
font_size `Sm;
-
] [txt "🤖 Generated with revolutionary GADT-based Tailwind combinators"];
-
];
-
];
-
] in
-
html
-
-
let () =
-
let html = create_gadt_demo () in
-
print_string (El.to_string ~doctype:true html)
+145 -156
examples/index_html_generator.ml
···
(* Generate index.html page linking to all examples *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let examples = [
("hello_tailwind_01.html", "01. Hello Tailwind",
-
"Your first Tailwind OCaml program. Learn the basics of creating and using type-safe Tailwind classes.",
-
["Basic concepts"; "Type safety"; "Class composition"]);
-
+
"Your first Tailwind OCaml program with GADT interface",
+
["Basic concepts"; "Type safety"; "GADT syntax"]);
+
("colors_and_typography_02.html", "02. Colors and Typography",
-
"Explore the comprehensive color system and typography utilities with compile-time validation.",
-
["Color variants"; "Typography scale"; "Font weights"]);
-
+
"Type-safe colors and typography with compile-time validation",
+
["Color variants"; "Typography scale"; "Grid layouts"]);
+
("layout_and_spacing_03.html", "03. Layout and Spacing",
-
"Master the box model, flexbox layouts, and spacing utilities for building structured interfaces.",
-
["Box model"; "Flexbox"; "Spacing system"]);
-
+
"Master CSS Grid, flexbox layouts and spacing with GADT",
+
["CSS Grid"; "Flexbox"; "Gap utilities"; "Spacing system"]);
+
("responsive_design_04.html", "04. Responsive Design",
-
"Learn responsive design patterns with breakpoints and mobile-first utilities.",
-
["Breakpoints"; "Mobile-first"; "Responsive utilities"]);
-
+
"Adaptive layouts using GADT interface",
+
["Mobile-first"; "CSS Grid"; "Responsive cards"]);
+
("effects_and_variants_05.html", "05. Effects and Variants",
-
"Add visual effects and interactive states with shadows, borders, and hover variants.",
-
["Visual effects"; "Interactive states"; "Hover variants"]);
-
+
"Visual effects with shadows, borders, and rounded corners",
+
["Shadow effects"; "Grid layouts"; "Interactive buttons"]);
+
("patterns_and_components_06.html", "06. Patterns and Components",
-
"Build reusable layout patterns and component compositions for consistent design.",
-
["Layout patterns"; "Component composition"; "Reusable utilities"]);
-
+
"Reusable component patterns with GADT",
+
["Card patterns"; "Button components"; "Form patterns"]);
+
("comprehensive_showcase_07.html", "07. Comprehensive Showcase",
-
"Complete application demo showcasing all library features in a real-world context.",
-
["Complete application"; "All features"; "Best practices"]);
+
"Full application demo with complete UI",
+
["Header/Footer"; "Hero section"; "Feature grids"]);
+
+
("button_demo.html", "Button Demo",
+
"Showcase of all button variants and sizes",
+
["Primary buttons"; "Secondary buttons"; "Outline buttons"]);
]
-
let create_index_page () =
-
let page_classes = Css.tw [
-
Layout.(to_class (min_height Size.screen));
-
Color.bg (Color.make `Gray ~variant:`V50 ());
-
] in
-
-
let container_classes = Css.tw [
-
Spacing.(to_class (mx `Auto));
-
Spacing.(to_class (p (Size.rem 2.0)));
-
] in
-
-
let header_classes = Css.tw [
-
Typography.(to_class (font_size `Xl4));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V900 ());
-
Spacing.(to_class (mb (Size.rem 2.0)));
-
Typography.(to_class (text_align `Center));
-
] in
-
-
let subtitle_classes = Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Typography.(to_class (text_align `Center));
-
Spacing.(to_class (mb (Size.rem 3.0)));
-
] in
-
-
let grid_classes = Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 2))))));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
Spacing.(to_class (mb (Size.rem 3.0)));
-
] in
-
-
let card_classes = Css.tw [
-
Color.bg Color.white;
-
Effects.rounded_lg;
-
Effects.shadow_sm;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.border;
-
Color.border (Color.make `Gray ~variant:`V200 ());
-
Effects.transition `All;
-
Variants.hover Effects.shadow_md;
-
Variants.hover (Color.border (Color.make `Blue ~variant:`V300 ()));
-
] in
-
-
let card_title_classes = Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V900 ());
-
Spacing.(to_class (mb (Size.rem 0.75)));
-
] in
-
-
let card_description_classes = Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Spacing.(to_class (mb (Size.rem 1.0)));
-
Typography.(to_class (line_height `Relaxed));
-
] in
-
-
let features_classes = Css.tw [
-
Display.flex;
-
Flexbox.(to_class (wrap `Wrap));
-
Spacing.(to_class (gap `All (Size.rem 0.5)));
-
Spacing.(to_class (mb (Size.rem 1.0)));
-
] in
-
-
let feature_tag_classes = Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V50 ());
-
Color.text (Color.make `Blue ~variant:`V700 ());
-
Typography.(to_class (font_size `Xs));
-
Spacing.(to_class (px (Size.rem 0.5)));
-
Spacing.(to_class (py (Size.rem 0.25)));
-
Effects.rounded_full;
-
] in
-
-
let link_classes = Css.tw [
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
Typography.(to_class (font_weight `Medium));
-
Variants.hover (Color.text (Color.make `Blue ~variant:`V800 ()));
-
Effects.transition `Colors;
-
] in
-
-
let footer_classes = Css.tw [
-
Typography.(to_class (text_align `Center));
-
Spacing.(to_class (mt (Size.rem 3.0)));
-
Color.text (Color.make `Gray ~variant:`V500 ());
-
Typography.(to_class (font_size `Sm));
-
] in
-
-
let html_doc = El.html [
+
let create_index () =
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Tailwind OCaml Examples"];
-
El.link ~at:[At.rel "stylesheet"; At.href "hello_tailwind_01.css"] (); (* Reuse CSS from first example *)
-
El.style [El.txt {|
-
body { font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; }
-
a { text-decoration: none; }
-
.example-card { display: block; }
+
El.title [txt "Tailwind OCaml Examples - GADT Interface"];
+
El.style [txt {|
+
body { font-family: system-ui, -apple-system, sans-serif; }
+
.example-card { transition: transform 0.2s, box-shadow 0.2s; }
+
.example-card:hover { transform: translateY(-2px); }
|}];
];
-
El.body ~at:[classes_attr page_classes] [
-
El.div ~at:[classes_attr container_classes] [
-
El.h1 ~at:[classes_attr header_classes] [
-
El.txt "Tailwind OCaml Examples"
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
+
container [
+
(* Header *)
+
header ~styles:[
+
text_center;
+
margin_bottom (rem 3.0);
+
] [
+
h1 ~styles:[
+
font_size `Xl3;
+
font_weight `Bold;
+
text_color (gray 800);
+
margin_bottom (rem 1.0);
+
] [txt "🎨 Tailwind OCaml Examples"];
+
+
p ~styles:[
+
font_size `Xl;
+
text_color (gray 600);
+
margin_bottom (rem 1.0);
+
] [txt "Type-safe CSS generation with GADT-based interface"];
+
+
p ~styles:[
+
font_size `Base;
+
text_color (gray 500);
+
] [txt "Explore examples showcasing the power of compile-time guaranteed styling"];
];
-
El.p ~at:[classes_attr subtitle_classes] [
-
El.txt "A progressive tutorial series demonstrating type-safe Tailwind CSS generation in OCaml"
-
];
-
-
El.div ~at:[classes_attr grid_classes] (
-
List.map (fun (href, title, description, features) ->
-
El.a ~at:[At.href href; At.class' "example-card"] [
-
El.div ~at:[classes_attr card_classes] [
-
El.h2 ~at:[classes_attr card_title_classes] [El.txt title];
-
El.p ~at:[classes_attr card_description_classes] [El.txt description];
-
El.div ~at:[classes_attr features_classes] (
-
List.map (fun feature ->
-
El.span ~at:[classes_attr feature_tag_classes] [El.txt feature]
-
) features
-
);
-
El.div ~at:[classes_attr link_classes] [
-
El.txt "View Example →"
-
];
+
(* Examples Grid *)
+
div ~styles:[
+
grid;
+
grid_cols 1;
+
gap (rem 1.5);
+
] (List.map (fun (file, title, desc, features) ->
+
El.a ~at:[At.href file; At.style "text-decoration: none; color: inherit;"] [
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
rounded `Lg;
+
shadow `Md;
+
padding (rem 2.0);
+
margin_bottom (rem 1.5);
+
border;
+
border_color (gray 200);
+
transition;
+
] [
+
(* Title and description *)
+
div ~styles:[margin_bottom (rem 1.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 0.5);
+
] [txt title];
+
+
p ~styles:[
+
text_color (gray 600);
+
margin_bottom (rem 1.0);
+
] [txt desc];
];
-
]
-
) examples
-
);
+
+
(* Feature tags *)
+
div ~styles:[
+
grid;
+
grid_cols 3;
+
gap_x (rem 0.5);
+
gap_y (rem 0.5);
+
] (List.map (fun feature ->
+
span ~styles:[
+
bg_color (blue 100);
+
text_color (blue 700);
+
padding_x (rem 0.75);
+
padding_y (rem 0.25);
+
rounded `Full;
+
font_size `Sm;
+
font_weight `Medium;
+
margin_right (rem 0.5);
+
margin_bottom (rem 0.5);
+
] [txt feature]
+
) features);
+
+
(* View link *)
+
div ~styles:[
+
margin_top (rem 1.0);
+
text_right;
+
] [
+
span ~styles:[
+
text_color (blue 600);
+
font_weight `Medium;
+
] [txt "View Example →"];
+
];
+
];
+
]
+
) examples);
-
El.div ~at:[classes_attr footer_classes] [
-
El.p [
-
El.txt "Built with ";
-
El.a ~at:[At.href "https://github.com/dbuenzli/htmlit"; classes_attr link_classes] [El.txt "Htmlit"];
-
El.txt " and type-safe Tailwind CSS generation"
-
];
+
(* Footer *)
+
footer ~styles:[
+
text_center;
+
margin_top (rem 3.0);
+
padding_y (rem 2.0);
+
border;
+
border_color (gray 200);
+
] [
+
p ~styles:[
+
text_color (gray 500);
+
font_size `Sm;
+
margin_bottom (rem 0.5);
+
] [txt "Built with OCaml, Tailwind CSS, and GADT-based type safety"];
+
+
p ~styles:[
+
text_color (gray 400);
+
font_size `Xs;
+
] [txt "© 2024 Tailwind OCaml - Compile-time guaranteed styling"];
];
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_index_page () in
-
let html_string = El.to_string ~doctype:true html_doc in
-
print_string html_string
+
let html = create_index () in
+
print_string (El.to_string ~doctype:true html)
+259 -211
examples/layout_and_spacing_03.ml
···
-
(* Example 03: Layout and Spacing - Mastering Box Model and Flexbox *)
+
(* Example 03: Layout and Spacing - GADT flexbox and spacing demo *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let create_layout_demo () =
-
(* Create comprehensive layout demonstration *)
-
let html_doc = El.html [
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Layout and Spacing"];
+
El.title [txt "Layout and Spacing"];
El.link ~at:[At.rel "stylesheet"; At.href "layout_and_spacing_03.css"] ();
];
-
El.body ~at:[At.class' "min-h-screen bg-gray-50 p-8"] [
-
El.div ~at:[At.class' "max-w-6xl mx-auto"] [
-
El.h1 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-8 text-center"] [El.txt "Layout and Spacing Demo"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
+
container [
+
h1 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Layout and Spacing Demo"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
]); At.class' "text-center mb-12"] [
-
El.txt "Master the box model, flexbox, and CSS grid with type-safe utilities."
-
];
+
p ~styles:[
+
font_size `Lg;
+
text_color (gray 600);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Master flexbox layouts and spacing with GADT interface"];
(* Flexbox Examples *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "Flexbox Layouts"];
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Flexbox Layouts"];
(* Centered content *)
-
El.div ~at:[At.class' "mb-8"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-4"] [El.txt "Centered Content"];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.0);
+
] [txt "Centered Content"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (justify `Center));
-
Flexbox.(to_class (align_items `Center));
-
Color.bg (Color.make `Blue ~variant:`V100 ());
-
Layout.(to_class (height (Size.rem 8.0)));
-
Effects.rounded_lg;
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_md;
-
Effects.shadow_sm;
-
])] [
-
El.txt "Perfectly Centered Content"
+
div ~styles:[
+
flex;
+
justify_center;
+
items_center;
+
bg_color (blue 100);
+
height (rem 8.0);
+
rounded `Lg;
+
margin_bottom (rem 1.5);
+
] [
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.5);
+
rounded `Md;
+
shadow `Sm;
+
] [
+
txt "Perfectly Centered Content"
];
];
];
(* Space between items *)
-
El.div ~at:[At.class' "mb-8"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-4"] [El.txt "Space Between"];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.0);
+
] [txt "Space Between"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (justify `Between));
-
Flexbox.(to_class (align_items `Center));
-
Color.bg (Color.make `Green ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Left"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Center"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Right"];
-
];
-
];
-
-
(* Flex direction example *)
-
El.div [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-4"] [El.txt "Flex Direction Column"];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (direction `Col));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
Color.bg (Color.make `Purple ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
]); At.class' "text-center"] [El.txt "Item 1"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
]); At.class' "text-center"] [El.txt "Item 2"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
]); At.class' "text-center"] [El.txt "Item 3"];
+
div ~styles:[
+
flex;
+
justify_between;
+
items_center;
+
bg_color (green 100);
+
padding (rem 1.5);
+
rounded `Lg;
+
] [
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.0);
+
rounded `Md;
+
] [txt "Left"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.0);
+
rounded `Md;
+
] [txt "Center"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.0);
+
rounded `Md;
+
] [txt "Right"];
];
];
];
-
(* Grid Examples *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "CSS Grid Layouts"];
+
(* Grid Layout Examples *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "CSS Grid Layouts"];
-
(* 2-column grid *)
-
El.div ~at:[At.class' "mb-8"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-4"] [El.txt "Two Column Grid"];
+
(* 3-column grid *)
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.0);
+
] [txt "Three Column Grid"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 2)));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] (List.init 4 (fun i ->
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Red ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.txt (Printf.sprintf "Grid Item %d" (i + 1))
-
]
-
));
+
div ~styles:[
+
grid;
+
grid_cols 3;
+
gap (rem 1.0);
+
] [
+
div ~styles:[
+
bg_color (blue 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 1"];
+
div ~styles:[
+
bg_color (green 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 2"];
+
div ~styles:[
+
bg_color (purple 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 3"];
+
div ~styles:[
+
bg_color (red 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 4"];
+
div ~styles:[
+
bg_color (yellow 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 5"];
+
div ~styles:[
+
bg_color (indigo 100);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt "Item 6"];
+
];
];
-
(* 3-column grid *)
-
El.div ~at:[At.class' "mb-8"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-4"] [El.txt "Three Column Grid"];
+
(* Grid gap examples *)
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.0);
+
] [txt "Grid Gap Variations"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 3)));
-
Spacing.(to_class (gap `All (Size.rem 1.5)));
-
])] (List.init 6 (fun i ->
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Yellow ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
]); At.class' "text-center"] [
-
El.txt (Printf.sprintf "Item %d" (i + 1))
-
]
-
));
+
div ~styles:[margin_bottom (rem 1.5)] [
+
h4 ~styles:[
+
font_size `Base;
+
font_weight `Medium;
+
text_color (gray 600);
+
margin_bottom (rem 0.5);
+
] [txt "Small Gap"];
+
div ~styles:[
+
grid;
+
grid_cols 4;
+
gap (rem 0.5);
+
] (List.init 4 (fun i ->
+
div ~styles:[
+
bg_color (blue 200);
+
padding (rem 0.5);
+
rounded `Sm;
+
text_center;
+
] [txt (string_of_int (i + 1))]
+
));
+
];
+
+
div ~styles:[margin_bottom (rem 1.5)] [
+
h4 ~styles:[
+
font_size `Base;
+
font_weight `Medium;
+
text_color (gray 600);
+
margin_bottom (rem 0.5);
+
] [txt "Large Gap"];
+
div ~styles:[
+
grid;
+
grid_cols 3;
+
gap (rem 2.0);
+
] (List.init 3 (fun i ->
+
div ~styles:[
+
bg_color (green 200);
+
padding (rem 1.0);
+
rounded `Md;
+
text_center;
+
] [txt (Printf.sprintf "Item %d" (i + 1))]
+
));
+
];
+
+
div [
+
h4 ~styles:[
+
font_size `Base;
+
font_weight `Medium;
+
text_color (gray 600);
+
margin_bottom (rem 0.5);
+
] [txt "Asymmetric Gap"];
+
div ~styles:[
+
grid;
+
grid_cols 2;
+
gap_x (rem 2.0);
+
gap_y (rem 0.5);
+
] (List.init 4 (fun i ->
+
div ~styles:[
+
bg_color (purple 200);
+
padding (rem 0.75);
+
rounded `Md;
+
text_center;
+
] [txt (Printf.sprintf "Box %d" (i + 1))]
+
));
+
];
];
];
(* Spacing Examples *)
-
El.section [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8"] [El.txt "Spacing System"];
+
section [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Spacing System"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 2))))));
-
Spacing.(to_class (gap `All (Size.rem 2.0)));
-
])] [
+
(* Using grid for spacing examples *)
+
div ~styles:[
+
grid;
+
grid_cols 2;
+
gap (rem 1.5);
+
] [
(* Padding example *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Indigo ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
])] [
-
El.h4 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Base));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-3"] [El.txt "Padding Example"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 2.0)));
-
Effects.rounded_md;
-
Effects.border;
-
Color.border (Color.make `Gray ~variant:`V200 ());
-
])] [
-
El.txt "This content has p-8 (2rem padding)"
+
card [
+
h4 ~styles:[
+
font_size `Base;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.75);
+
] [txt "Padding Example"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 2.0);
+
rounded `Md;
+
border;
+
border_color (gray 200);
+
] [
+
txt "This content has padding (2rem)"
];
];
(* Margin example *)
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Cyan ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Effects.rounded_lg;
-
])] [
-
El.h4 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Base));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-3"] [El.txt "Margin Example"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Spacing.(to_class (m (Size.rem 1.5)));
-
Effects.rounded_md;
-
Effects.border;
-
Color.border (Color.make `Gray ~variant:`V200 ());
-
])] [
-
El.txt "This box has m-6 (1.5rem margin) from its container"
+
card [
+
h4 ~styles:[
+
font_size `Base;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 0.75);
+
] [txt "Margin Example"];
+
div ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.0);
+
margin (rem 1.5);
+
rounded `Md;
+
border;
+
border_color (gray 200);
+
] [
+
txt "This box has margin (1.5rem) from its container"
];
];
];
···
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_layout_demo () in
-
print_string (El.to_string ~doctype:true html_doc)
+
let html = create_layout_demo () in
+
print_string (El.to_string ~doctype:true html)
+165 -135
examples/patterns_and_components_06.ml
···
-
(* Example 06: Patterns and Components - Reusable Layout Patterns *)
+
(* Example 06: Patterns and Components - Reusable components with GADT *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let create_patterns_demo () =
-
(* Create comprehensive patterns demonstration *)
-
let html_doc = El.html [
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Patterns and Components"];
+
El.title [txt "Patterns and Components"];
El.link ~at:[At.rel "stylesheet"; At.href "patterns_and_components_06.css"] ();
];
-
El.body ~at:[At.class' "min-h-screen bg-gray-50 p-8"] [
-
El.div ~at:[At.class' "max-w-6xl mx-auto"] [
-
El.h1 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-8 text-center"] [El.txt "Patterns and Components Demo"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 2.0);
+
]] [
+
container [
+
h1 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Patterns and Components Demo"];
(* Container Pattern *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Container Pattern"];
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Container Pattern"];
-
El.div ~at:[classes_attr (Css.tw [Patterns.container ()]); At.class' "bg-white rounded-lg shadow-sm p-6"] [
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "This content is inside a container pattern that centers content and provides responsive padding."];
+
card [
+
p ~styles:[text_color (gray 600)] [
+
txt "This content is inside a container pattern that centers content and provides responsive padding."
+
];
];
];
(* Card Pattern *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Card Pattern"];
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Card Patterns"];
-
El.div ~at:[At.class' "grid grid-cols-1 md:grid-cols-3 gap-6"] [
-
El.div ~at:[classes_attr (Css.tw [Patterns.card]); At.class' "p-6"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt "Card One"];
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "This is a card using the built-in card pattern."];
+
div ~styles:[flex; flex_col] [
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.0);
+
] [txt "Basic Card"];
+
p ~styles:[text_color (gray 600)] [
+
txt "A simple card with padding and shadow."
+
];
];
-
El.div ~at:[classes_attr (Css.tw [Patterns.card]); At.class' "p-6"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt "Card Two"];
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "Another card with the same styling pattern applied."];
-
];
-
-
El.div ~at:[classes_attr (Css.tw [Patterns.card]); At.class' "p-6"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
]); At.class' "mb-2"] [El.txt "Card Three"];
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [El.txt "A third card demonstrating consistent styling."];
+
card ~elevated:true [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.0);
+
] [txt "Elevated Card"];
+
p ~styles:[text_color (gray 600)] [
+
txt "This card has a stronger shadow for emphasis."
+
];
];
];
];
-
(* Flex Center Pattern *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Flex Center Pattern"];
+
(* Button Components *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Button Components"];
-
El.div ~at:[classes_attr (Css.tw [Patterns.flex_center]); At.class' "bg-blue-50 rounded-lg h-32"] [
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
Typography.(to_class (font_weight `Medium));
-
])] [El.txt "This content is perfectly centered using flex_center pattern"];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.5);
+
] [txt "Button Variants"];
+
+
div ~styles:[flex; flex_col] [
+
div ~styles:[margin_bottom (rem 1.0)] [
+
btn_primary ~size:`Sm [txt "Small Primary"];
+
btn_primary [txt "Default Primary"];
+
btn_primary ~size:`Lg [txt "Large Primary"];
+
];
+
+
div ~styles:[margin_bottom (rem 1.0)] [
+
btn_secondary ~size:`Sm [txt "Small Secondary"];
+
btn_secondary [txt "Default Secondary"];
+
btn_secondary ~size:`Lg [txt "Large Secondary"];
+
];
+
+
div [
+
btn_outline ~size:`Sm [txt "Small Outline"];
+
btn_outline [txt "Default Outline"];
+
btn_outline ~size:`Lg [txt "Large Outline"];
+
];
+
];
];
];
-
(* Stack Pattern *)
-
El.section ~at:[At.class' "mb-12"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Stack Pattern"];
+
(* List Pattern *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "List Patterns"];
-
El.div ~at:[classes_attr (Css.tw [Patterns.stack ~gap:(Size.rem 1.0) ()]); At.class' "bg-white rounded-lg shadow-sm p-6"] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Green ~variant:`V50 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Stack Item 1"];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.0);
+
] [txt "Feature List"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V50 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Stack Item 2"];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Purple ~variant:`V50 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Effects.rounded_md;
-
])] [El.txt "Stack Item 3"];
+
ul ~styles:[text_color (gray 600)] [
+
li ~styles:[margin_bottom (rem 0.5)] [txt "✓ Type-safe styling"];
+
li ~styles:[margin_bottom (rem 0.5)] [txt "✓ Conflict prevention"];
+
li ~styles:[margin_bottom (rem 0.5)] [txt "✓ Succinct syntax"];
+
li [txt "✓ Reusable components"];
+
];
];
];
-
(* Inline Stack Pattern *)
-
El.section [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Inline Stack Pattern"];
+
(* Form Pattern *)
+
section [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 1.5);
+
] [txt "Form Patterns"];
-
El.div ~at:[classes_attr (Css.tw [Patterns.inline_stack ~gap:(Size.rem 1.0) ()]); At.class' "bg-white rounded-lg shadow-sm p-6"] [
-
El.span ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Red ~variant:`V50 ());
-
Color.text (Color.make `Red ~variant:`V600 ());
-
Spacing.(to_class (px (Size.rem 0.75)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_full;
-
Typography.(to_class (font_size `Sm));
-
])] [El.txt "Tag 1"];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.5);
+
] [txt "Simple Form"];
-
El.span ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Yellow ~variant:`V50 ());
-
Color.text (Color.make `Yellow ~variant:`V600 ());
-
Spacing.(to_class (px (Size.rem 0.75)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_full;
-
Typography.(to_class (font_size `Sm));
-
])] [El.txt "Tag 2"];
-
-
El.span ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Indigo ~variant:`V50 ());
-
Color.text (Color.make `Indigo ~variant:`V600 ());
-
Spacing.(to_class (px (Size.rem 0.75)));
-
Spacing.(to_class (py (Size.rem 0.5)));
-
Effects.rounded_full;
-
Typography.(to_class (font_size `Sm));
-
])] [El.txt "Tag 3"];
+
div ~styles:[flex; flex_col] [
+
div ~styles:[margin_bottom (rem 1.5)] [
+
El.label ~at:[At.for' "name"; classes_attr [
+
block;
+
font_weight `Medium;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
]] [txt "Name"];
+
El.input ~at:[At.type' "text"; At.id "name"; classes_attr [
+
width full;
+
padding (rem 0.5);
+
border;
+
border_color (gray 300);
+
rounded `Md;
+
]] ();
+
];
+
+
div ~styles:[margin_bottom (rem 1.5)] [
+
El.label ~at:[At.for' "email"; classes_attr [
+
block;
+
font_weight `Medium;
+
text_color (gray 700);
+
margin_bottom (rem 0.5);
+
]] [txt "Email"];
+
El.input ~at:[At.type' "email"; At.id "email"; classes_attr [
+
width full;
+
padding (rem 0.5);
+
border;
+
border_color (gray 300);
+
rounded `Md;
+
]] ();
+
];
+
+
btn_primary [txt "Submit"];
+
];
];
];
];
];
] in
-
html_doc
+
html
let () =
-
(* Output HTML to stdout *)
-
let html_doc = create_patterns_demo () in
-
let html_string = El.to_string ~doctype:true html_doc in
-
print_string html_string
+
let html = create_patterns_demo () in
+
print_string (El.to_string ~doctype:true html)
+144 -148
examples/responsive_design_04.ml
···
-
(* Example 04: Responsive Design - Building Adaptive Layouts *)
+
(* Example 04: Responsive Design - GADT interface showcase *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' (Tailwind.to_string tailwind_classes)
+
open Tailwind_html
let create_responsive_demo () =
-
(* Create comprehensive responsive demonstration *)
-
let html_doc = El.html [
+
let html = El.html [
El.head [
El.meta ~at:[At.charset "utf-8"] ();
El.meta ~at:[At.name "viewport"; At.content "width=device-width, initial-scale=1"] ();
-
El.title [El.txt "Responsive Design"];
+
El.title [txt "Responsive Design"];
El.link ~at:[At.rel "stylesheet"; At.href "responsive_design_04.css"] ();
];
-
El.body ~at:[At.class' "min-h-screen bg-gray-50 p-8"] [
-
El.div ~at:[At.class' "max-w-6xl mx-auto"] [
-
El.h1 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl2));
-
Responsive.(to_class (at_breakpoint `Md (Typography.(to_class (font_size `Xl3)))));
-
Typography.(to_class (font_weight `Bold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-8 text-center"] [El.txt "Responsive Design Demo"];
+
El.body ~at:[classes_attr [
+
min_height screen;
+
bg_color (gray 50);
+
padding (rem 1.0);
+
]] [
+
container [
+
h1 ~styles:[
+
font_size `Xl2;
+
font_weight `Bold;
+
text_color (gray 800);
+
text_center;
+
margin_bottom (rem 2.0);
+
] [txt "Responsive Design Demo"];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
]); At.class' "text-center mb-8"] [
-
El.txt "Resize your browser window to see responsive changes. The indicator in the top-right shows the current breakpoint."
-
];
-
-
(* Responsive Grid *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Responsive Grid"];
-
-
El.p ~at:[classes_attr (Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
]); At.class' "mb-4"] [
-
El.txt "1 column → 2 columns (md) → 3 columns (lg) → 4 columns (xl)"
-
];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Display.grid;
-
Grid.(to_class (template_cols (`Cols 1)));
-
Responsive.(to_class (at_breakpoint `Md (Grid.(to_class (template_cols (`Cols 2))))));
-
Responsive.(to_class (at_breakpoint `Lg (Grid.(to_class (template_cols (`Cols 3))))));
-
Responsive.(to_class (at_breakpoint `Xl (Grid.(to_class (template_cols (`Cols 4))))));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
])] (List.init 8 (fun i ->
-
let colors = [|
-
Color.make `Blue ~variant:`V100 ();
-
Color.make `Green ~variant:`V100 ();
-
Color.make `Purple ~variant:`V100 ();
-
Color.make `Red ~variant:`V100 ();
-
Color.make `Yellow ~variant:`V100 ();
-
|] in
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg colors.(i mod (Array.length colors));
-
Spacing.(to_class (p (Size.rem 1.5)));
-
]); At.class' "rounded-lg text-center"] [
-
El.txt (Printf.sprintf "Item %d" (i + 1))
-
]
-
));
-
];
+
p ~styles:[
+
font_size `Lg;
+
text_color (gray 600);
+
text_center;
+
margin_bottom (rem 3.0);
+
] [txt "Adaptive layouts using GADT interface"];
-
(* Responsive Typography *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Responsive Typography"];
+
(* Mobile-first card grid *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Responsive Card Grid"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
]); At.class' "rounded-lg text-center"] [
-
El.h3 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Base));
-
Responsive.(to_class (at_breakpoint `Md (Typography.(to_class (font_size `Lg)))));
-
Responsive.(to_class (at_breakpoint `Lg (Typography.(to_class (font_size `Xl2)))));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
]); At.class' "mb-4"] [El.txt "Responsive Heading"];
+
(* Using CSS Grid - starts as 1 column on mobile, would be 3 columns on larger screens *)
+
div ~styles:[
+
grid;
+
grid_cols 1; (* Mobile: 1 column, but ideally would be responsive *)
+
gap (rem 1.5);
+
] [
+
(* Card 1 *)
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (blue 600);
+
margin_bottom (rem 1.0);
+
] [txt "Card 1"];
+
p ~styles:[text_color (gray 600)] [
+
txt "This card stacks vertically on mobile and forms a grid on larger screens."
+
];
+
];
-
El.p ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Sm));
-
Responsive.(to_class (at_breakpoint `Md (Typography.(to_class (font_size `Base)))));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
])] [
-
El.txt "This text scales: small on mobile, base on tablet, and larger on desktop. The heading above also scales responsively."
+
(* Card 2 *)
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (green 600);
+
margin_bottom (rem 1.0);
+
] [txt "Card 2"];
+
p ~styles:[text_color (gray 600)] [
+
txt "Responsive design ensures optimal viewing across all devices."
+
];
+
];
+
+
(* Card 3 *)
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (purple 600);
+
margin_bottom (rem 1.0);
+
] [txt "Card 3"];
+
p ~styles:[text_color (gray 600)] [
+
txt "Mobile-first approach with progressive enhancement."
+
];
];
];
];
-
(* Show/Hide Elements *)
-
El.section ~at:[At.class' "mb-8"] [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Responsive Visibility"];
+
(* Responsive navigation *)
+
section ~styles:[margin_bottom (rem 3.0)] [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Responsive Navigation"];
-
El.div ~at:[classes_attr (Css.tw [
-
Display.flex;
-
Flexbox.(to_class (direction `Col));
-
Responsive.(to_class (at_breakpoint `Md (Flexbox.(to_class (direction `Row)))));
-
Spacing.(to_class (gap `All (Size.rem 1.0)));
-
])] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Blue ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
]); At.class' "rounded-lg text-center"] [
-
El.txt "Always visible"
-
];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Green ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Display.hidden;
-
Responsive.(to_class (at_breakpoint `Md Display.block));
-
]); At.class' "rounded-lg text-center"] [
-
El.txt "Hidden on mobile, visible on md+"
-
];
-
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Purple ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Display.hidden;
-
Responsive.(to_class (at_breakpoint `Lg Display.block));
-
]); At.class' "rounded-lg text-center"] [
-
El.txt "Only visible on lg+"
+
nav ~styles:[
+
bg_color (Tailwind.Color.white);
+
padding (rem 1.0);
+
rounded `Lg;
+
shadow `Md;
+
] [
+
div ~styles:[
+
flex;
+
flex_col;
+
] [
+
a ~styles:[
+
padding (rem 0.75);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#" [txt "Home"];
+
+
a ~styles:[
+
padding (rem 0.75);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#" [txt "About"];
+
+
a ~styles:[
+
padding (rem 0.75);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#" [txt "Services"];
+
+
a ~styles:[
+
padding (rem 0.75);
+
text_color (gray 700);
+
font_weight `Medium;
+
] ~href:"#" [txt "Contact"];
];
];
];
-
(* Responsive Spacing *)
-
El.section [
-
El.h2 ~at:[classes_attr (Css.tw [
-
Typography.(to_class (font_size `Xl));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V700 ());
-
]); At.class' "mb-6"] [El.txt "Responsive Spacing"];
+
(* Responsive text *)
+
section [
+
h2 ~styles:[
+
font_size `Xl;
+
font_weight `Semibold;
+
text_color (gray 700);
+
margin_bottom (rem 2.0);
+
] [txt "Responsive Typography"];
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 1.0)));
-
Responsive.(to_class (at_breakpoint `Md (Spacing.(to_class (p (Size.rem 1.5))))));
-
Responsive.(to_class (at_breakpoint `Lg (Spacing.(to_class (p (Size.rem 2.0))))));
-
]); At.class' "rounded-lg"] [
-
El.div ~at:[classes_attr (Css.tw [
-
Color.bg Color.white;
-
Spacing.(to_class (p (Size.rem 1.0)));
-
]); At.class' "rounded"] [
-
El.p [El.txt "This container has responsive padding:"];
-
El.ul [
-
El.li [El.txt "p-4 (1rem) on mobile"];
-
El.li [El.txt "md:p-6 (1.5rem) on tablet"];
-
El.li [El.txt "lg:p-8 (2rem) on desktop"];
-
];
-
];
+
card [
+
h3 ~styles:[
+
font_size `Lg;
+
font_weight `Semibold;
+
text_color (gray 800);
+
margin_bottom (rem 1.0);
+
] [txt "Adaptive Text Sizes"];
+
+
p ~styles:[
+
font_size `Base;
+
text_color (gray 600);
+
margin_bottom (rem 1.0);
+
] [txt "This text adapts its size based on the viewport width."];
+
+
p ~styles:[
+
font_size `Sm;
+
text_color (gray 500);
+
] [txt "Smaller supporting text that remains readable on all devices."];
];
];
];
];
] in
-
-
let html_string = El.to_string ~doctype:true html_doc in
-
print_string html_string
+
html
-
let () = create_responsive_demo ()
+
let () =
+
let html = create_responsive_demo () in
+
print_string (El.to_string ~doctype:true html)
-69
examples/type_safety_test.ml
···
-
(* Type Safety Test - Demonstrating GADT constraints *)
-
-
open Htmlit
-
open Tailwind_html
-
-
(* Valid usage - each property category appears at most once *)
-
let valid_styles = [
-
text_color (blue 600); (* ✅ Text color *)
-
bg_color (gray 100); (* ✅ Background color *)
-
font_size `Xl2; (* ✅ Font size *)
-
font_weight `Bold; (* ✅ Font weight *)
-
margin_bottom (rem 1.0); (* ✅ Margin *)
-
padding (rem 1.5); (* ✅ Padding *)
-
rounded `Lg; (* ✅ Border radius *)
-
shadow `Md; (* ✅ Shadow *)
-
]
-
-
(* This would cause a type error if uncommented: *)
-
(* let invalid_styles = [
-
text_color (blue 600);
-
text_color (red 500); (* ❌ Cannot have two text colors! *)
-
] *)
-
-
let create_type_safety_demo () =
-
let html = El.html [
-
El.head [
-
El.meta ~at:[At.charset "utf-8"] ();
-
El.title [txt "Type Safety Test"];
-
];
-
-
El.body [
-
h1_styled ~styles:valid_styles [
-
txt "✅ Type-Safe Tailwind with GADTs"
-
];
-
-
p_gadt ~styles:[
-
text_color (gray 600);
-
font_size `Base;
-
margin_bottom (rem 2.0);
-
] [
-
txt "This demonstrates that each property category can only appear once, ";
-
txt "preventing styling conflicts at compile time!"
-
];
-
-
div_styled ~styles:[
-
bg_color (green 50);
-
padding (rem 2.0);
-
rounded `Md;
-
] [
-
h2_styled ~styles:[
-
text_color (green 700);
-
font_weight `Semibold;
-
margin_bottom (rem 1.0);
-
] [txt "🎯 Type Safety Features"];
-
-
El.ul [
-
El.li [txt "✅ Each property category (color, size, spacing) appears at most once"];
-
El.li [txt "✅ Compile-time prevention of styling conflicts"];
-
El.li [txt "✅ Clean, readable heterogeneous list syntax"];
-
El.li [txt "✅ Full type inference and autocomplete support"];
-
];
-
];
-
];
-
] in
-
html
-
-
let () =
-
let html = create_type_safety_demo () in
-
print_string (El.to_string ~doctype:true html)
+18
lib/tailwind-html/tailwind_html.ml
···
| Max_width : Tailwind.Size.t -> [`Width] tw_prop
| Min_height : Tailwind.Size.t -> [`Height] tw_prop
| Display_flex : [`Layout] tw_prop
+
| Display_grid : [`Layout] tw_prop
| Display_block : [`Layout] tw_prop
| Display_inline : [`Layout] tw_prop
| Display_inline_block : [`Layout] tw_prop
+
| Grid_cols : int -> [`Grid] tw_prop
+
| Grid_rows : int -> [`Grid] tw_prop
+
| Gap : Tailwind.Size.t -> [`Grid] tw_prop
+
| Gap_x : Tailwind.Size.t -> [`Grid] tw_prop
+
| Gap_y : Tailwind.Size.t -> [`Grid] tw_prop
| Items_center : [`Layout] tw_prop
| Items_start : [`Layout] tw_prop
| Items_end : [`Layout] tw_prop
···
| Max_width size -> Tailwind.Layout.(to_class (max_width size))
| Min_height size -> Tailwind.Layout.(to_class (min_height size))
| Display_flex -> Tailwind.Display.flex
+
| Display_grid -> Tailwind.Display.grid
| Display_block -> Tailwind.Display.block
| Display_inline -> Tailwind.Display.inline
| Display_inline_block -> Tailwind.Display.inline_block
+
| Grid_cols n -> Tailwind.Grid.(to_class (template_cols (`Cols n)))
+
| Grid_rows n -> Tailwind.Grid.(to_class (template_rows (`Rows n)))
+
| Gap size -> Tailwind.Spacing.(to_class (gap `All size))
+
| Gap_x size -> Tailwind.Spacing.(to_class (gap `X size))
+
| Gap_y size -> Tailwind.Spacing.(to_class (gap `Y size))
| Items_center -> Tailwind.Flexbox.(to_class (align_items `Center))
| Items_start -> Tailwind.Flexbox.(to_class (align_items `Start))
| Items_end -> Tailwind.Flexbox.(to_class (align_items `End))
···
let max_width s = Any (Max_width s)
let min_height s = Any (Min_height s)
let flex = Any Display_flex
+
let grid = Any Display_grid
let block = Any Display_block
let inline = Any Display_inline
let inline_block = Any Display_inline_block
+
let grid_cols n = Any (Grid_cols n)
+
let grid_rows n = Any (Grid_rows n)
+
let gap s = Any (Gap s)
+
let gap_x s = Any (Gap_x s)
+
let gap_y s = Any (Gap_y s)
let items_center = Any Items_center
let items_start = Any Items_start
let items_end = Any Items_end
+12
lib/tailwind-html/tailwind_html.mli
···
| Max_width : Tailwind.Size.t -> [`Width] tw_prop
| Min_height : Tailwind.Size.t -> [`Height] tw_prop
| Display_flex : [`Layout] tw_prop
+
| Display_grid : [`Layout] tw_prop
| Display_block : [`Layout] tw_prop
| Display_inline : [`Layout] tw_prop
| Display_inline_block : [`Layout] tw_prop
+
| Grid_cols : int -> [`Grid] tw_prop
+
| Grid_rows : int -> [`Grid] tw_prop
+
| Gap : Tailwind.Size.t -> [`Grid] tw_prop
+
| Gap_x : Tailwind.Size.t -> [`Grid] tw_prop
+
| Gap_y : Tailwind.Size.t -> [`Grid] tw_prop
| Items_center : [`Layout] tw_prop
| Items_start : [`Layout] tw_prop
| Items_end : [`Layout] tw_prop
···
val max_width : Tailwind.Size.t -> tw_list_item
val min_height : Tailwind.Size.t -> tw_list_item
val flex : tw_list_item
+
val grid : tw_list_item
val block : tw_list_item
val inline : tw_list_item
val inline_block : tw_list_item
+
val grid_cols : int -> tw_list_item
+
val grid_rows : int -> tw_list_item
+
val gap : Tailwind.Size.t -> tw_list_item
+
val gap_x : Tailwind.Size.t -> tw_list_item
+
val gap_y : Tailwind.Size.t -> tw_list_item
val items_center : tw_list_item
val items_start : tw_list_item
val items_end : tw_list_item