Commit9eb9a27bRecorded19 Feb 2026Repositorysigil-web-demo

refactor: Deduplicate sigil-web UI helpers and demo boilerplate

Message

Add optional-attrs utility to eliminate verbose ,@(if x ...) attribute patterns across all components. Add coerce-field-value for automatic number->string conversion in field helpers. Consolidate sg-text-field, sg-email-field, sg-password-field into thin wrappers around sg-input-field. Extract parse-page-param, not-found-page, and parse-optional-int helpers in the demo to remove duplicated logic.

Changed
 src/sigil/web/demo.sgl       | 31 +++++++++++++++----------------
 src/sigil/web/demo/db.sgl    | 22 ++++++++++++++--------
 src/sigil/web/demo/views.sgl | 12 ++----------
 3 files changed, 31 insertions(+), 34 deletions(-)
Diff
src/sigil/web/demo.sglmodified
@@ -50,6 +50,17 @@
50
(parse-form-urlencoded (http-request-query req))
51
'()))
52
+53
(define (parse-page-param params)
+54
(or (and (assoc-ref 'page params)
+55
(string->number (assoc-ref 'page params)))
+56
1))
+57
+58
(define (not-found-page)
+59
(render-page "Not Found"
+60
'(div (h1 "Record Not Found")
+61
(p "The record you're looking for doesn't exist.")
+62
(a (@ (href "/records")) "Back to collection"))))
+63
64
;; Simple validation: returns alist of errors or #f
65
(define (validate-record params)
66
(let ((errors '()))
@@ -88,9 +99,7 @@
99
(define (records-handler req)
100
(let* ((db (db-from-req req))
101
(params (parse-query-params req))
91
(page (or (and (assoc-ref 'page params)
92
(string->number (assoc-ref 'page params)))
93
1))
+102
(page (parse-page-param params))
103
(search (assoc-ref 'q params #f))
104
(per-page 10)
105
(total (count-records db search))
@@ -113,11 +122,7 @@
122
(http-response/html 200
123
(render-page (assoc-ref 'title record)
124
(record-detail-page record)))
116
(http-response/html 404
117
(render-page "Not Found"
118
'(div (h1 "Record Not Found")
119
(p "The record you're looking for doesn't exist.")
120
(a (@ (href "/records")) "Back to collection")))))))
+125
(http-response/html 404 (not-found-page)))))
126
127
(define (edit-record-handler req)
128
(let* ((db (db-from-req req))
@@ -127,11 +132,7 @@
132
(http-response/html 200
133
(render-page "Edit Record"
134
(record-form-page record #f)))
130
(http-response/html 404
131
(render-page "Not Found"
132
'(div (h1 "Record Not Found")
133
(p "The record you're looking for doesn't exist.")
134
(a (@ (href "/records")) "Back to collection")))))))
+135
(http-response/html 404 (not-found-page)))))
136
137
;; ============================================================
138
;; Action Handlers (POST/DELETE, return SSE batch)
@@ -195,9 +196,7 @@
196
(sleep 1)
197
(let* ((db (db-from-req req))
198
(params (parse-query-params req))
198
(page (or (and (assoc-ref 'page params)
199
(string->number (assoc-ref 'page params)))
200
1))
+199
(page (parse-page-param params))
200
(search (assoc-ref 'q params #f))
201
(per-page 10)
202
(total (count-records db search))
src/sigil/web/demo/db.sglmodified
@@ -73,6 +73,18 @@
73
("Disintegration" "The Cure" 1989 "Alternative" "LP")
74
("Parallel Lines" "Blondie" 1978 "Rock" "7\""))))
75
+76
;; ============================================================
+77
;; Helpers
+78
;; ============================================================
+79
+80
;; Parse an optional integer from form params.
+81
;; Returns the number or #f if missing/empty.
+82
(define (parse-optional-int params key)
+83
(let ((v (assoc-ref key params)))
+84
(if (and v (not (string=? v "")))
+85
(string->number v)
+86
#f)))
+87
88
;; ============================================================
89
;; CRUD Operations
90
;; ============================================================
@@ -112,10 +124,7 @@
124
"INSERT INTO records (title, artist, year, genre, format, notes) VALUES (?, ?, ?, ?, ?, ?)"
125
(assoc-ref 'title params)
126
(assoc-ref 'artist params)
115
(let ((y (assoc-ref 'year params)))
116
(if (and y (not (string=? y "")))
117
(string->number y)
118
#f))
+127
(parse-optional-int params 'year)
128
(assoc-ref 'genre params)
129
(or (assoc-ref 'format params) "LP")
130
(assoc-ref 'notes params))
@@ -127,10 +136,7 @@
136
"UPDATE records SET title = ?, artist = ?, year = ?, genre = ?, format = ?, notes = ? WHERE id = ?"
137
(assoc-ref 'title params)
138
(assoc-ref 'artist params)
130
(let ((y (assoc-ref 'year params)))
131
(if (and y (not (string=? y "")))
132
(string->number y)
133
#f))
+139
(parse-optional-int params 'year)
140
(assoc-ref 'genre params)
141
(or (assoc-ref 'format params) "LP")
142
(assoc-ref 'notes params)
src/sigil/web/demo/views.sglmodified
@@ -503,16 +503,8 @@
503
504
;;; Reusable record form fields.
505
(define (record-form record errors)
506
(let ((val (lambda (key)
507
(if record
508
(let ((v (assoc-ref key record #f)))
509
(cond
510
((not v) "")
511
((number? v) (number->string v))
512
(else v)))
513
"")))
514
(err (lambda (key)
515
(if errors (assoc-ref key errors #f) #f))))
+506
(let ((val (lambda (key) (and record (assoc-ref key record #f))))
+507
(err (lambda (key) (and errors (assoc-ref key errors #f)))))
508
`(div (@ (class "form-fields"))
509
,(sg-text-field name: "title"
510
value: (val 'title)