瀏覽代碼

Implement indices in a really nasty, "just get it done" sort of way, tweak API + update TODO.

Brit Butler 14 年之前
父節點
當前提交
1d01f91c2b
共有 7 個文件被更改,包括 113 次插入34 次删除
  1. 8 1
      TODO
  2. 5 2
      src/indices.lisp
  3. 3 2
      src/posts.lisp
  4. 13 1
      static/coleslaw.lisp
  5. 56 8
      static/indices.lisp
  6. 18 20
      static/posts.lisp
  7. 10 0
      static/util.lisp

+ 8 - 1
TODO

@@ -12,16 +12,23 @@ Ideas:
12 12
 ;;;; DYNAMIC
13 13
 
14 14
 ;;;; STATIC
15
-;;;; implement render-site, head-inject/body-inject/navigation.
15
+;;;; implement head-inject/body-inject/navigation!
16
+;;;; implement start-coleslaw, stop-coleslaw!
16 17
 ;;;; non-disqus comment support?
18
+;;; indexes
19
+;; what should it really look like, keeping in mind the API should be mostly
20
+;; identical between the static and dynamic backend?
17 21
 ;;; posts
18 22
 ;; Make find-by-date, post-url not suck.
23
+;; -- re: find-by-date, aside from the subseq+string= grossness, the posts it
24
+;; -- returns are not in reverse chronological order. Fix it!
19 25
 ;; -- re: post-url, escaping is insufficient and there are collisions by title.
20 26
 ;; -- What are alternatives?
21 27
 
22 28
 ;;;; PLUGINS
23 29
 ;;;; implement disqus support
24 30
 ;;; import
31
+;; add output to HTML files when static-p is true
25 32
 ;; add comment handling ... (when comments ...)
26 33
 ;; support old URLs via use of post-aliases?
27 34
 

+ 5 - 2
src/indices.lisp

@@ -6,8 +6,11 @@
6 6
 (defgeneric remove-index (id)
7 7
   (:documentation "Remove the index matching ID from *storage*."))
8 8
 
9
-(defgeneric render-index (index)
10
-  (:documentation "Generate the final HTML for INDEX."))
9
+(defgeneric render-index (id page)
10
+  (:documentation "Generate the final HTML for the index with given ID."))
11 11
 
12 12
 (defgeneric find-index (id)
13 13
   (:documentation "Retrieve the index matching ID from *storage*."))
14
+
15
+(defgeneric index-url (id page)
16
+  (:documentation "Return the URL for the PAGE of index with given ID."))

+ 3 - 2
src/posts.lisp

@@ -14,7 +14,8 @@
14 14
    (aliases :initform nil :initarg :aliases
15 15
             :accessor post-aliases)))
16 16
 
17
-(defgeneric make-post (title tags date content &key id &allow-other-keys)
17
+(defgeneric make-post (title tags date content
18
+                       &key id aliases &allow-other-keys)
18 19
   (:documentation "Create a POST with the given data."))
19 20
 
20 21
 (defgeneric add-post (post id)
@@ -24,7 +25,7 @@
24 25
   (:documentation "Remove a post from *storage* matching ID."))
25 26
 
26 27
 (defgeneric render-post (id)
27
-  (:documentation "Generate the final HTML for post."))
28
+  (:documentation "Generate the final HTML for the post with given ID."))
28 29
 
29 30
 (defgeneric find-post (id)
30 31
   (:documentation "Retrieve a post from *storage* matching ID."))

+ 13 - 1
static/coleslaw.lisp

@@ -2,7 +2,7 @@
2 2
 
3 3
 (defvar *site-root* nil
4 4
   "A string representing the base URL of the site,
5
-e.g. \"http://blog.redlinernotes.com/\".")
5
+e.g. \"http://blog.redlinernotes.com\".")
6 6
 
7 7
 (defvar *site-title* nil
8 8
   "A string containing the title of the site,
@@ -39,3 +39,15 @@ e.g. \"CC-BY-SA\". Otherwise, standard copyright is assumed.")
39 39
 
40 40
 (defmethod set-credentials (name credentials)
41 41
   (setf (gethash name (gethash :credentials *storage*)) credentials))
42
+
43
+(defmethod render-page (content)
44
+  (let ((result (funcall (find-symbol "BASE" (theme-package))
45
+                         (list :title *site-title*
46
+                               :siteroot *site-root*
47
+                               :head-inject nil
48
+                               :navigation nil
49
+                               :content content
50
+                               :body-inject nil
51
+                               :license *site-license*
52
+                               :credits *site-credits*))))
53
+    result))

+ 56 - 8
static/indices.lisp

@@ -1,13 +1,61 @@
1 1
 (in-package :coleslaw)
2 2
 
3
-(defmethod find-index (id)
4
-  (gethash id (gethash :indices *storage*)))
3
+(defun monthlinks ()
4
+  (loop for month in (gethash :months-index *storage*)
5
+     collect (cons (index-url :date month) month) into months
6
+     finally (return
7
+               (pretty-list (mapcar (lambda (consp)
8
+                                      (format nil "<a href=\"~a\">~a</a>"
9
+                                              (car consp) (cdr consp)))
10
+                                    months)))))
5 11
 
6
-(defmethod add-index (index id)
7
-  (setf (find-index id) index))
12
+(defun taglinks ()
13
+  (loop for tag in (gethash :tags-index *storage*)
14
+     collect (cons (index-url :tag tag) tag) into tags
15
+     finally (return
16
+               (pretty-list (mapcar (lambda (consp)
17
+                                      (format nil "<a href=\"~a\">~a</a>"
18
+                                              (car consp) (cdr consp)))
19
+                                    tags)))))
8 20
 
9
-(defmethod remove-index (id)
10
-  (setf (find-index id) nil))
21
+(defun index-title (id &optional page)
22
+  (case id
23
+    (:range "Recent Posts")
24
+    (:date (format nil "Posts from ~A" page))
25
+    (:tag (format nil "Posts tagged ~A" page))))
11 26
 
12
-(defmethod render-index (index)
13
-  )
27
+(defun index-posts (id page)
28
+  (case id
29
+    (:range (let* ((count (hash-table-count (gethash :posts *storage*)))
30
+                   (start (- count (* 10 (1- page))))
31
+                   (end (- start 9)))
32
+              (remove nil (find-by-range start end))))
33
+    (:date (find-by-date page))
34
+    (:tag (find-by-tag page))))
35
+
36
+(defmethod render-index (id page)
37
+  (let* ((posts (index-posts id page))
38
+         (content (funcall (find-symbol "INDEX" (theme-package))
39
+                           (list :taglinks (taglinks)
40
+                                 :monthlinks (monthlinks)
41
+                                 :title (index-title id page)
42
+                                 :posts (loop for post in posts collect
43
+                                             (list :url (post-url (post-id post))
44
+                                                   :title (post-title post)
45
+                                                   :date (pretty-date (post-date post))
46
+                                                   :contents (post-content post)))
47
+                                 :prev (when (and (numberp id)
48
+                                                  (index-posts id (1- page)))
49
+                                         (index-url id (1- page)))
50
+                                 :next (when (and (numberp id)
51
+                                                  (index-posts id (1+ page)))
52
+                                         (index-url id (1+ page)))))))
53
+    content))
54
+
55
+(defmethod index-url (id page)
56
+  (flet ((keyword-name (keyword)
57
+           (format nil "~A" keyword)))
58
+    (if (member id '(:date :tag))
59
+        (concatenate 'string *site-root* "/"
60
+                     (string-downcase (keyword-name id)) "/" page)
61
+        (concatenate 'string *site-root* "/page/" (write-to-string page)))))

+ 18 - 20
static/posts.lisp

@@ -11,29 +11,27 @@
11 11
 (defmethod add-post ((post post) id)
12 12
   (setf (gethash id (gethash :posts *storage*)) post)
13 13
   (loop for tag in (post-tags post)
14
-     do (pushnew tag (gethash :tags-index *storage*) :test #'string=)))
14
+     do (pushnew tag (gethash :tags-index *storage*) :test #'string=))
15
+  (let ((date (post-date post))
16
+        (month (format nil "~4d-~2,'0d" (local-time:timestamp-year date)
17
+                       (local-time:timestamp-month date))))
18
+    (pushnew month (gethash :months-index *storage*) :test #'string=)))
15 19
 
16 20
 (defmethod remove-post (id)
17 21
   (setf (gethash id (gethash :posts *storage*)) nil))
18 22
 
19 23
 (defmethod render-post (id)
20
-  (flet ((fn (name)
21
-           (find-symbol name (theme-package)))
22
-         (pretty-date (date)
23
-           (subseq (local-time:format-rfc1123-timestring nil date) 0 16))
24
-         (pretty-tags (tags)
25
-           (format nil "~{~A~^, ~}" tags)))
26
-    (let* ((post (find-post id))
27
-           (result (funcall (fn "POST")
28
-                           (list :title (post-title post)
29
-                                 :tags (pretty-tags (post-tags post))
30
-                                 :date (pretty-date (post-date post))
31
-                                 :content (post-content post)
32
-                                 :prev (when (find-post (1- id))
33
-                                         (post-url (1- id)))
34
-                                 :next (when (find-post (1+ id))
35
-                                         (post-url (1+ id)))))))
36
-      result)))
24
+  (let* ((post (find-post id))
25
+         (result (funcall (theme-fn "POST")
26
+                          (list :title (post-title post)
27
+                                :tags (pretty-tags (post-tags post))
28
+                                :date (pretty-date (post-date post))
29
+                                :content (post-content post)
30
+                                :prev (when (find-post (1- id))
31
+                                        (post-url (1- id)))
32
+                                :next (when (find-post (1+ id))
33
+                                        (post-url (1+ id)))))))
34
+    result))
37 35
 
38 36
 (defmethod find-post (id)
39 37
   (gethash id (gethash :posts *storage*)))
@@ -41,7 +39,7 @@
41 39
 (defmethod find-by-tag (tag)
42 40
   (let ((results nil))
43 41
     (loop for post being the hash-values in (gethash :posts *storage*)
44
-       do (when (search tag (post-tags post))
42
+       do (when (member tag (post-tags post) :test #'string=)
45 43
             (push post results)))
46 44
     results))
47 45
 
@@ -64,4 +62,4 @@
64 62
 (defmethod post-url (id)
65 63
   (flet ((escape (str)
66 64
            (substitute #\- #\Space str)))
67
-    (concatenate 'string *site-root* (escape (post-title (find-post id))))))
65
+    (concatenate 'string *site-root* "/" (escape (post-title (find-post id))))))

+ 10 - 0
static/util.lisp

@@ -0,0 +1,10 @@
1
+(in-package :coleslaw)
2
+
3
+(defun pretty-date (date)
4
+  (subseq (local-time:format-rfc1123-timestring nil date) 0 16))
5
+
6
+(defun pretty-list (list)
7
+  (format nil "~{~A~^, ~}" list))
8
+
9
+(defun theme-fn (name)
10
+  (find-symbol name (theme-package)))