Skip to content

Commit e6df70f

Browse files
committed
Integrate UI kit into ticked example
1 parent 2edc60a commit e6df70f

10 files changed

Lines changed: 310 additions & 22 deletions

File tree

examples/ticked/assets/static/ticked.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,132 @@ body {
227227
text-decoration: underline;
228228
}
229229

230+
/* Kit compatibility - BEM-style classes */
231+
.btn {
232+
display: inline-block;
233+
padding: 0.75rem 1.5rem;
234+
background-color: transparent;
235+
border: 1px solid var(--border-color);
236+
border-radius: 4px;
237+
font-size: 1rem;
238+
font-weight: 500;
239+
cursor: pointer;
240+
text-align: center;
241+
text-decoration: none;
242+
color: var(--text-color);
243+
}
244+
245+
.btn--primary {
246+
color: var(--primary-color);
247+
border-color: var(--primary-color);
248+
}
249+
250+
.btn--primary:hover {
251+
background-color: var(--primary-color);
252+
color: var(--bg-color);
253+
}
254+
255+
.btn--secondary {
256+
color: var(--text-secondary);
257+
border-color: var(--border-color);
258+
}
259+
260+
.btn--secondary:hover {
261+
border-color: var(--primary-color);
262+
color: var(--primary-color);
263+
}
264+
265+
.btn--danger {
266+
color: var(--danger-color);
267+
border-color: var(--danger-color);
268+
}
269+
270+
.btn--danger:hover {
271+
background-color: var(--danger-color);
272+
color: #FFFFFF;
273+
}
274+
275+
.btn--success {
276+
color: var(--success-color);
277+
border-color: var(--success-color);
278+
}
279+
280+
.btn--success:hover {
281+
background-color: var(--success-color);
282+
color: #FFFFFF;
283+
}
284+
285+
.btn--sm {
286+
padding: 0.5rem 1rem;
287+
font-size: 0.875rem;
288+
}
289+
290+
.btn--lg {
291+
padding: 1rem 2rem;
292+
font-size: 1.125rem;
293+
}
294+
295+
.btn:disabled, .btn--loading {
296+
opacity: 0.6;
297+
cursor: not-allowed;
298+
}
299+
300+
.btn__emoji {
301+
margin-right: 0.5rem;
302+
}
303+
304+
.btn__text {
305+
/* default styling */
306+
}
307+
308+
/* Kit chip/label compatibility */
309+
.chip, .label {
310+
display: inline-block;
311+
padding: 0.25rem 0.5rem;
312+
font-size: 0.75rem;
313+
font-weight: 500;
314+
background-color: transparent;
315+
border: 1px solid var(--border-color);
316+
color: var(--text-color);
317+
}
318+
319+
.chip {
320+
border-radius: 9999px;
321+
}
322+
323+
.label {
324+
border-radius: 4px;
325+
}
326+
327+
.chip--primary, .label--primary {
328+
border-color: var(--primary-color);
329+
color: var(--primary-color);
330+
}
331+
332+
.chip--success, .label--success {
333+
border-color: var(--success-color);
334+
color: var(--success-color);
335+
}
336+
337+
.chip--danger, .label--danger {
338+
border-color: var(--danger-color);
339+
color: var(--danger-color);
340+
}
341+
342+
.chip--warning, .label--warning {
343+
border-color: var(--warning-color);
344+
color: var(--warning-color);
345+
}
346+
347+
.chip--info, .label--info {
348+
border-color: var(--primary-color);
349+
color: var(--primary-color);
350+
}
351+
352+
.chip__emoji, .label__emoji {
353+
margin-right: 0.25rem;
354+
}
355+
230356
/* Main container */
231357
.main-container {
232358
max-width: 800px;

examples/ticked/assets/templates/admin/users.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ <h1>Users</h1>
2929
<div class="user-row">
3030
<div class="user-info">
3131
<span class="user-email">{{.Email}}</span>
32-
{{if not .Active}}<span class="badge badge-inactive">Inactive</span>{{end}}
32+
{{if not .Active}}{{with chip "Inactive"}}{{with .Danger}}{{.Render}}{{end}}{{end}}{{end}}
3333
{{range .Roles}}
34-
<span class="badge badge-role">{{.}}</span>
34+
{{with chip .}}{{with .Info}}{{.Render}}{{end}}{{end}}
3535
{{end}}
3636
</div>
3737
<div class="user-actions">
38-
<a href="/admin/get-user?id={{.ID}}" class="btn-secondary">Details</a>
38+
<a href="/admin/get-user?id={{.ID}}" class="btn btn--secondary">Details</a>
3939
</div>
4040
</div>
4141
{{else}}

examples/ticked/assets/templates/auth/signin.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ <h1>Sign In to Ticked</h1>
2727
<input type="password" id="password" name="password" required>
2828
</div>
2929

30-
<button type="submit" class="btn-primary">Sign In</button>
30+
{{with btnSubmit "Sign In"}}{{with .Primary}}{{.Render}}{{end}}{{end}}
3131
</form>
3232

3333
<p class="auth-link">

examples/ticked/assets/templates/auth/signup.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ <h1>Sign Up for Ticked</h1>
3636
<input type="password" id="confirm_password" name="confirm_password" required minlength="8">
3737
</div>
3838

39-
<button type="submit" class="btn-primary">Sign Up</button>
39+
{{with btnSubmit "Sign Up"}}{{with .Primary}}{{.Render}}{{end}}{{end}}
4040
</form>
4141

4242
<p class="auth-link">

examples/ticked/internal/web/handler_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/hatmaxkit/hatmax/auth"
1515
"github.com/hatmaxkit/hatmax/examples/ticked/internal/feat/audit"
1616
"github.com/hatmaxkit/hatmax/examples/ticked/internal/feat/list"
17+
"github.com/hatmaxkit/hatmax/kit"
1718
"github.com/hatmaxkit/hatmax/log"
1819
"github.com/hatmaxkit/hatmax/web"
1920
)
@@ -40,7 +41,7 @@ func (f *fakeAuditStore) List(ctx context.Context, limit int) ([]audit.Record, e
4041

4142
func TestHandlerRegisterRoutes(t *testing.T) {
4243
logger := log.NewTestLogger("error")
43-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
44+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
4445

4546
h := &Handler{
4647
tmpl: tmplMgr,
@@ -103,7 +104,7 @@ func TestHandleIndex(t *testing.T) {
103104

104105
func TestHandleSigninForm(t *testing.T) {
105106
logger := log.NewTestLogger("error")
106-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
107+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
107108
tmplMgr.Start(context.Background())
108109

109110
h := &Handler{
@@ -123,7 +124,7 @@ func TestHandleSigninForm(t *testing.T) {
123124

124125
func TestHandleSignupForm(t *testing.T) {
125126
logger := log.NewTestLogger("error")
126-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
127+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
127128
tmplMgr.Start(context.Background())
128129

129130
h := &Handler{
@@ -143,7 +144,7 @@ func TestHandleSignupForm(t *testing.T) {
143144

144145
func TestHandleSignin_EmptyFields(t *testing.T) {
145146
logger := log.NewTestLogger("error")
146-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
147+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
147148
tmplMgr.Start(context.Background())
148149

149150
h := &Handler{
@@ -182,7 +183,7 @@ func TestHandleSignin_EmptyFields(t *testing.T) {
182183

183184
func TestHandleSignup_EmptyFields(t *testing.T) {
184185
logger := log.NewTestLogger("error")
185-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
186+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
186187
tmplMgr.Start(context.Background())
187188

188189
h := &Handler{
@@ -263,7 +264,7 @@ func TestHandleListItems_NoUser(t *testing.T) {
263264

264265
func TestHandleListItems_WithUser(t *testing.T) {
265266
logger := log.NewTestLogger("error")
266-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
267+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
267268
tmplMgr.Start(context.Background())
268269

269270
h := &Handler{
@@ -338,7 +339,7 @@ func TestHandleAddItem_EmptyText(t *testing.T) {
338339

339340
func TestHandleAddItem_Success(t *testing.T) {
340341
logger := log.NewTestLogger("error")
341-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
342+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
342343
tmplMgr.Start(context.Background())
343344

344345
h := &Handler{
@@ -410,7 +411,7 @@ func TestHandleDeleteItem_NoUser(t *testing.T) {
410411

411412
func TestHandleDashboard(t *testing.T) {
412413
logger := log.NewTestLogger("error")
413-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
414+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
414415
tmplMgr.Start(context.Background())
415416

416417
h := &Handler{
@@ -434,7 +435,7 @@ func TestHandleDashboard(t *testing.T) {
434435

435436
func TestHandleListUsers(t *testing.T) {
436437
logger := log.NewTestLogger("error")
437-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
438+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
438439
tmplMgr.Start(context.Background())
439440

440441
h := &Handler{
@@ -482,7 +483,7 @@ func TestHandleGetUser_MissingID(t *testing.T) {
482483

483484
func TestHandleGetUser_Success(t *testing.T) {
484485
logger := log.NewTestLogger("error")
485-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
486+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
486487
tmplMgr.Start(context.Background())
487488

488489
h := &Handler{
@@ -603,7 +604,7 @@ func TestHandleToggleUser_SelfDeactivate(t *testing.T) {
603604

604605
func TestHandleListEvents(t *testing.T) {
605606
logger := log.NewTestLogger("error")
606-
tmplMgr := web.NewTemplateManager(testAssetsFS, logger)
607+
tmplMgr := web.NewTemplateManager(testAssetsFS, logger, web.WithFuncMap(kit.FuncMap()))
607608
tmplMgr.Start(context.Background())
608609

609610
h := &Handler{
Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,54 @@
1-
<html><body>users</body></html>
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>{{.Title}}</title>
7+
<link rel="stylesheet" href="/static/ticked.css">
8+
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
9+
</head>
10+
<body>
11+
<nav class="nav-container">
12+
<div class="nav-left">
13+
<a href="/list-items" class="nav-brand">Ticked</a>
14+
<a href="/admin" class="nav-link">Admin</a>
15+
</div>
16+
<div class="nav-right">
17+
<span class="nav-user">{{.UserEmail}}</span>
18+
<form hx-post="/signout" hx-target="body" hx-swap="innerHTML" style="display: inline; margin: 0;">
19+
<button type="submit" class="btn-link">Sign Out</button>
20+
</form>
21+
</div>
22+
</nav>
23+
24+
<main class="main-container">
25+
<h1>Users</h1>
26+
27+
<div class="users-list">
28+
{{range .Users}}
29+
<div class="user-row">
30+
<div class="user-info">
31+
<span class="user-email">{{.Email}}</span>
32+
{{if not .Active}}{{with chip "Inactive"}}{{with .Danger}}{{.Render}}{{end}}{{end}}{{end}}
33+
{{range .Roles}}
34+
{{with chip .}}{{with .Info}}{{.Render}}{{end}}{{end}}
35+
{{end}}
36+
</div>
37+
<div class="user-actions">
38+
<a href="/admin/get-user?id={{.ID}}" class="btn btn--secondary">Details</a>
39+
</div>
40+
</div>
41+
{{else}}
42+
<div class="empty-state">No users found.</div>
43+
{{end}}
44+
</div>
45+
46+
<div class="back-link">
47+
<a href="/admin">&larr; Back to Dashboard</a>
48+
</div>
49+
</main>
50+
51+
<button type="button" id="theme-toggle" title="Toggle theme (Alt+D)">🌙</button>
52+
<script src="/static/ticked.js"></script>
53+
</body>
54+
</html>
Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,42 @@
1-
<html><body>signin</body></html>
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>{{.Title}}</title>
7+
<link rel="stylesheet" href="/static/ticked.css">
8+
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
9+
</head>
10+
<body>
11+
<div class="auth-container">
12+
<div class="auth-card">
13+
<h1>Sign In to Ticked</h1>
14+
15+
{{if .Error}}
16+
<div class="error">{{.Error}}</div>
17+
{{end}}
18+
19+
<form hx-post="/signin" hx-target="body" hx-swap="innerHTML">
20+
<div class="form-group">
21+
<label for="email">Email</label>
22+
<input type="email" id="email" name="email" placeholder="email@example.com" required autofocus>
23+
</div>
24+
25+
<div class="form-group">
26+
<label for="password">Password</label>
27+
<input type="password" id="password" name="password" required>
28+
</div>
29+
30+
{{with btnSubmit "Sign In"}}{{with .Primary}}{{.Render}}{{end}}{{end}}
31+
</form>
32+
33+
<p class="auth-link">
34+
Don't have an account? <a href="/signup">Sign up</a>
35+
</p>
36+
</div>
37+
</div>
38+
39+
<button type="button" id="theme-toggle" title="Toggle theme (Alt+D)">🌙</button>
40+
<script src="/static/ticked.js"></script>
41+
</body>
42+
</html>

0 commit comments

Comments
 (0)