-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.cpp
More file actions
159 lines (139 loc) · 6.04 KB
/
Copy pathexample.cpp
File metadata and controls
159 lines (139 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// example.cpp — htpp.hpp with predeclared attribute keys + `_a` UDL fallback.
// Compile: clang++ -std=c++23 -Wall -Wextra -Wpedantic -o example example.cpp
#include "htpp.hpp"
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using namespace htpp::attr; // class_, id, href, aria_label, ...
using namespace htpp::attr_literals; // "data-x"_a = "..."
// ---------------------------------------------------------------------------
// Reusable components — plain functions; `os` is the first parameter.
// Attributes can appear in any order at the call site.
// ---------------------------------------------------------------------------
HT_COMPONENT_DECL(nav_link, std::string_view url);
HT_COMPONENT(nav_link, std::string_view url) {
HT_A(class_ = "px-3 py-2 hover:underline", href = url) {
HT_SLOT();
}
}
HT_COMPONENT_DECL(card, std::string_view heading);
HT_COMPONENT(card, std::string_view heading) {
HT_DIV(class_ = "rounded shadow p-4 bg-white") {
HT_H2(class_ = "text-lg font-bold mb-2") { HT_TEXT(heading); }
HT_SLOT();
}
}
// Demonstrates HT_SLOT positioned between sibling content — children land in
// the middle of the rendered output, not just at the end.
struct demo_card_props { std::string_view title; };
HT_COMPONENT_DECL(demo_card, const demo_card_props& props);
HT_COMPONENT(demo_card, const demo_card_props& props) {
HT_DIV() {
HT_H2() { HT_TEXT(props.title); }
HT_SLOT();
HT_P() { os << "Goodbye"; }
}
}
HT_COMPONENT_DECL(user_table,
const std::vector<std::pair<std::string, std::string>>& users);
HT_COMPONENT(user_table,
const std::vector<std::pair<std::string, std::string>>& users) {
HT_TABLE(class_ = "w-full border-collapse text-left") {
HT_THEAD() {
HT_TR(class_ = "bg-gray-100") {
HT_TH(class_ = "p-2 border") { os << "Name"; }
HT_TH(class_ = "p-2 border") { os << "Role"; }
}
}
HT_TBODY() {
for (auto& [user_name, user_role] : users) {
HT_TR(class_ = "hover:bg-gray-50") {
HT_TD(class_ = "p-2 border") { HT_TEXT(user_name); }
HT_TD(class_ = "p-2 border") { HT_TEXT(user_role); }
}
}
}
}
}
// ---------------------------------------------------------------------------
// Full page template
// ---------------------------------------------------------------------------
HT_COMPONENT_DECL(page, const std::string& username, bool is_submitting);
HT_COMPONENT(page, const std::string& username, bool is_submitting) {
std::vector<std::pair<std::string, std::string>> users = {
{"Alice", "Admin"},
{"Bob", "Editor"},
{"<script>xss</script>", "Attacker"}, // safely escaped by HT_TEXT
};
HT_DOCTYPE();
HT_HTML(lang = "en") {
HT_HEAD() {
HT_META(charset = "UTF-8");
HT_META(name = "viewport", content = "width=device-width, initial-scale=1");
HT_TITLE() { os << "htpp demo"; }
HT_LINK(rel = "stylesheet", href = "https://cdn.tailwindcss.com");
}
HT_BODY(class_ = "bg-gray-50 font-sans") {
HT_HEADER(class_ = "bg-blue-600 text-white p-4 flex gap-4") {
HT_USE(nav_link, "/") { HT_TEXT("Home"); }
HT_USE(nav_link, "/about") { HT_TEXT("About"); }
HT_USE(nav_link, "/logout") { HT_TEXT("Logout"); }
}
HT_MAIN(class_ = "max-w-3xl mx-auto mt-8 px-4 space-y-6") {
HT_H1(class_ = "text-2xl font-bold") {
os << "Welcome, ";
HT_TEXT(username);
os << "!";
}
HT_DIV(class_ = "grid grid-cols-2 gap-4") {
HT_USE(card, "Posts") {
HT_P(class_ = "text-gray-600") { HT_TEXT("You have 12 published posts."); }
}
HT_USE(card, "Comments") {
HT_P(class_ = "text-gray-600") { HT_TEXT("3 comments need moderation."); }
}
}
HT_SECTION() {
HT_H2(class_ = "text-xl font-semibold mb-3") { os << "User List"; }
user_table(os, users);
}
HT_SECTION(class_ = "mt-6") {
HT_H2(class_ = "text-xl font-semibold mb-3") { os << "Send a message"; }
HT_FORM(action = "/send", class_ = "space-y-3", method = "post") {
HT_LABEL(class_ = "block font-medium", for_ = "msg") {
os << "Message";
}
HT_TEXTAREA(class_ = "w-full border rounded p-2",
id = "msg",
name = "message",
rows = "4") {}
HT_BUTTON(class_ = "bg-blue-600 text-white px-4 py-2 rounded",
type = "submit",
aria_label = "Submit the message",
"data-action"_a = "send",
attr_if(is_submitting, disabled)) {
os << "Send";
}
}
}
HT_SECTION(class_ = "mt-6 text-sm text-gray-600") {
HT_LABEL(for_ = "notify") {
HT_INPUT(type = "checkbox", id = "notify", name = "notify", checked);
os << " Email me about replies";
}
}
}
}
}
}
auto main() -> int {
page(std::cout, "Alice & \"friends\"", /*is_submitting=*/false);
std::cout << '\n';
auto& os = std::cout;
HT_USE(demo_card, {.title = "Hello"}) {
HT_H3() { os << "This should end up at the HT_SLOT in the nearest HT_USE()"; }
}
std::cout << '\n';
return 0;
}