2011-04-16 15:45:37 -04:00
|
|
|
(in-package :coleslaw)
|
|
|
|
|
2012-09-12 11:00:21 -04:00
|
|
|
(defclass index ()
|
2014-04-07 20:54:45 -04:00
|
|
|
((slug :initform nil :initarg :slug :accessor index-slug)
|
2014-04-15 20:30:47 -04:00
|
|
|
(title :initform nil :initarg :title :accessor index-title)
|
|
|
|
(content :initform nil :initarg :content :accessor index-content)))
|
2012-09-12 11:00:21 -04:00
|
|
|
|
2013-04-29 10:17:19 -04:00
|
|
|
(defmethod render ((object index) &key prev next)
|
|
|
|
(funcall (theme-fn 'index) (list :tags (all-tags)
|
|
|
|
:months (all-months)
|
|
|
|
:config *config*
|
|
|
|
:index object
|
|
|
|
:prev prev
|
|
|
|
:next next)))
|
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
;;; Index by Tag
|
2012-08-20 17:26:12 -04:00
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
(defclass tag-index (index) ())
|
|
|
|
|
|
|
|
(defmethod page-url ((object tag-index))
|
|
|
|
(format nil "tag/~a" (index-slug object)))
|
|
|
|
|
|
|
|
(defmethod discover ((doc-type (eql (find-class 'tag-index))))
|
|
|
|
(let ((content (by-date (find-all 'post))))
|
|
|
|
(dolist (tag (all-tags))
|
|
|
|
(add-document (index-by-tag tag content)))))
|
2011-04-22 17:16:42 -04:00
|
|
|
|
2013-01-02 14:23:56 -05:00
|
|
|
(defun index-by-tag (tag content)
|
|
|
|
"Return an index of all CONTENT matching the given TAG."
|
2014-04-07 20:54:45 -04:00
|
|
|
(make-instance 'tag-index :slug (tag-slug tag)
|
2014-04-15 20:30:47 -04:00
|
|
|
:content (remove-if-not (lambda (x) (tag-p tag x)) content)
|
2014-04-15 20:39:13 -04:00
|
|
|
:title (format nil "Content tagged ~a" (tag-name tag))))
|
2011-04-16 15:45:37 -04:00
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
(defmethod publish ((doc-type (eql (find-class 'tag-index))))
|
|
|
|
(dolist (index (find-all 'tag-index))
|
|
|
|
(render-index index)))
|
|
|
|
|
|
|
|
;;; Index by Month
|
|
|
|
|
|
|
|
(defclass month-index (index) ())
|
|
|
|
|
|
|
|
(defmethod page-url ((object month-index))
|
|
|
|
(format nil "date/~a" (index-slug object)))
|
|
|
|
|
|
|
|
(defmethod discover ((doc-type (eql (find-class 'month-index))))
|
|
|
|
(let ((content (by-date (find-all 'post))))
|
|
|
|
(dolist (month (all-months))
|
|
|
|
(add-document (index-by-month month content)))))
|
|
|
|
|
2013-01-02 14:23:56 -05:00
|
|
|
(defun index-by-month (month content)
|
|
|
|
"Return an index of all CONTENT matching the given MONTH."
|
2014-04-15 15:27:46 -04:00
|
|
|
(make-instance 'month-index :slug month
|
2014-04-15 20:30:47 -04:00
|
|
|
:content (remove-if-not (lambda (x) (month-p month x)) content)
|
2014-04-15 20:39:13 -04:00
|
|
|
:title (format nil "Content from ~a" month)))
|
2012-09-12 13:37:55 -04:00
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
(defmethod publish ((doc-type (eql (find-class 'month-index))))
|
|
|
|
(dolist (index (find-all 'month-index))
|
|
|
|
(render-index index)))
|
|
|
|
|
|
|
|
;;; Reverse Chronological Index
|
|
|
|
|
|
|
|
(defclass numeric-index (index) ())
|
|
|
|
|
|
|
|
(defmethod page-url ((object numeric-index))
|
|
|
|
(format nil "~d" (index-slug object)))
|
|
|
|
|
|
|
|
(defmethod discover ((doc-type (eql (find-class 'numeric-index))))
|
|
|
|
(let ((content (by-date (find-all 'post))))
|
|
|
|
(dotimes (i (ceiling (length content) 10))
|
|
|
|
(add-document (index-by-n i content)))))
|
|
|
|
|
2014-04-08 16:51:13 -04:00
|
|
|
(defun index-by-n (i content)
|
2013-01-02 14:23:56 -05:00
|
|
|
"Return the index for the Ith page of CONTENT in reverse chronological order."
|
2014-04-08 16:51:13 -04:00
|
|
|
(let ((content (subseq content (* 10 i))))
|
2014-04-07 20:54:45 -04:00
|
|
|
(make-instance 'numeric-index :slug (1+ i)
|
2014-04-15 20:30:47 -04:00
|
|
|
:content (take-up-to 10 content)
|
2014-04-15 20:39:13 -04:00
|
|
|
:title "Recent Content")))
|
2014-04-08 16:51:13 -04:00
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
(defmethod publish ((doc-type (eql (find-class 'numeric-index))))
|
|
|
|
(let ((indexes (sort (find-all 'numeric-index) #'< :key #'index-slug)))
|
|
|
|
(dolist (index indexes)
|
|
|
|
(let ((prev (1- (index-slug index)))
|
|
|
|
(next (1+ (index-slug index))))
|
|
|
|
(render-index index :prev (when (plusp prev) prev)
|
|
|
|
:next (when (<= next (length indexes)) next))))))
|
|
|
|
|
|
|
|
;;; Atom and RSS Feeds
|
|
|
|
|
|
|
|
(defclass feed (index)
|
|
|
|
((format :initform nil :initarg :format :accessor feed-format)))
|
|
|
|
|
|
|
|
(defmethod page-url ((object feed))
|
|
|
|
(format nil "~(~a~).xml" (feed-format object)))
|
|
|
|
|
|
|
|
(defmethod discover ((doc-type (eql (find-class 'feed))))
|
|
|
|
(let ((content (take-up-to 10 (by-date (find-all 'post)))))
|
|
|
|
(dolist (format '(rss atom))
|
2014-04-15 20:30:47 -04:00
|
|
|
(let ((feed (make-instance 'feed :content content :format format)))
|
2014-04-15 15:27:46 -04:00
|
|
|
(add-document feed)))))
|
|
|
|
|
|
|
|
(defmethod publish ((doc-type (eql (find-class 'feed))))
|
|
|
|
(dolist (feed (find-all 'feed))
|
|
|
|
(render-feed feed)))
|
|
|
|
|
2014-04-16 00:04:50 -04:00
|
|
|
;;; Tag Feeds
|
|
|
|
|
2014-04-15 15:27:46 -04:00
|
|
|
(defclass tag-feed (feed) ())
|
|
|
|
|
|
|
|
(defmethod page-url ((object tag-feed))
|
|
|
|
(format nil "tag/~a~(~a~).xml" (index-slug object) (feed-format object)))
|
|
|
|
|
|
|
|
(defmethod discover ((doc-type (eql (find-class 'tag-feed))))
|
|
|
|
(let ((content (by-date (find-all 'post))))
|
|
|
|
(dolist (tag (feeds *config*))
|
2014-04-15 20:39:13 -04:00
|
|
|
(let ((tagged (remove-if-not (lambda (x) (tag-p tag x)) content)))
|
2014-04-15 15:27:46 -04:00
|
|
|
(dolist (format '(rss atom))
|
2014-04-15 20:39:13 -04:00
|
|
|
(let ((feed (make-instance 'tag-feed :content (take-up-to 10 tagged)
|
2014-04-15 15:27:46 -04:00
|
|
|
:format format
|
|
|
|
:slug tag)))
|
|
|
|
(add-document feed)))))))
|
|
|
|
|
|
|
|
(defmethod publish ((doc-type (eql (find-class 'tag-feed))))
|
|
|
|
(dolist (feed (find-all 'tag-feed))
|
|
|
|
(render-feed feed)))
|
|
|
|
|
|
|
|
;;; Helper Functions
|
|
|
|
|
|
|
|
(defun all-months ()
|
|
|
|
"Retrieve a list of all months with published content."
|
|
|
|
(let ((months (mapcar (lambda (x) (subseq (content-date x) 0 7))
|
2014-04-15 16:46:04 -04:00
|
|
|
(find-all 'post))))
|
2014-04-15 15:27:46 -04:00
|
|
|
(sort (remove-duplicates months :test #'string=) #'string>)))
|
|
|
|
|
|
|
|
(defun all-tags ()
|
|
|
|
"Retrieve a list of all tags used in content."
|
2014-04-15 16:46:04 -04:00
|
|
|
(let* ((dupes (mappend #'content-tags (find-all 'post)))
|
2014-04-15 15:27:46 -04:00
|
|
|
(tags (remove-duplicates dupes :test #'string= :key #'tag-slug)))
|
|
|
|
(sort tags #'string< :key #'tag-name)))
|
|
|
|
|
2014-04-08 16:51:13 -04:00
|
|
|
(defun render-feed (feed)
|
|
|
|
"Render the given FEED to both RSS and ATOM."
|
|
|
|
(let ((theme-fn (theme-fn (feed-format feed) "feeds")))
|
2014-04-18 12:12:57 -04:00
|
|
|
(write-file (page-path feed) (render-page feed theme-fn))))
|
2011-04-19 00:34:17 -04:00
|
|
|
|
2013-04-29 10:17:19 -04:00
|
|
|
(defun render-index (index &rest render-args)
|
|
|
|
"Render the given INDEX using RENDER-ARGS if provided."
|
2014-04-18 12:12:57 -04:00
|
|
|
(write-file (page-path index) (apply #'render-page index nil render-args)))
|