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)