post-renderer.rkt 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #lang racket
  2. (require (prefix-in xml: xml)
  3. markdown
  4. pollen/unstable/pygments
  5. "../response.rkt"
  6. "../benchmark.rkt"
  7. "../utils/assertions.rkt"
  8. "../utils/list-operations.rkt"
  9. web-server/servlet
  10. gregor)
  11. (provide Post
  12. Post?
  13. Post-content
  14. Post-metadata
  15. PostMetadata
  16. PostMetadata-title
  17. PostMetadata-author
  18. PostMetadata-tags
  19. PostMetadata-creation-date
  20. PostMetadata-id
  21. Post-from-content
  22. PostMetadata-from-unserialized-yaml
  23. create-post-renderer)
  24. ;; =======
  25. ;; STRUCTS
  26. ;; =======
  27. (define-struct Post
  28. (metadata
  29. content)
  30. #:transparent)
  31. (define-struct PostMetadata
  32. (id
  33. title
  34. author
  35. creation-date
  36. tags)
  37. #:transparent)
  38. (define (Post-from-content content metadata)
  39. (Post metadata content))
  40. (define (PostMetadata-from-unserialized-yaml unserialized-yaml)
  41. ;; (display "creating PostMetadata from:") (displayln unserialized-yaml)
  42. (let ([id (hash-ref unserialized-yaml "id" 0)]
  43. [title (hash-ref unserialized-yaml "title" "no title")]
  44. [author (hash-ref unserialized-yaml "author" "anonymous")]
  45. [creation-date (parse-datetime (hash-ref unserialized-yaml "creation-date" "2017-01-01")
  46. "yyyy-MM-dd")]
  47. [tags (hash-ref unserialized-yaml "tags" (list))])
  48. (make-PostMetadata id title author creation-date tags)))
  49. ;; =========
  50. ;; RENDERING
  51. ;; =========
  52. (define (create-post-renderer #:render-metadata [render-metadata #t]
  53. #:render-toc [render-toc #t]
  54. #:render-content [render-content #t])
  55. (λ (post)
  56. (define (render-post-metadata metadata)
  57. `(div ((class "post-metadata"))
  58. (h1 ((class "post-title")) ,(PostMetadata-title metadata))
  59. (div ((class "post-metadata-non-title"))
  60. (ul ((class "post-metadata-list"))
  61. (li ,(string-append "id: "
  62. (number->string (PostMetadata-id metadata))))
  63. (li ,(string-append "Author: "
  64. (PostMetadata-author metadata)))
  65. (li ,(string-append "Creation date: "
  66. (parameterize ([current-locale "en"])
  67. (~t (PostMetadata-creation-date metadata)
  68. "EEEE, dd. MMMM yyyy, (yyyy-MM-dd)"))))
  69. (li (span "Tags: ")
  70. ,@(list-join (map render-tag
  71. (PostMetadata-tags metadata))
  72. `(span ", ")))))))
  73. (define (render-tag a-tag)
  74. (let ([tag-link (string-append "/tag/" a-tag)])
  75. `(a ((class "post-tag-link") (href ,tag-link)) ,a-tag)))
  76. ;; content: list of xexpr
  77. (define (render-post-content content)
  78. `(div ((class "post-content"))
  79. ,@content))
  80. ;; content: list of xexpr
  81. (define (render-post-toc content)
  82. (let ([toc (toc content)])
  83. `(div ((class "post-toc"))
  84. ,(insert-at-pos (replace-in-list toc
  85. 2
  86. `(div ((class "post-toc-inside")) ,(list-ref toc 2)))
  87. 2
  88. '(h1 ((class "post-toc-heading")) "Table of contents")))))
  89. (let* ([rendering-content
  90. (build-list-conditionally '()
  91. render-metadata
  92. (λ () (render-post-metadata (Post-metadata post))))]
  93. ;; shadowing previous rendering-content
  94. [rendering-content
  95. (build-list-conditionally rendering-content
  96. render-toc
  97. (λ () (render-post-toc (Post-content post))))]
  98. ;; shadowing previous rendering-content
  99. [rendering-content
  100. (build-list-conditionally rendering-content
  101. render-content
  102. (λ () (render-post-content (Post-content post))))])
  103. ;; The original render function is not required any longer.
  104. ;; We can simply return the result.
  105. `(div ((class "post"))
  106. ,@rendering-content))))