aboutsummaryrefslogtreecommitdiff
path: root/module/calp/html/components.scm
blob: df30b6bca18c2634b8d712ffb8eb45be2c896548 (plain)
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
(define-module (calp html components)
  :use-module (hnh util)
  :use-module (ice-9 curried-definitions)
  :use-module (ice-9 match)
  :use-module (calp translation)
  :export (xhtml-doc
           slider-input
           btn
           include-css
           include-alt-css
           input-plus-minus
           ))

;; Wraps a number of sxml forms into a valid sxhtml-tree.
(define-syntax xhtml-doc
  (syntax-rules (@)
    ((_ (@ attr ...) body ...)
     `(*TOP*
       (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
       ,(lambda () (format #t "~%<!DOCTYPE html>~%"))
       (html (@ (xmlns "http://www.w3.org/1999/xhtml") attr ...)
             body ...)))
    ((_ body ...)
     (xhtml-doc (@) body ...))))


;; Add a slider with an associated number input. Keeps the two in sync.
(define* (slider-input key: variable
                       (min 0)
                       (max 10)
                       (step 1)
                       (value 1)
                       (unit ""))

  `(slider-input
    (@ (min ,min)
       (max ,max)
       (step ,step)
       (value ,value)
       (oninput
        ,(format #f "document.documentElement.style.setProperty('--~a', this.value + '~a')"
                 variable unit)))))


;; Takes a (flat list which may contains keywords followed by items.
;; Return a new list where each of the keyword-value pairs have been removed.
(define (remove-key-values list)
  (cond ((null? list) '())
        ((keyword? (car list)) (remove-key-values (cddr list)))
        (else (cons (car list) (remove-key-values (cdr list))))))

;; Generates a button or button-like link.
(define* (btn key: onclick href (class '())
              rest: args)
  (when (and onclick href)
    (scm-error 'wrong-type-arg "btn"
               (_ "href and onclick are mutually exclusive. href = ~s, onclick = ~s.")
               (list href onclick)
               #f))
  (let ((classes (string-join (cons "btn" class) " "))
        (body (remove-key-values args)))
    (cond (href
           `(a (@ (class ,classes)
                  (href ,href))
               ,@body))
          (onclick
           `(button (@ (class ,classes)
                       (onclick ,onclick))
                    ,@body))
          (else
           `(button (@ (class ,classes))
                    ,@body)))))


(define ((set-attribute attr) el)
  (match el
    [(tagname ('@ params ...) inner-body ...)
     `(,tagname (@ ,@(assq-merge params attr))
                ,@inner-body)]
    [(tagname inner-body ...)
     `(,tagname (@ ,attr)
                ,@inner-body)]))


(define (include-css path . extra-attributes)
  `(link (@ (type "text/css")
            (rel "stylesheet")
            (href ,path)
            ,@extra-attributes)))


(define (include-alt-css path . extra-attributes)
  `(link (@ (type "text/css")
            (rel "alternate stylesheet")
            (href ,path)
            ,@extra-attributes)))


(define (input-plus-minus positive?)
  (define id (gensym "id"))
  `(span (@ (class "input-timespan"))
         (input (@ (type "checkbox")
                   (style "display:none")
                   (class "plusminuscheck")
                   ,@(if positive? '((checked)) '())
                   (id ,id)))
         (label
          (@ (for ,id))
          (span (@ (class "plus"))  "+")
          (span (@ (class "minus")) "-"))))