Skip to content

Commit b77d61b

Browse files
haliceaclaude
andcommitted
Web sample: style with Tw.* Tailwind utilities
Tailwind's preflight resets headings, so the sample now applies explicit Tw.* classes (composed CssClass values) alongside the generated Site.* classes, which are trimmed to what Tailwind doesn't cover. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 9c9c5ef commit b77d61b

2 files changed

Lines changed: 64 additions & 48 deletions

File tree

‎samples/Web/Program.cs‎

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,58 @@
1-
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
2-
WebApplication app = builder.Build();
3-
4-
int counter = 0;
5-
// a virtual (higher-order) class: expands to "btn btn--accent"
6-
CssClass accentButton = Site.btn + Site.btnAccent;
7-
app.MapGet("/", () => Render(
8-
Master("Counter",
9-
Div(@class(Site.panel),
10-
Button("-", @class(accentButton), hxPost("/decrement", target: "#counter")),
11-
B(Label(id("counter"), @class(Site.counter), counter)),
12-
Button("+", @class(accentButton), hxPost("/increment", target: "#counter")),
13-
"|",
14-
Button("Reset", @class(Site.btn), hxPost("/reset", target: "#counter"))
15-
)
16-
)
17-
));
18-
19-
app.MapPost("increment", () => Render($"{++counter}"));
20-
app.MapPost("decrement", () => Render($"{--counter}"));
21-
app.MapPost("reset", () => Render($"{counter = 0}"));
22-
app.Run();
23-
static HtmlNode Master(string title, params HtmlNode[] content)
24-
{
25-
return Html(
26-
Meta(charset("utf-8")),
27-
Head(
28-
Title(title),
29-
Meta(charset("utf-8")),
30-
HtmxImports,
31-
CssImports.Inline(Site.Bundle),
32-
Script(src("https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"))
33-
),
34-
Body(
35-
style(fontFamily("sans-serif"), CSS.color("#333")),
36-
"how are you",
37-
H2(@class(Tw.textCenter, Tw.textSky600, Tw.fontBold, Tw.hover(Tw.underline)), "this is great"),
38-
H1(@class(Site.textCenter), title),
39-
content,
40-
Hr()
41-
)
42-
);
43-
}
1+
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
2+
WebApplication app = builder.Build();
3+
4+
int counter = 0;
5+
6+
// Tailwind utilities composed as typed CssClass values (Tw.*), plus the generated Site.* classes
7+
// from styles/site.css. Both are plain CssClass and can be mixed with `+`.
8+
CssClass button = Tw.inlineFlex + Tw.itemsCenter + Tw.justifyCenter + Tw.roundedLg + Tw.fontSemibold
9+
+ Tw.cursorPointer + Tw.transitionColors + Tw.selectNone + Tw.outlineNone + Site.btn;
10+
CssClass accentButton = button + Tw.w12 + Tw.h12 + Tw.textXl + Tw.bgIndigo600 + Tw.textWhite + Tw.hover(Tw.bgIndigo500) + Site.btnAccent;
11+
CssClass neutralButton = button + Tw.px5 + Tw.py2 + Tw.textSm + Tw.bgSlate100 + Tw.textSlate700 + Tw.hover(Tw.bgSlate200);
12+
13+
app.MapGet("/", () => Render(
14+
Master("Hello world",
15+
Div(@class(Tw.bgWhite + Tw.rounded2xl + Tw.shadowLg + Tw.p8 + Tw.maxWSm + Tw.mxAuto + Site.panel),
16+
P(@class(Tw.textXs + Tw.uppercase + Tw.trackingWider + Tw.textSlate400 + Tw.mb6 + Tw.textCenter),
17+
"htmx counter"),
18+
Div(@class(Tw.flex + Tw.itemsCenter + Tw.justifyCenter + Tw.gap4),
19+
Button("−", @class(accentButton), hxPost("/decrement", target: "#counter")),
20+
Label(id("counter"), @class(Tw.text4xl + Tw.fontBold + Tw.textSlate800 + Tw.w14 + Tw.textCenter + Site.counter), counter),
21+
Button("+", @class(accentButton), hxPost("/increment", target: "#counter"))
22+
),
23+
Div(@class(Tw.mt6 + Tw.flex + Tw.justifyCenter),
24+
Button("Reset", @class(neutralButton), hxPost("/reset", target: "#counter"))
25+
)
26+
),
27+
P(@class(Tw.mt8 + Tw.textCenter + Tw.textSm + Tw.textSlate500),
28+
"Rendered with CC.CSX · styled with ", Code(@class(Tw.fontMono + Tw.textSlate700), "Tw.*"),
29+
" and the generated ", Code(@class(Tw.fontMono + Tw.textSlate700), "Site.*"), " classes")
30+
)
31+
));
32+
33+
app.MapPost("increment", () => Render($"{++counter}"));
34+
app.MapPost("decrement", () => Render($"{--counter}"));
35+
app.MapPost("reset", () => Render($"{counter = 0}"));
36+
app.Run();
37+
38+
static HtmlNode Master(string title, params HtmlNode[] content)
39+
{
40+
return Html(lang("en"),
41+
Head(
42+
Meta(charset("utf-8")),
43+
Meta(name("viewport"), ("content", "width=device-width, initial-scale=1")),
44+
Title(title),
45+
HtmxImports,
46+
CssImports.Inline(Site.Bundle),
47+
// Dev-only Tailwind v4 browser build. Note: Tailwind's preflight resets headings
48+
// (h1 inherits font-size/weight), so give them explicit Tw.* classes.
49+
Script(src("https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"))
50+
),
51+
Body(@class(Tw.minHScreen + Tw.bgSlate50 + Tw.textSlate800 + Tw.fontSans + Tw.antialiased),
52+
Main(@class(Tw.mxAuto + Tw.maxWMd + Tw.px4 + Tw.py16),
53+
H1(@class(Tw.text4xl + Tw.fontBold + Tw.trackingTight + Tw.textCenter + Tw.mb8), title),
54+
content
55+
)
56+
)
57+
);
58+
}

‎samples/Web/styles/site.css‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
.text-center { text-align: center; }
2-
.counter { font-size: 1.5rem; padding: 0 0.5rem; }
3-
.btn { padding: 0.25rem 0.75rem; border-radius: 4px; cursor: pointer; }
4-
.btn--accent { background: #346beb; color: #fff; }
5-
.panel { max-width: 24rem; margin: 0 auto; }
1+
/* Project-specific styles that complement the Tailwind utilities (Tw.*) used in Program.cs.
2+
Compiled by the CC.CSX.Css source generator into typed `Site.*` constants. */
3+
.panel { position: relative; }
4+
.counter { font-variant-numeric: tabular-nums; }
5+
.btn:active { transform: scale(0.95); }
6+
.btn--accent { box-shadow: 0 1px 2px rgb(49 46 129 / 0.3); }

0 commit comments

Comments
 (0)