git.fiddlerwoaroof.com
Browse code

feature: actually render the feeds

Ed Langley authored on 06/11/2019 07:55:28
Showing 8 changed files
... ...
@@ -2,32 +2,52 @@
2 2
   (:use :cl )
3 3
   (:export
4 4
    #:default-layout
5
-   #:border-color))
5
+   #:border-color
6
+   #:background-color
7
+   #:text-color
8
+   #:link-color))
6 9
 (in-package :fwoar.default-layout)
7 10
 
8
-(defclass default-layout ()
9
-  ((%border-color :reader border-color :initform "#eee")))
10
-
11 11
 (defgeneric border-color (layout)
12 12
   )
13
+(defgeneric text-color (layout)
14
+  )
15
+(defgeneric link-color (layout)
16
+  (:method (layout)
17
+    (text-color layout)))
18
+(defgeneric background-color (layout)
19
+  )
20
+
21
+(defclass default-layout ()
22
+  ((%text-color :reader text-color :initform "#eee")
23
+   (%border-color :reader border-color :initform "#eee")
24
+   (%background-color :reader background-color :initform "#eee")))
13 25
 
14 26
 (defmethod araneus:styles append ((layout default-layout))
15 27
   `((body
28
+     :background ,(background-color layout)
29
+     :color ,(text-color layout)
16 30
      :display flex
17 31
      :flex-direction column
18 32
      :min-height 100vh)
33
+    (a
34
+     :color ,(link-color layout))
19 35
     (h1
20 36
      :height 3em
21
-     :border-bottom 1px solid ,(border-color layout)
37
+     :border-bottom 4px double ,(border-color layout)
22 38
      :text-align center
23 39
      :line-height 3em)
24 40
     (div.main
25 41
      :display flex
26 42
      :width 100%
27
-     :flex-grow 1)
43
+     :flex-grow 1
44
+     :flex-shrink 1
45
+     )
28 46
     (nav
29
-     :width 10%
47
+     :width 20rem
30 48
      :display flex
49
+     :flex-grow 0
50
+     :flex-shrink 0
31 51
      :flex-direction column)
32 52
     ((nav a)
33 53
      :font-weight bold
... ...
@@ -35,9 +55,11 @@
35 55
      :text-align right
36 56
      :text-decoration underline)
37 57
     ((nav (:and a :hover))
38
-     :background "#eee")
58
+     :background ,(link-color layout)
59
+     :color ,(background-color layout))
39 60
     (main
61
+     :border-left 4px double ,(border-color layout)
40 62
      :flex-grow 1
63
+     :flex-shrink 1
41 64
      :padding 1.5rem
42
-     :border-left 1px solid ,(border-color layout)
43
-     :flex-shrink 1)))
65
+     :max-width 50em)))
... ...
@@ -7,15 +7,25 @@
7 7
   (:documentation "the clack handler representing the currently running application"))
8 8
 
9 9
 (defclass+ rss-reader ()
10
-  ((%app :initform (make-instance 'ningle:<app>)
10
+  ((%feeds :initarg :feeds :accessor feeds)
11
+   (%app :initform (make-instance 'ningle:<app>)
11 12
          :reader app)
12 13
    (%handler :accessor handler))
13 14
   (:documentation
14 15
    "A simple wrapper that ties a ningle app to a clack handler"))
15 16
 
17
+
16 18
 (defmethod araneus:routes progn ((app rss-reader))
17 19
   (araneus:defroutes (app app)
18 20
     (("/") (serapeum:partial 'araneus:run-route (make-instance 'homepage)))
21
+    (("/f/:feed") (lambda (params)
22
+                    (optima:match params
23
+                      ((optima.extra:alist (:feed . feed))
24
+                       (araneus:run-route (feed-page
25
+                                           (feeds app)
26
+                                           (serapeum:assocdr feed (feeds app)
27
+                                                             :test 'string-equal))
28
+                                          params)))))
19 29
     (("/other") (serapeum:partial 'araneus:run-route 'other))))
20 30
 
21 31
 (defun start (app)
... ...
@@ -23,5 +33,16 @@
23 33
         (clack:clackup (app app)))
24 34
   app)
25 35
 
36
+(defvar *app*)
37
+
38
+(defun unboundp (symbol)
39
+  (not (boundp symbol)))
40
+
26 41
 (defun main ()
27
-  (start (araneus:routes (rss-reader))))
42
+  (setf *app*
43
+        (if (not (boundp '*app*))
44
+            (start
45
+             (araneus:routes
46
+              (rss-reader `((:techcrunch . "https://techcrunch.com/feed/")
47
+                            (:just-thomism . "https://thomism.wordpress.com/feed/")))))
48
+            *app*)))
... ...
@@ -5,7 +5,8 @@
5 5
 (defpackage :fwoar.rss-reader.ui
6 6
   (:use :cl :parenscript)
7 7
   (:export ui
8
-           #:homepage))
8
+           #:homepage
9
+           #:intercooler-debugger))
9 10
 
10 11
 (defpackage :fwoar.rss-reader
11 12
   (:use :cl )
... ...
@@ -22,6 +22,7 @@
22 22
   :components ((:file "package")
23 23
                (:file "utils" :depends-on ("package"))
24 24
                (:file "default-layout")
25
+               (:file "rss-render")
25 26
                (:file "ui" :depends-on ("package"))
26
-               (:file "view" :depends-on ("package" "ui" "default-layout"))
27
+               (:file "view" :depends-on ("package" "ui" "default-layout" "rss-render"))
27 28
                (:file "main" :depends-on ("package" "utils" "view"))))
28 29
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+(defpackage :fwoar.rss-render
2
+  (:use :cl )
3
+  (:export
4
+   #:summary))
5
+(in-package :fwoar.rss-render)
6
+
7
+(defmethod alimenta.render:render-feed (feed (renderer (eql 'summary)))
8
+  (plump:parse
9
+   (spinneret:with-html-string
10
+     (:div.feed
11
+      (:section
12
+       (:h2.title (plump:decode-entities
13
+                   (alimenta:title feed)))
14
+       (:p.description (plump:decode-entities
15
+                        (alimenta:description feed))))
16
+      (:ul.items)))))
17
+
18
+(defmethod alimenta.render:render-item (item feed (renderer (eql 'summary)))
19
+  (plump:first-element
20
+   (plump:parse
21
+    (spinneret:with-html-string
22
+      (:li
23
+       (:a :href (alimenta:link item)
24
+           (plump:decode-entities
25
+            (alimenta:title item)))
26
+       (:p.description
27
+        (plump:decode-entities
28
+         (alimenta:description item))))))))
29
+
30
+(defmethod alimenta.render:add-rendered-item (feed-r item-r (renderer (eql 'summary)))
31
+  (lquery:$
32
+    (inline feed-r)
33
+    ".items"
34
+    (append item-r))
35
+  feed-r)
... ...
@@ -5,16 +5,24 @@
5 5
     (:h1 "Hello, World!")
6 6
     (:div.main
7 7
      (:nav
8
+      :data-ic-target "main"
9
+      :data-ic-replace-target "true"
8 10
       (:a :data-ic-get-from "/"
9
-          :data-ic-target "#content"
10 11
           "home")
11 12
       (:a :data-ic-get-from "/other"
12
-          :data-ic-target "#content"
13 13
           "other")
14 14
       (:a :data-ic-get-from "/third"
15
-          :data-ic-target "#content"
16 15
           "third")
17 16
       (:a :data-ic-get-from "/fourth"
18
-          :data-ic-target "#content"
19 17
           "fourth"))
20
-     (:main#content content))))
18
+     (funcall content))))
19
+
20
+
21
+(defun intercooler-debugger ()
22
+  (ps
23
+    (defun cdnjs-library (name version &key (file name))
24
+      (chain
25
+       $ (get-script
26
+          "https://cdnjs.cloudflare.com/ajax/libs/intercooler-js/1.2.2/intercooler-debugger.js")))
27
+    (cdnjs-library
28
+     "intercooler-js" "1.2.2" #+(or)"intercooler-debugger.js")))
... ...
@@ -12,7 +12,12 @@
12 12
                                                                           :initarg)))
13 13
                                        (make-symbol (symbol-name initarg)))))
14 14
                                   direct-slots))))
15
-    `(progn (defclass ,name ,super
15
+    `(progn (defclass ,name
16
+                ,(mapcar (lambda (it)
17
+                           (typecase it
18
+                             (cons (car it))
19
+                             (t it)))
20
+                  super)
16 21
               ,direct-slots
17 22
               ,@options)
18 23
             (defun ,name (,@initargs)
... ...
@@ -1,23 +1,31 @@
1 1
 (in-package :fwoar.rss-reader)
2 2
 
3 3
 (defclass rss-reader-route ()
4
+  ((%feed-list :initarg :feed-list :reader feed-list)))
5
+
6
+(defclass+ intercooler-request ()
7
+  ((%request :initarg :request :reader request)))
8
+(defclass+ partial-request ((intercooler-request (request)))
9
+  ())
10
+(defclass+ full-request ((intercooler-request (request)))
4 11
   ())
5 12
 
6 13
 (defmethod araneus:view :around ((route rss-reader-route) model)
7 14
   "basic html and javascript for our app, as well as an invocation of
8 15
 the hook that pulls in CSS"
9 16
 
10
-  (ecase model
11
-    (:full
17
+  (etypecase model
18
+    (full-request
12 19
      (spinneret:with-html-string
13 20
        (:doctype)
14 21
        (:html
15 22
         (:head
16
-         (:script :src "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"
17
-                  :defer "defer")
23
+         (:script :src "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js")
18 24
          (:script :src
19 25
                   "https://cdnjs.cloudflare.com/ajax/libs/intercooler-js/1.2.2/intercooler.min.js"
20 26
                   :defer "defer")
27
+         (:script :defer "defer"
28
+                  (:raw (fwoar.rss-reader.ui:intercooler-debugger)))
21 29
          (:meta :name "intercoolerjs:use-data-prefix"
22 30
                 :content "true"/)
23 31
          (:style
... ...
@@ -25,7 +33,7 @@ the hook that pulls in CSS"
25 33
                  (araneus:styles route))))
26 34
         (:body
27 35
          (call-next-method)))))
28
-    (:partial
36
+    (partial-request
29 37
      (spinneret:with-html-string
30 38
        (call-next-method)))))
31 39
 
... ...
@@ -46,6 +54,47 @@ the hook that pulls in CSS"
46 54
     ((:or ul ol)
47 55
      :padding-left 2rem)))
48 56
 
57
+(defclass+ feed-page ((rss-reader-route (feed-list)) fwoar.default-layout:default-layout)
58
+  ((%feed :initarg :feed :reader feed)))
59
+
60
+(defmethod araneus:controller ((route feed-page) params &key)
61
+  (funcall (if (equal (serapeum:assocdr "ic-request" params
62
+                                        :test 'equal)
63
+                      "true")
64
+               'partial-request
65
+               'full-request)
66
+           (alimenta.pull-feed:pull-feed (feed route))))
67
+
68
+(defmacro with-layout ((render-type layout) &body content)
69
+  `(let ((content (lambda ()
70
+                    (spinneret:with-html
71
+                      (:main
72
+                       ,@content)))))
73
+     (ecase ,render-type
74
+       (:full (spinneret:with-html
75
+                (,layout content)))
76
+       (:partial (funcall content)))))
77
+
78
+(defmethod araneus:view ((_ feed-page) (model intercooler-request))
79
+  (spinneret:with-html
80
+    (:main#content
81
+     (alimenta:render (request model)
82
+                      'fwoar.rss-render:summary))))
83
+(defmethod araneus:view ((route feed-page) (model full-request))
84
+  (spinneret:with-html
85
+    (:h1 "Hello, World!")
86
+    (:div.main
87
+     (:nav
88
+      :data-ic-push-url "true"
89
+      :data-ic-target "main"
90
+      :data-ic-replace-target "true"
91
+      (loop for (feed-id) in (feed-list route)
92
+            collect (:a :data-ic-get-from (format nil "/f/~a" (string-downcase feed-id))
93
+                        feed-id)))
94
+     (:main#content
95
+      (alimenta:render (request model)
96
+                       'fwoar.rss-render:summary)))))
97
+
49 98
 (defclass homepage (rss-reader-route fwoar.default-layout:default-layout)
50 99
   ())
51 100
 
... ...
@@ -61,15 +110,14 @@ the hook that pulls in CSS"
61 110
       :full))
62 111
 
63 112
 (defmethod araneus:view ((route homepage) model)
64
-  (let ((content "home content"))
65
-    (ecase model
66
-      (:full (fwoar.rss-reader.ui:homepage content))
67
-      (:partial (spinneret:with-html
68
-                  (:raw (with-output-to-string (s)
69
-                          (cl-markdown:markdown content
70
-                                                :stream s))))))))
113
+  (with-layout (model fwoar.rss-reader.ui:homepage)
114
+    (:raw
115
+     (plump:serialize (alimenta:render (alimenta.pull-feed:pull-feed
116
+                                        "https://thomism.wordpress.com/feed/")
117
+                                       'fwoar.rss-render:summary)
118
+                      nil))))
71 119
 
72 120
 (araneus:define-controller other (_)
73 121
   (values))
74 122
 (araneus:define-view other (_)
75
-  "<h2>???</h2>")
123
+  "<main><h2>???</h2></main>")