Tailwind classes in OCaml

Redesign Tailwind_html with succinct Htmlit-style combinators

Transform verbose Tailwind class construction into concise, type-safe combinators:
- Add utility functions: blue 600, gray 50, rem 1.0, txt "text"
- Add utility classes: flex, items_center, font_bold, rounded_lg
- Add enhanced elements: h1/h2/p_styled with styling parameters
- Add simple components: container, card, btn_primary, btn_secondary
- Remove module re-exports from Tailwind (use Tailwind directly)
- Update hello_tailwind example to demonstrate new succinct API
- Add button_demo example showcasing before/after comparison

Reduces ~10 lines of verbose class construction to 1 line:
h1 ~size:\`Xl2 ~weight:\`Bold ~color:(blue 600) [txt "Hello\!"]

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

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

Changed files
+448 -136
examples
lib
+127
examples/button_demo.ml
···
+
(* Button Demo - Showcasing new button combinators *)
+
+
open Htmlit
+
open Tailwind_html
+
+
let create_button_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 "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)));
+
])] [
+
container [
+
h1 ~size:`Xl3 ~weight:`Bold ~color:(gray 800) ~align:`Center ~mb:(rem 2.0) [
+
txt "Button Combinator 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"
+
];
+
+
(* 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"];
+
];
+
];
+
+
(* 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"];
+
];
+
];
+
+
(* 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!"]|}];
+
];
+
];
+
];
+
];
+
];
+
];
+
];
+
] in
+
html
+
+
let () =
+
let html = create_button_demo () in
+
print_string (El.to_string ~doctype:true html)
+64 -108
examples/hello_tailwind_01.ml
···
(* Example 01: Hello Tailwind - Your First Tailwind OCaml Program *)
open Htmlit
-
open Tailwind
-
-
let classes_attr tailwind_classes =
-
At.class' @@ Tailwind.to_string tailwind_classes
+
open Tailwind_html
let create_page () =
-
let hello_classes = 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)));
-
] in
-
-
let body_classes = Css.tw [
-
Layout.(to_class (min_height Size.screen));
-
Color.bg (Color.make `Gray ~variant:`V50 ());
-
Display.flex;
-
Flexbox.(to_class (align_items `Center));
-
Flexbox.(to_class (justify `Center));
-
Spacing.(to_class (p (Size.rem 2.0)));
-
] in
-
-
let container_classes = Css.tw [
-
Spacing.(to_class (mx `Auto));
-
Typography.(to_class (text_align `Center));
-
Spacing.(to_class (px (Size.rem 1.0)));
-
] in
-
-
let paragraph_classes = Css.tw [
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
Spacing.(to_class (mb (Size.rem 1.5)));
-
] in
-
-
let card_classes = Css.tw [
-
Color.bg Color.white;
-
Effects.rounded_lg;
-
Effects.shadow_sm;
-
Spacing.(to_class (p (Size.rem 1.5)));
-
Typography.(to_class (text_align `Left));
-
] in
-
-
let subheading_classes = Css.tw [
-
Typography.(to_class (font_size `Lg));
-
Typography.(to_class (font_weight `Semibold));
-
Color.text (Color.make `Gray ~variant:`V800 ());
-
Spacing.(to_class (mb (Size.rem 0.75)));
-
] in
-
-
let code_block_classes = Css.tw [
-
Color.bg (Color.make `Gray ~variant:`V100 ());
-
Spacing.(to_class (p (Size.rem 0.75)));
-
Effects.rounded_sm;
-
Typography.(to_class (font_size `Sm));
-
Layout.(to_class (overflow `X `Auto));
-
] in
-
-
let code_classes = Css.tw [
-
Color.text (Color.make `Blue ~variant:`V600 ());
-
] in
-
-
let section_classes = Css.tw [
-
Spacing.(to_class (mt (Size.rem 2.0)));
-
Spacing.(to_class (gap `Y (Size.rem 1.0)));
-
] in
-
-
let list_classes = Css.tw [
-
Typography.(to_class (text_align `Left));
-
Spacing.(to_class (gap `Y (Size.rem 0.5)));
-
Color.text (Color.make `Gray ~variant:`V600 ());
-
] in
-
-
let list_item_classes = Css.tw [
-
Display.flex;
-
Flexbox.(to_class (align_items `Start));
-
] in
-
-
let checkmark_classes = Css.tw [
-
Color.text (Color.make `Green ~variant:`V500 ());
-
Spacing.(to_class (mr (Size.rem 0.5)));
-
] in
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 "Hello Tailwind"];
+
El.title [txt "Hello Tailwind"];
El.link ~at:[At.rel "stylesheet"; At.href "hello_tailwind_01.css"] ();
];
-
El.body ~at:[classes_attr body_classes] [
-
El.div ~at:[classes_attr container_classes] [
-
El.h1 ~at:[classes_attr hello_classes] [
-
El.txt "Hello, Tailwind OCaml!"
+
El.body ~at:[classes_attr (Tailwind.Css.tw [
+
Tailwind.Layout.(to_class (min_height screen));
+
Tailwind.Color.bg (gray 50);
+
flex;
+
items_center;
+
justify_center;
+
Tailwind.Spacing.(to_class (p (rem 2.0)));
+
])] [
+
container [
+
h1 ~size:`Xl2 ~weight:`Bold ~color:(blue 600) ~mb:(rem 1.0) [
+
txt "Hello, Tailwind OCaml!"
];
-
El.p ~at:[classes_attr paragraph_classes] [
-
El.txt "This is your first Tailwind OCaml program. ";
-
El.txt "The heading above uses type-safe Tailwind classes."
+
p_styled ~color:(gray 600) ~mb:(rem 1.5) [
+
txt "This is your first Tailwind OCaml program. ";
+
txt "The heading above uses type-safe Tailwind classes."
];
-
El.div ~at:[classes_attr card_classes] [
-
El.h2 ~at:[classes_attr subheading_classes] [
-
El.txt "Generated Classes:"
+
card [
+
h2 ~size:`Lg ~weight:`Semibold ~color:(gray 800) ~mb:(rem 0.75) [
+
txt "Generated Classes:"
];
-
El.pre ~at:[classes_attr code_block_classes] [
-
El.code ~at:[classes_attr code_classes] [
-
El.txt (to_string hello_classes)
+
El.pre ~at:[classes_attr (Tailwind.Css.tw [
+
Tailwind.Color.bg (gray 100);
+
Tailwind.Spacing.(to_class (p (rem 0.75)));
+
Tailwind.Effects.rounded_sm;
+
Tailwind.Typography.(to_class (font_size `Sm));
+
Tailwind.Layout.(to_class (overflow `X `Auto));
+
])] [
+
El.code ~at:[classes_attr (Tailwind.Css.tw [
+
Tailwind.Color.text (blue 600);
+
])] [
+
txt "text-blue-600 text-2xl font-bold mb-4"
];
];
];
-
El.div ~at:[classes_attr section_classes] [
-
El.h3 ~at:[classes_attr subheading_classes] [
-
El.txt "What you're learning:"
+
div ~classes:(Tailwind.Css.tw [
+
Tailwind.Spacing.(to_class (mt (rem 2.0)));
+
]) [
+
h2 ~size:`Lg ~weight:`Semibold ~color:(gray 700) ~mb:(rem 1.5) [
+
txt "What you're learning:"
];
-
El.ul ~at:[classes_attr list_classes] [
-
El.li ~at:[classes_attr list_item_classes] [
-
El.span ~at:[classes_attr checkmark_classes] [El.txt "✓"];
-
El.txt "Using the `tw` function to compose Tailwind classes"
+
ul ~classes:(Tailwind.Css.tw [
+
Tailwind.Typography.(to_class (text_align `Left));
+
Tailwind.Spacing.(to_class (gap `Y (rem 0.5)));
+
Tailwind.Color.text (gray 600);
+
]) [
+
li ~classes:(Tailwind.Css.tw [flex; Tailwind.Flexbox.(to_class (align_items `Start))]) [
+
span ~classes:(Tailwind.Css.tw [
+
Tailwind.Color.text (green 500);
+
Tailwind.Spacing.(to_class (mr (rem 0.5)));
+
]) [txt "✓"];
+
txt "Using succinct combinator functions"
];
-
El.li ~at:[classes_attr list_item_classes] [
-
El.span ~at:[classes_attr checkmark_classes] [El.txt "✓"];
-
El.txt "Type-safe color creation with variants"
+
li ~classes:(Tailwind.Css.tw [flex; Tailwind.Flexbox.(to_class (align_items `Start))]) [
+
span ~classes:(Tailwind.Css.tw [
+
Tailwind.Color.text (green 500);
+
Tailwind.Spacing.(to_class (mr (rem 0.5)));
+
]) [txt "✓"];
+
txt "Type-safe color creation with simple functions"
];
-
El.li ~at:[classes_attr list_item_classes] [
-
El.span ~at:[classes_attr checkmark_classes] [El.txt "✓"];
-
El.txt "Typography utilities for font size and weight"
+
li ~classes:(Tailwind.Css.tw [flex; Tailwind.Flexbox.(to_class (align_items `Start))]) [
+
span ~classes:(Tailwind.Css.tw [
+
Tailwind.Color.text (green 500);
+
Tailwind.Spacing.(to_class (mr (rem 0.5)));
+
]) [txt "✓"];
+
txt "Enhanced element functions with styling parameters"
];
-
El.li ~at:[classes_attr list_item_classes] [
-
El.span ~at:[classes_attr checkmark_classes] [El.txt "✓"];
-
El.txt "Converting Tailwind classes to HTML attributes"
+
li ~classes:(Tailwind.Css.tw [flex; Tailwind.Flexbox.(to_class (align_items `Start))]) [
+
span ~classes:(Tailwind.Css.tw [
+
Tailwind.Color.text (green 500);
+
Tailwind.Spacing.(to_class (mr (rem 0.5)));
+
]) [txt "✓"];
+
txt "Automatic class-to-attribute conversion"
];
];
];
+181 -14
lib/tailwind-html/tailwind_html.ml
···
(* Main module for Tailwind HTML library *)
-
(* Re-export all submodules *)
-
module Component = Component
-
module Button = Button
-
module Card = Card
-
module Form = Form
-
module Layout = Layout
-
module Cli = Cli
-
(* Common utility for converting Tailwind classes to HTML class attribute *)
let classes_attr tailwind_classes =
Htmlit.At.class' (Tailwind.to_string tailwind_classes)
···
let img ?classes ?attributes ~src ~alt () =
let attrs = match attributes with Some a -> a | None -> [] in
el "img" ?classes ~attributes:(("src", src) :: ("alt", alt) :: attrs) []
-
let h1 ?classes ?attributes children = el "h1" ?classes ?attributes children
-
let h2 ?classes ?attributes children = el "h2" ?classes ?attributes children
-
let h3 ?classes ?attributes children = el "h3" ?classes ?attributes children
-
let h4 ?classes ?attributes children = el "h4" ?classes ?attributes children
-
let h5 ?classes ?attributes children = el "h5" ?classes ?attributes children
-
let h6 ?classes ?attributes children = el "h6" ?classes ?attributes children
let ul ?classes ?attributes children = el "ul" ?classes ?attributes children
let ol ?classes ?attributes children = el "ol" ?classes ?attributes children
let li ?classes ?attributes children = el "li" ?classes ?attributes children
+
+
(* Utility functions for colors and sizes *)
+
let blue variant = Tailwind.Color.make `Blue ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
| _ -> `V600) ()
+
+
let gray variant = Tailwind.Color.make `Gray ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
| _ -> `V600) ()
+
+
let red variant = Tailwind.Color.make `Red ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
| _ -> `V600) ()
+
+
let green variant = Tailwind.Color.make `Green ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
| _ -> `V600) ()
+
+
let rem f = Tailwind.Size.rem f
+
let px = Tailwind.Size.px
+
let zero = Tailwind.Size.zero
+
let auto = Tailwind.Size.auto
+
let full = Tailwind.Size.full
+
let screen = Tailwind.Size.screen
+
let txt s = Htmlit.El.txt s
+
+
(* Common utility classes *)
+
let flex = Tailwind.Display.flex
+
let flex_col = Tailwind.Flexbox.(to_class (direction `Col))
+
let items_center = Tailwind.Flexbox.(to_class (align_items `Center))
+
let justify_center = Tailwind.Flexbox.(to_class (justify `Center))
+
let justify_between = Tailwind.Flexbox.(to_class (justify `Between))
+
let font_bold = Tailwind.Typography.(to_class (font_weight `Bold))
+
let font_semibold = Tailwind.Typography.(to_class (font_weight `Semibold))
+
let text_center = Tailwind.Typography.(to_class (text_align `Center))
+
let w_full = Tailwind.Layout.w_full
+
let h_full = Tailwind.Layout.h_full
+
let rounded_lg = Tailwind.Effects.rounded_lg
+
let rounded_md = Tailwind.Effects.rounded_md
+
let shadow_md = Tailwind.Effects.shadow_md
+
let shadow_lg = Tailwind.Effects.shadow_lg
+
+
(* Enhanced element functions with styling parameters *)
+
let h1 ?size ?weight ?color ?align ?mb ?classes children =
+
let base_styles = [Tailwind.Typography.(to_class (font_size `Xl2)); font_bold] in
+
let size_styles = match size with
+
| Some `Xl -> [Tailwind.Typography.(to_class (font_size `Xl))]
+
| Some `Xl2 -> [Tailwind.Typography.(to_class (font_size `Xl2))]
+
| Some `Xl3 -> [Tailwind.Typography.(to_class (font_size `Xl3))]
+
| Some `Xl4 -> [Tailwind.Typography.(to_class (font_size `Xl4))]
+
| None -> []
+
in
+
let weight_styles = match weight with
+
| Some `Bold -> [font_bold]
+
| Some `Semibold -> [font_semibold]
+
| Some `Medium -> [Tailwind.Typography.(to_class (font_weight `Medium))]
+
| None -> []
+
in
+
let color_styles = match color with Some c -> [Tailwind.Color.text c] | None -> [] in
+
let align_styles = match align with
+
| Some `Center -> [text_center]
+
| Some `Left -> [Tailwind.Typography.(to_class (text_align `Left))]
+
| Some `Right -> [Tailwind.Typography.(to_class (text_align `Right))]
+
| None -> []
+
in
+
let spacing_styles = match mb with Some s -> [Tailwind.Spacing.(to_class (mb s))] | None -> [] in
+
let final_classes = Tailwind.Css.tw (base_styles @ size_styles @ weight_styles @ color_styles @ align_styles @ spacing_styles @
+
(match classes with Some c -> [c] | None -> [])) in
+
Htmlit.El.h1 ~at:[classes_attr final_classes] children
+
+
let h2 ?size ?weight ?color ?align ?mb ?classes children =
+
let base_styles = [Tailwind.Typography.(to_class (font_size `Xl)); font_semibold] in
+
let size_styles = match size with
+
| Some `Lg -> [Tailwind.Typography.(to_class (font_size `Lg))]
+
| Some `Xl -> [Tailwind.Typography.(to_class (font_size `Xl))]
+
| Some `Xl2 -> [Tailwind.Typography.(to_class (font_size `Xl2))]
+
| None -> []
+
in
+
let weight_styles = match weight with
+
| Some `Bold -> [font_bold]
+
| Some `Semibold -> [font_semibold]
+
| Some `Medium -> [Tailwind.Typography.(to_class (font_weight `Medium))]
+
| None -> []
+
in
+
let color_styles = match color with Some c -> [Tailwind.Color.text c] | None -> [] in
+
let align_styles = match align with
+
| Some `Center -> [text_center]
+
| Some `Left -> [Tailwind.Typography.(to_class (text_align `Left))]
+
| Some `Right -> [Tailwind.Typography.(to_class (text_align `Right))]
+
| None -> []
+
in
+
let spacing_styles = match mb with Some s -> [Tailwind.Spacing.(to_class (mb s))] | None -> [] in
+
let final_classes = Tailwind.Css.tw (base_styles @ size_styles @ weight_styles @ color_styles @ align_styles @ spacing_styles @
+
(match classes with Some c -> [c] | None -> [])) in
+
Htmlit.El.h2 ~at:[classes_attr final_classes] children
+
+
let p_styled ?size ?color ?align ?mb ?classes children =
+
let base_styles = [Tailwind.Typography.(to_class (font_size `Base))] in
+
let size_styles = match size with
+
| Some `Sm -> [Tailwind.Typography.(to_class (font_size `Sm))]
+
| Some `Base -> [Tailwind.Typography.(to_class (font_size `Base))]
+
| Some `Lg -> [Tailwind.Typography.(to_class (font_size `Lg))]
+
| None -> []
+
in
+
let color_styles = match color with Some c -> [Tailwind.Color.text c] | None -> [] in
+
let align_styles = match align with
+
| Some `Center -> [text_center]
+
| Some `Left -> [Tailwind.Typography.(to_class (text_align `Left))]
+
| Some `Right -> [Tailwind.Typography.(to_class (text_align `Right))]
+
| None -> []
+
in
+
let spacing_styles = match mb with Some s -> [Tailwind.Spacing.(to_class (mb s))] | None -> [] in
+
let final_classes = Tailwind.Css.tw (base_styles @ size_styles @ color_styles @ align_styles @ spacing_styles @
+
(match classes with Some c -> [c] | None -> [])) in
+
Htmlit.El.p ~at:[classes_attr final_classes] children
+
+
(* Simple component functions *)
+
let container children =
+
let container_classes = Tailwind.Css.tw [Tailwind.Patterns.container ()] in
+
div ~classes:container_classes children
+
+
let flex_center children =
+
let flex_classes = Tailwind.Css.tw [flex; items_center; justify_center] in
+
div ~classes:flex_classes children
+
+
let card ?elevated ?padding children =
+
let base_classes = [Tailwind.Color.bg Tailwind.Color.white; rounded_lg] in
+
let shadow_classes = if elevated = Some true then [shadow_lg] else [Tailwind.Effects.shadow_sm] in
+
let padding_classes = if padding <> Some false then [Tailwind.Spacing.(to_class (p (rem 1.5)))] else [] in
+
let card_classes = Tailwind.Css.tw (base_classes @ shadow_classes @ padding_classes) in
+
div ~classes:card_classes children
+
+
let btn_primary ?size ?disabled children =
+
let base_classes = [
+
flex; items_center; justify_center; rounded_md;
+
Tailwind.Typography.(to_class (font_size `Sm));
+
Tailwind.Typography.(to_class (font_weight `Medium));
+
Tailwind.Color.bg (blue 600);
+
Tailwind.Color.text Tailwind.Color.white;
+
Tailwind.Variants.hover (Tailwind.Color.bg (blue 700));
+
Tailwind.Effects.transition `Colors;
+
] in
+
let size_classes = match size with
+
| Some `Sm -> [Tailwind.Spacing.(to_class (px (rem 0.75))); Tailwind.Spacing.(to_class (py (rem 0.375)))]
+
| Some `Lg -> [Tailwind.Spacing.(to_class (px (rem 2.0))); Tailwind.Spacing.(to_class (py (rem 0.75)))]
+
| _ -> [Tailwind.Spacing.(to_class (px (rem 1.0))); Tailwind.Spacing.(to_class (py (rem 0.5)))]
+
in
+
let disabled_classes = if disabled = Some true then [
+
Tailwind.Css.make "disabled:opacity-50";
+
Tailwind.Css.make "disabled:cursor-not-allowed"
+
] else [] in
+
let btn_classes = Tailwind.Css.tw (base_classes @ size_classes @ disabled_classes) in
+
let attrs = [classes_attr btn_classes] @ (if disabled = Some true then [Htmlit.At.disabled] else []) in
+
Htmlit.El.button ~at:attrs children
+
+
let btn_secondary ?size ?disabled children =
+
let base_classes = [
+
flex; items_center; justify_center; rounded_md;
+
Tailwind.Typography.(to_class (font_size `Sm));
+
Tailwind.Typography.(to_class (font_weight `Medium));
+
Tailwind.Color.bg (gray 200);
+
Tailwind.Color.text (gray 900);
+
Tailwind.Variants.hover (Tailwind.Color.bg (gray 300));
+
Tailwind.Effects.transition `Colors;
+
] in
+
let size_classes = match size with
+
| Some `Sm -> [Tailwind.Spacing.(to_class (px (rem 0.75))); Tailwind.Spacing.(to_class (py (rem 0.375)))]
+
| Some `Lg -> [Tailwind.Spacing.(to_class (px (rem 2.0))); Tailwind.Spacing.(to_class (py (rem 0.75)))]
+
| _ -> [Tailwind.Spacing.(to_class (px (rem 1.0))); Tailwind.Spacing.(to_class (py (rem 0.5)))]
+
in
+
let disabled_classes = if disabled = Some true then [
+
Tailwind.Css.make "disabled:opacity-50";
+
Tailwind.Css.make "disabled:cursor-not-allowed"
+
] else [] in
+
let btn_classes = Tailwind.Css.tw (base_classes @ size_classes @ disabled_classes) in
+
let attrs = [classes_attr btn_classes] @ (if disabled = Some true then [Htmlit.At.disabled] else []) in
+
Htmlit.El.button ~at:attrs children
(* Text element with built-in typography utilities *)
let text ?size ?weight ?color ?align ?classes text_content =
+76 -14
lib/tailwind-html/tailwind_html.mli
···
(** Main Tailwind-HTML integration module *)
-
(** Re-exported submodules *)
-
module Button : module type of Button
-
module Card : module type of Card
-
module Component : module type of Component
-
module Form : module type of Form
-
module Layout : module type of Layout
-
module Cli : module type of Cli
-
(** Convert Tailwind classes to HTML class attribute *)
val classes_attr : Tailwind.t -> Htmlit.At.t
···
val p : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
val a : ?classes:Tailwind.t -> ?attributes:(string * string) list -> href:string -> Htmlit.El.html list -> Htmlit.El.html
val img : ?classes:Tailwind.t -> ?attributes:(string * string) list -> src:string -> alt:string -> unit -> Htmlit.El.html
-
val h1 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
-
val h2 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
-
val h3 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
-
val h4 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
-
val h5 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
-
val h6 : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
val ul : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
val ol : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
val li : ?classes:Tailwind.t -> ?attributes:(string * string) list -> Htmlit.El.html list -> Htmlit.El.html
+
+
(** Utility functions for colors and sizes *)
+
val blue : int -> Tailwind.Color.t
+
val gray : int -> Tailwind.Color.t
+
val red : int -> Tailwind.Color.t
+
val green : int -> Tailwind.Color.t
+
val rem : float -> Tailwind.Size.t
+
val px : Tailwind.Size.t
+
val zero : Tailwind.Size.t
+
val auto : Tailwind.Size.t
+
val full : Tailwind.Size.t
+
val screen : Tailwind.Size.t
+
val txt : string -> Htmlit.El.html
+
+
(** Common utility classes *)
+
val flex : Tailwind.t
+
val flex_col : Tailwind.t
+
val items_center : Tailwind.t
+
val justify_center : Tailwind.t
+
val justify_between : Tailwind.t
+
val font_bold : Tailwind.t
+
val font_semibold : Tailwind.t
+
val text_center : Tailwind.t
+
val w_full : Tailwind.t
+
val h_full : Tailwind.t
+
val rounded_lg : Tailwind.t
+
val rounded_md : Tailwind.t
+
val shadow_md : Tailwind.t
+
val shadow_lg : Tailwind.t
+
+
(** Enhanced element functions with styling parameters *)
+
val h1 :
+
?size:[`Xl | `Xl2 | `Xl3 | `Xl4] ->
+
?weight:[`Bold | `Semibold | `Medium] ->
+
?color:Tailwind.Color.t ->
+
?align:[`Center | `Left | `Right] ->
+
?mb:Tailwind.Size.t ->
+
?classes:Tailwind.t ->
+
Htmlit.El.html list ->
+
Htmlit.El.html
+
+
val h2 :
+
?size:[`Lg | `Xl | `Xl2] ->
+
?weight:[`Bold | `Semibold | `Medium] ->
+
?color:Tailwind.Color.t ->
+
?align:[`Center | `Left | `Right] ->
+
?mb:Tailwind.Size.t ->
+
?classes:Tailwind.t ->
+
Htmlit.El.html list ->
+
Htmlit.El.html
+
+
val p_styled :
+
?size:[`Sm | `Base | `Lg] ->
+
?color:Tailwind.Color.t ->
+
?align:[`Center | `Left | `Right] ->
+
?mb:Tailwind.Size.t ->
+
?classes:Tailwind.t ->
+
Htmlit.El.html list ->
+
Htmlit.El.html
+
+
(** Simple component functions *)
+
val container : Htmlit.El.html list -> Htmlit.El.html
+
val flex_center : Htmlit.El.html list -> Htmlit.El.html
+
val card : ?elevated:bool -> ?padding:bool -> Htmlit.El.html list -> Htmlit.El.html
+
+
val btn_primary :
+
?size:[`Sm | `Md | `Lg] ->
+
?disabled:bool ->
+
Htmlit.El.html list ->
+
Htmlit.El.html
+
+
val btn_secondary :
+
?size:[`Sm | `Md | `Lg] ->
+
?disabled:bool ->
+
Htmlit.El.html list ->
+
Htmlit.El.html
(** Text element with typography utilities *)
val text :