root/svg-template-discord.scm

(define-module (svg-template-discord)
  #:use-module (srfi srfi-19)
  #:use-module (sxml simple)
  #:export (svg-template-discord))

(define day-w 11)
(define day-h day-w)
(define day-p 2)

(define month-w (*  5 (+ day-p day-w)))
(define month-h (* 15 (+ day-p day-h)))
(define month-p (* 2 day-h))

(define (is-leap-year dyear)
  (let ((year (- dyear 1166)))
    (and (= 0 (remainder year 4))
         (or (not (= 0 (remainder year 100)))
             (=  0 (remainder year 400))))))

(define (month-max year) (if (is-leap-year year) 5 4))

(define (days-in-month month)
  (if (= 5 month) 1 73))

(define (translate-str x y)
  (string-append "translate("
                 (number->string x) ","
                 (number->string y) ")"))

(define (month-pos n)
  (cond ((= 0 n) (cons month-w (* month-h 0.5)))
        ((= 1 n) (cons 0 0))
        ((= 2 n) (cons 0 (+ month-p month-h)))
        ((= 3 n) (cons (* month-w 2) 0))
        ((= 4 n) (cons (* month-w 2) (+ month-p month-h)))
        ((= 5 n) (cons (* month-w 1) (* (+ month-p month-h) 1.5)))))

(define (month-week-offset n)
  (cond ((= 0 n) 0)
        ((= 1 n) 3)
        ((= 2 n) 1)
        ((= 3 n) 4)
        ((= 4 n) 2)
        ((= 5 n) 0)))

(define (generate-month month)
  (let ((x (car (month-pos month)))
        (y (cdr (month-pos month))))
    `(g (@ (transform ,(translate-str x y)) (class "month"))
        (text (@ ;; (fill "#ffffbb")
               (x ,(exact->inexact (/ month-w 2)))
               (y ,-3)
               (text-anchor "middle")
               (font-family "Courier")
               (text-decoration "line-through")
               (font-weight "bold")
               (font-size 9))
              ,(month-name month)))))

(define dayd (* 60 60 24))
(define (add-leap day season year)
  (if (and (is-leap-year year)
           (or (and (= season 0) (> day 59))
               (> season 0)))
      dayd
      0))

(define (ddate->heretic day season year)
  (time-monotonic->date
   (make-time 'time-monotonic 0
              (+ (add-leap day season year)
                 (if (= season 5)
                     (* 60 dayd)
                     (* day dayd))
                 (* 73 dayd season)
                 ;; (* 1 dayd)
                 (time-second
                  (date->time-monotonic
                   (make-date 0 0 0 0 0 1 (- year 1166) 0))))))) ;; 2lazy2doit→

(define (generate-day day month year day-details-lam)
  (let* ((mo (month-week-offset month))
         (in-week (remainder (- (+ day mo) 1) 5))
         (x (* in-week (+ day-w day-p)))
         (y (* (floor (/ (- (+ day mo) 1) 5)) (+ day-h day-p)))
         (custom (day-details-lam (ddate->heretic day month year))))
    `(g (@ (transform ,(translate-str x y)) ,(assoc 'class custom))
        ,(assoc 'title custom)
        ,(assoc 'desc custom)
        (rect (@ (height ,day-h)
                 (width ,day-w)
                 ,(assoc 'fill custom)))
        (text (@ (y ,(- day-h 1))
                 (x ,(/ day-w 2.0))
                 (font-size ,(- day-h 1)) (font-weight "bold")
                 (font-family "Courier") (text-anchor "middle") (fill "#ffaaff"))
              ,day))))

(define (generate-days month-n year day-details-lam)
  (let ((day-tags '()) ;; this code is a shit
        (days-in-m (days-in-month month-n)))
    (do ((day-n 1 (1+ day-n))) ((> day-n days-in-m))
      (let ((day-tag (generate-day day-n month-n year day-details-lam)))
        (set! day-tags (cons day-tag day-tags))
        day-tags))
    day-tags))

;; Chaos, Discord, Confusion, Bureaucracy, and The Aftermath
(define (month-name n)
  (cond ((= 0 n) "Chaos")
        ((= 1 n) "Discord")
        ((= 2 n) "Confusion")
        ((= 3 n) "Bureaucracy")
        ((= 4 n) "Aftermath")
        ((= 5 n) "Saint Tib")))

(define (generate-months year day-details-lam)
  (let ((month-tags '())) ;; this code is a shit
    (do ((month-n 0 (1+ month-n))) ((> month-n (month-max year)))
      (let* ((month-tag (generate-month month-n)))
        (set! month-tag (append month-tag (generate-days month-n year day-details-lam)))
        (set! month-tags (cons month-tag month-tags))
        month-tags))
    month-tags))

(define label-style
  `((text-anchor "end")
    (font-family "Courier")
    (font-weight "bold")
    (font-size 10)
    (text-decoration "underline")
    ))
;; Sweetmorn, Boomtime, Pungenday, Prickle-Prickle, and Setting Orange
(define (legend)
  `(g (@ (transform ,(string-append (translate-str (* 2.1 month-w) 100) " rotate(90)")))
      (text ,(append '(@) label-style `((y ,(number->string (* 4 (+ day-p day-h)))))) "Sweetmorn")
      (text ,(append '(@) label-style `((y ,(number->string (* 3 (+ day-p day-h)))))) "Boomtime")
      (text ,(append '(@) label-style `((y ,(number->string (* 2 (+ day-p day-h)))))) "Pungenday")
      (text ,(append '(@) label-style `((y ,(number->string (* 1 (+ day-p day-h)))))) "Prickle-Prickle")
      (text ,(append '(@) label-style `((y ,(number->string (* 0 (+ day-p day-h)))))) "Setting Orange")
      (text ,(append '(@) label-style `((y ,(number->string (* 5 (+ day-p day-h)))))) "0")))

(define (year-legend year)
  `(g (@ (transform ,(string-append (translate-str (* 1.5 month-w) (+ month-h (* month-p 9)))
                                    " rotate(163)")))
      (text (@ (text-anchor "end")
               (font-family "Courier")
               (font-weight "bold")
               (text-decoration "underline line-through overline")
               (font-size 10))
            ,(number->string year))))

(define (generate-svg-discord gyear day-details-lam)
  (let* ((year (+ gyear 1166))
         (month-tags (generate-months year day-details-lam))
         (total-width (+ 15 (* 3 (+ day-p month-w))))
         (total-height (* (+ month-p month-h) 2)))
    `(svg (@ (width ,total-width) (height ,total-height)
             (viewBox ,(string-append
                        "0 0 "
                        (number->string total-width) " "
                        (number->string total-height)))
             (xmlns "http://www.w3.org/2000/svg"))
          ,(legend)
          ,(year-legend year)
          (title ,(string-append "git activity discordian calendar " (number->string year)))
          (g (@ (transform "translate(15,15)") (class "discordian"))
             ,month-tags))))

(define svg-template-discord
  `((fn . ,generate-svg-discord)
    (theme . ((day-bg . "rgba(255,255,0,1)")))))

;; (with-output-to-file "img/git-discord-3181.svg"
;;   (lambda ()
;;     (display "<?xml-stylesheet type=\"text/css\" href=\"../css/svg.css\" ?>")
;;     (sxml->xml (generate-svg-discord 3181 (lambda (date) '(fill "rgba(255,255,0,1)"))))))