diff --git a/coleslaw.asd b/coleslaw.asd index 35063030..e62c786c 100644 --- a/coleslaw.asd +++ b/coleslaw.asd @@ -14,7 +14,8 @@ :cl-fad :cl-ppcre :closer-mop - :cl-unicode) + :cl-unicode + :djula) :serial t :components ((:file "packages") (:file "util") diff --git a/docs/config.md b/docs/config.md index 5814c579..38beaf51 100644 --- a/docs/config.md +++ b/docs/config.md @@ -22,14 +22,15 @@ It is usually recommend to start from the [example config][ex_config] and pare d ## Extras There are also many *optional* config parameters such as: -* `:charset` => to set HTML attributes for international characters, default: "UTF-8" -* `:feeds` => to generate RSS and Atom feeds for certain tagged content -* `:lang` => to set HTML attributes indicating the site language, default: "en" -* `:license` => to override the displayed content license, the default is CC-BY-SA -* `:page-ext` => to set the suffix of generated files, default: "html" -* `:plugins` => to configure and enable coleslaw's [various plugins][plugin-use] -* `:separator` => to set the separator for content metadata, default: ";;;;;" -* `:sitenav` => to provide relevant links and ease navigation -* `:staging-dir` => for Coleslaw to do intermediate work, default: "/tmp/coleslaw" +* `:charset` => to set HTML attributes for international characters, default: "UTF-8" +* `:feeds` => to generate RSS and Atom feeds for certain tagged content +* `:lang` => to set HTML attributes indicating the site language, default: "en" +* `:license` => to override the displayed content license, the default is CC-BY-SA +* `:page-ext` => to set the suffix of generated files, default: "html" +* `:plugins` => to configure and enable coleslaw's [various plugins][plugin-use] +* `:separator` => to set the separator for content metadata, default: ";;;;;" +* `:sitenav` => to provide relevant links and ease navigation +* `:staging-dir` => for Coleslaw to do intermediate work, default: "/tmp/coleslaw" +* `:template-engine` => to set the template engine coleslaw should use, default: cl-closure [plugin-use]: https://github.com/redline6561/coleslaw/blob/master/docs/plugin-use.md diff --git a/docs/themes.md b/docs/themes.md index 178dc934..2a3192c9 100644 --- a/docs/themes.md +++ b/docs/themes.md @@ -10,10 +10,13 @@ template engine and how you can influence the resulting HTML. ## High-Level Overview -Themes are written using [Closure Templates][clt]. Those templates are -then compiled into functions that Lisp calls with the blog data to get -HTML. Since the Lisp code to use theme functions is already written, -your theme must follow a few rules. +Themes are written using [Closure Templates][clt] or using +[Djula][djula]. + +## Closure templates +Closure templates are then compiled into functions that Lisp calls with +the blog data to get HTML. Since the Lisp code to use theme functions is +already written, your theme must follow a few rules. Every theme **must** be in a folder under "themes/" named after the theme. The theme's templates must start with a namespace declaration @@ -67,7 +70,23 @@ template hacking. There is plenty of advice on CSS styling on the web. I'm no expert but feel free to send pull requests modifying a theme's CSS or improving this section, perhaps by recommending a CSS resource. -## Creating a Theme from Scratch (with code) +## Djula templates + +Djula templates are somewhat more traditional than closure templates. +They are inspired by Django templates. For more info see the Djula +[documentation][djula_doc]. Instead of having a base template that +gets called with data from the child template, Djula uses an extend +mechanism. A template extends from an other template and defines blocks +that the extended templates uses. + +Because you extend templates in djula you only have to define a post.html and +index.html template in the theme folder. The variables passed to this template +are the same as with closure. So post.html gets the post and base variables and +index.html gets the index and base variables. + +For more information see the hyde-djula theme on how djula works. + +## Creating a Theme from Scratch using Closure (with code) ### Step 1. Create the directory. @@ -214,5 +233,7 @@ between the pages so navigation is cumbersome but adding links is simple. Just do: `{$object.name}`. [clt]: https://developers.google.com/closure/templates/ +[djula]: https://github.com/mmontone/djula +[djula_doc]: https://mmontone.github.io/djula/doc/build/html/index.html [ovr]: https://github.com/redline6561/coleslaw/blob/master/docs/overview.md [hck]: https://github.com/redline6561/coleslaw/blob/master/docs/hacking.md diff --git a/plugins/cl-closure.lisp b/plugins/cl-closure.lisp new file mode 100644 index 00000000..2c943702 --- /dev/null +++ b/plugins/cl-closure.lisp @@ -0,0 +1,45 @@ +(eval-when (:compile-toplevel :load-toplevel) + (ql:quickload :cl-closure)) + +(defpackage :coleslaw-cl-closure + (:use :cl) + (:import-from :closure-template #:compile-template) + (:import-from :local-time #:format-rfc1123-timestring) + (:import-from :coleslaw #:find-theme + #:app-path + #:render + #:find-injections + #:*config* + #:theme + #:do-files + #:render + #:theme-package) + (:export #:enable)) + +(in-package :coleslaw-cl-closure) + +(defclass cl-closure () ()) + +(defmethod coleslaw:compile-theme ((cl-closure cl-closure) theme) + "Compile the templates used by cl-closure" + (do-files (file (app-path "themes/auxiliary") + "cl-closure") + (compile-template :common-lisp-backend file)) + (do-files (file (find-theme theme) "tmpl") + (compile-template :common-lisp-backend file))) + +(defmethod coleslaw:render-page ((template cl-closure) content &optional theme-fn &rest render-args) + (apply (or theme-fn (get-theme-fn 'theme 'base)) + :config *config* + :content content + :pubdate (format-rfc1123-timestring nil (local-time:now)) + :injections (find-injections content) + :raw (apply #'render content render-args) + render-args)) + +(defmethod coleslaw:get-theme-fn ((template cl-closure) name &optional (package (theme *config*))) + (let ((closure-func (find-symbol (princ-to-string name) (theme-package package)))) + (lambda (&rest template-args) + (funcall closure-func template-args)))) + +(defun enable ()) diff --git a/plugins/djula.lisp b/plugins/djula.lisp new file mode 100644 index 00000000..b75d1233 --- /dev/null +++ b/plugins/djula.lisp @@ -0,0 +1,57 @@ +(eval-when (:compile-toplevel :load-toplevel) + (ql:quickload :djula)) + +(defpackage :coleslaw-djula + (:use :cl :cl-ppcre) + (:import-from :djula #:compile-template* + #:render-template*) + (:import-from :local-time #:format-rfc1123-timestring) + (:import-from :coleslaw #:get-theme-fn + #:render-page + #:find-theme + #:app-path + #:render + #:find-injections + #:*config* + #:theme + #:do-files) + (:import-from :cl-ppcre #:create-scanner + #:regex-replace) + (:export #:enable)) + +(in-package :coleslaw-djula) + +(defclass djula () + ((templates :initform (make-hash-table :test #'equalp) :accessor templates))) + +(defparameter +remove-extension+ (create-scanner "(.*)\\..*")) + +(defun compile-djula (djula file &optional (filename (regex-replace +remove-extension+ (file-namestring file) "\\1"))) + (setf (gethash filename + (templates djula)) (compile-template* file))) + +(defmethod coleslaw:compile-theme ((djula djula) theme) + (do-files (file (app-path "themes/auxiliary") + "djula") + (compile-djula djula file)) + (do-files (file (find-theme theme) "html") + (compile-djula djula file))) + +(defmethod coleslaw:render-page ((djula djula) content &optional theme-fn &rest render-args) + (apply (or theme-fn #'render) + content + :config *config* + :content content + :pubdate (format-rfc1123-timestring nil (local-time:now)) + :injections (find-injections content) + render-args)) + +(defmethod coleslaw:get-theme-fn ((djula djula) name &optional package) + (declare (ignore package)) + (break) + (let ((theme (gethash (string name) (templates djula)))) + (lambda (&rest template-args) + (with-output-to-string (stream) + (apply #'render-template* theme stream template-args))))) + +(defun enable ()) diff --git a/plugins/sitemap.lisp b/plugins/sitemap.lisp index ea4a0ea8..3605a204 100644 --- a/plugins/sitemap.lisp +++ b/plugins/sitemap.lisp @@ -5,8 +5,9 @@ #:page-url #:find-all #:publish - #:theme-fn + #:get-theme-fn #:add-document + #:template-engine #:write-document) (:import-from :alexandria #:hash-table-values) (:export #:enable)) @@ -25,6 +26,6 @@ (let* ((base-urls '("" "sitemap.xml")) (urls (mapcar #'page-url (hash-table-values coleslaw::*site*))) (sitemap (make-instance 'sitemap :urls (append base-urls urls)))) - (write-document sitemap (theme-fn 'sitemap "sitemap")))) + (write-document sitemap (get-theme-fn (template-engine *config*) 'sitemap "sitemap")))) (defun enable ()) diff --git a/plugins/static-pages.lisp b/plugins/static-pages.lisp index f83849e8..0a78947b 100644 --- a/plugins/static-pages.lisp +++ b/plugins/static-pages.lisp @@ -6,9 +6,11 @@ #:find-all #:render #:publish - #:theme-fn + #:get-theme-fn #:render-text - #:write-document)) + #:write-document + #:template-engine) + (:import-from :djula #:render-template*)) (in-package :coleslaw-static-pages) @@ -24,11 +26,12 @@ format (alexandria:make-keyword (string-upcase format)) coleslaw::text (render-text coleslaw::text format)))) -(defmethod render ((object page) &key next prev) +(defmethod render ((object page) &rest rest &key next prev) ;; For the time being, we'll re-use the normal post theme. (declare (ignore next prev)) - (funcall (theme-fn 'post) (list :config *config* - :post object))) + (apply (get-theme-fn (template-engine *config*) 'post) :config *config* + :post object + rest)) (defmethod publish ((doc-type (eql (find-class 'page)))) (dolist (page (find-all 'page)) diff --git a/src/coleslaw.lisp b/src/coleslaw.lisp index c5b9bad2..7cc5de46 100644 --- a/src/coleslaw.lisp +++ b/src/coleslaw.lisp @@ -3,16 +3,27 @@ (defvar *last-revision* nil "The git revision prior to the last push. For use with GET-UPDATED-FILES.") +(defvar *templating-engine* nil + "The templating engine to use. This will be set during the main routine. +Possible options at this time are djula and cl-closure.") + +(defvar *djula-post-template* nil + "The template to use for rendering a post using a djula template.") + +(defvar *djula-index-template* nil + "The template to use for rendering the index using a djula template.") + (defun main (repo-dir &optional oldrev) "Load the user's config file, then compile and deploy the blog stored in REPO-DIR. Optionally, OLDREV is the revision prior to the last push." (load-config repo-dir) - (setf *last-revision* oldrev) - (load-content) - (compile-theme (theme *config*)) - (let ((dir (staging-dir *config*))) - (compile-blog dir) - (deploy dir))) + (let ((*templating-engine* (template-engine *config*))) + (setf *last-revision* oldrev) + (load-content) + (compile-theme (template-engine *config*) (theme *config*)) + (let ((dir (staging-dir *config*))) + (compile-blog dir) + (deploy dir)))) (defun load-content () "Load all content stored in the blog's repo." @@ -55,17 +66,15 @@ in REPO-DIR. Optionally, OLDREV is the revision prior to the last push." (let ((current-working-directory (cl-fad:pathname-directory-pathname path))) (unless *config* (load-config (namestring current-working-directory)) - (compile-theme (theme *config*))) + (compile-theme (template-engine *config*) (theme *config*))) (let* ((file (rel-path (repo-dir *config*) path)) (content (construct content-type (read-content file)))) - (write-file "tmp.html" (render-page content))))) + (write-file "tmp.html" (render-page (template-engine *config*) content))))) -(defun render-page (content &optional theme-fn &rest render-args) - "Render the given CONTENT to HTML using THEME-FN if supplied. -Additional args to render CONTENT can be passed via RENDER-ARGS." - (funcall (or theme-fn (theme-fn 'base)) - (list :config *config* - :content content - :raw (apply 'render content render-args) - :pubdate (format-rfc1123-timestring nil (local-time:now)) - :injections (find-injections content)))) +(defgeneric render-page (template-engine content &optional theme-fn &rest render-args) + (:documentation "Render a page using the given theme. TEMPLATE-ENGINE should be +an instance of a template-engine object specified in one of the plugins. This +object is stored in the config object. CONTENT should be the object to render as +main part of the page, THEME-FN should be the function to render the page with +and RENDER-ARGS should be additional arguments that should be passed to the +render function(s).")) diff --git a/src/config.lisp b/src/config.lisp index 15b5b1f1..b0c35080 100644 --- a/src/config.lisp +++ b/src/config.lisp @@ -1,7 +1,8 @@ (in-package :coleslaw) (defclass blog () - ((author :initarg :author :reader author) + ((master :initarg :master :reader master) + (author :initarg :author :reader author) (charset :initarg :charset :reader charset) (deploy-dir :initarg :deploy-dir :reader deploy-dir) (domain :initarg :domain :reader domain) @@ -16,8 +17,10 @@ (sitenav :initarg :sitenav :reader sitenav) (staging-dir :initarg :staging-dir :reader staging-dir) (theme :initarg :theme :reader theme) + (template-engine :initarg :template-engine :accessor template-engine) (title :initarg :title :reader title)) (:default-initargs + :master nil :feeds nil :license nil :plugins nil @@ -26,7 +29,23 @@ :lang "en" :page-ext "html" :separator ";;;;;" - :staging-dir "/tmp/coleslaw")) + :staging-dir "/tmp/coleslaw" + :template-engine 'cl-closure)) + +(defmethod initialize-instance :after ((config blog) &rest rest) + "Initialize config object by creating the correct template-engine class and +setting it to template-engine" + (declare (ignore rest)) + (when (master config) (setf *config* config)) + (load-plugins (cons `(,(format nil + "~:@(~A~)" + (string (template-engine config)))) + (plugins config))) + (let ((theme-class (intern (string-upcase (template-engine config)) + (format nil + "~:@(coleslaw-~A~)" + (string (template-engine config)))))) + (setf (template-engine config) (make-instance theme-class)))) (defun dir-slot-reader (config name) "Take CONFIG and NAME, and return a directory pathname for the matching SLOT." @@ -84,6 +103,4 @@ doesn't exist, use the .coleslawrc in the home directory." preferred over the home directory if provided." (with-open-file (in (discover-config-path repo-dir) :external-format :utf-8) (let ((config-form (read in))) - (setf *config* (construct 'blog config-form) - (repo-dir *config*) repo-dir))) - (load-plugins (plugins *config*))) + (construct 'blog (append `(:master t :repo ,repo-dir) config-form))))) diff --git a/src/documents.lisp b/src/documents.lisp index b90d299f..7950fa80 100644 --- a/src/documents.lisp +++ b/src/documents.lisp @@ -63,8 +63,8 @@ is provided, it overrides the route used." "Write the given DOCUMENT to disk as HTML. If THEME-FN is present, use it as the template passing any RENDER-ARGS." (let ((html (if (or theme-fn render-args) - (apply #'render-page document theme-fn render-args) - (render-page document nil))) + (apply #'render-page (template-engine *config*) document theme-fn render-args) + (render-page (template-engine *config*) document nil))) (url (namestring (page-url document)))) (write-file (rel-path (staging-dir *config*) url) html))) diff --git a/src/feeds.lisp b/src/feeds.lisp index 4bebcb0e..56e9a5ff 100644 --- a/src/feeds.lisp +++ b/src/feeds.lisp @@ -16,7 +16,10 @@ (defmethod publish ((doc-type (eql (find-class 'feed)))) (dolist (feed (find-all 'feed)) - (write-document feed (theme-fn (feed-format feed) "feeds")))) + (write-document feed + (get-theme-fn (template-engine *config*) + (feed-format feed) + "feeds")))) ;;; Tag Feeds @@ -34,4 +37,4 @@ (defmethod publish ((doc-type (eql (find-class 'tag-feed)))) (dolist (feed (find-all 'tag-feed)) - (write-document feed (theme-fn (feed-format feed) "feeds")))) + (write-document feed (get-theme-fn (template-engine *config*) (feed-format feed) "feeds")))) diff --git a/src/indexes.lisp b/src/indexes.lisp index 6cbf0562..e6db8f9c 100644 --- a/src/indexes.lisp +++ b/src/indexes.lisp @@ -15,13 +15,14 @@ (with-slots (url) object (setf url (compute-url object slug)))) -(defmethod render ((object index) &key prev next) - (funcall (theme-fn 'index) (list :tags (find-all 'tag-index) - :months (find-all 'month-index) - :config *config* - :index object - :prev prev - :next next))) +(defmethod render ((object index) &rest rest) + (apply (get-theme-fn (template-engine *config*) 'index) + :tags (find-all 'tag-index) + :months (find-all 'month-index) + :config *config* + :index object + (append (find-all 'month-index) + rest))) ;;; Index by Tag diff --git a/src/packages.lisp b/src/packages.lisp index d49035f0..ce9b6d68 100644 --- a/src/packages.lisp +++ b/src/packages.lisp @@ -10,6 +10,8 @@ (:import-from :local-time #:format-rfc1123-timestring) (:import-from :uiop #:getcwd #:ensure-directory-pathname) + (:import-from :djula #:render-template* + #:compile-template*) (:export #:main #:preview #:*config* @@ -21,6 +23,7 @@ #:repo-dir #:staging-dir #:title + #:template-engine ;; Core Classes #:content #:post @@ -30,7 +33,9 @@ #:author-of #:find-content-by-path ;; Theming + Plugin API - #:theme-fn + #:get-theme-fn + #:compile-theme + #:render-page #:plugin-conf-error #:render-text #:add-injection diff --git a/src/posts.lisp b/src/posts.lisp index d8fe29d5..44ffb24a 100644 --- a/src/posts.lisp +++ b/src/posts.lisp @@ -13,11 +13,11 @@ text (render-text text format) author (or author (author *config*))))) -(defmethod render ((object post) &key prev next) - (funcall (theme-fn 'post) (list :config *config* - :post object - :prev prev - :next next))) +(defmethod render ((object post) &rest rest) + (apply (get-theme-fn (template-engine *config*) 'post) + :config *config* + :post object + rest)) (defmethod publish ((doc-type (eql (find-class 'post)))) (loop for (next post prev) on (append '(nil) (by-date (find-all 'post))) diff --git a/src/themes.lisp b/src/themes.lisp index 267178eb..2195f5b7 100644 --- a/src/themes.lisp +++ b/src/themes.lisp @@ -3,6 +3,8 @@ (defparameter *injections* '() "A list that stores pairs of (string . predicate) to inject in the page.") +(defclass template-engine () ()) + (defun add-injection (injection location) "Adds an INJECTION to a given LOCATION for rendering. The INJECTION should be a function that takes a DOCUMENT and returns NIL or a STRING for template insertion." @@ -26,9 +28,14 @@ function that takes a DOCUMENT and returns NIL or a STRING for template insertio (or (find-package (format nil "~:@(coleslaw.theme.~A~)" name)) (error 'theme-does-not-exist :theme name))) -(defun theme-fn (name &optional (package (theme *config*))) - "Find the symbol NAME inside PACKAGE which defaults to the theme package." - (find-symbol (princ-to-string name) (theme-package package))) +(defun get-djula-theme (name) + (symbol-value (intern (string-upcase (format nil "*djula-~A-template*" (string name)))))) + +(defgeneric get-theme-fn (template name &optional package) + (:documentation "Get the function used to render the template for NAME. +The engine used to do this must be specified in TEMPLATE and should be a class +instance of an engine. PACKAGE can be used to specify where to search for +methods to render a template.")) (defun find-theme (theme) "Find the theme prefering themes in the local repo." @@ -37,9 +44,8 @@ function that takes a DOCUMENT and returns NIL or a STRING for template insertio local-theme (app-path "themes/~a/" theme)))) -(defun compile-theme (theme) - "Locate and compile the templates for the given THEME." - (do-files (file (find-theme theme) "tmpl") - (compile-template :common-lisp-backend file)) - (do-files (file (app-path "themes/") "tmpl") - (compile-template :common-lisp-backend file))) +(defgeneric compile-theme (template-engine theme) + (:documentation "Locate and compile the templates for the given THEME and + compile them. The compiling is done appropriately for each template engine + that is specified in TEMPLATE-ENGINE in the form of a template engine class + instance.")) diff --git a/themes/atom.tmpl b/themes/auxiliary/atom.cl-closure similarity index 100% rename from themes/atom.tmpl rename to themes/auxiliary/atom.cl-closure diff --git a/themes/auxiliary/atom.djula b/themes/auxiliary/atom.djula new file mode 100644 index 00000000..ed5fe377 --- /dev/null +++ b/themes/auxiliary/atom.djula @@ -0,0 +1,26 @@ + + + + {{ config.title }} + + + {{ pubdate }} + + {{ config.author }} + + + {% for post in content.content %} + + + {{ post.title }} + {{ post.date }} + {{ post.date }} + + {{ config.author }} + {{ config.domain }} + + {{ post.text |safe}} + + {% endfor %} + + diff --git a/themes/rss.tmpl b/themes/auxiliary/rss.cl-closure similarity index 100% rename from themes/rss.tmpl rename to themes/auxiliary/rss.cl-closure diff --git a/themes/auxiliary/rss.djula b/themes/auxiliary/rss.djula new file mode 100644 index 00000000..fe69cfa1 --- /dev/null +++ b/themes/auxiliary/rss.djula @@ -0,0 +1,25 @@ + + + + {{ config.title }} + {{ config.domain }} + + en-us + {{ pubdate }} + + {% for post in content.content %} + + {{ post.title }} + {{ config.domain }}/{{ post.url }} + {{ post.date }} + {{ config.author }} + {{ config.domain }}/{{ post.url }} + {% for tag in post.tags %} + + {% endfor %} + + + {% endfor %} + + + diff --git a/themes/sitemap.tmpl b/themes/auxiliary/sitemap.cl-closure similarity index 100% rename from themes/sitemap.tmpl rename to themes/auxiliary/sitemap.cl-closure diff --git a/themes/auxiliary/sitemap.djula b/themes/auxiliary/sitemap.djula new file mode 100644 index 00000000..e13af065 --- /dev/null +++ b/themes/auxiliary/sitemap.djula @@ -0,0 +1,9 @@ + + + {% for url in content.urls %} + + {{ config.domain }}/{{ url }} + {{ pubdate }} + + {% endfor %} + diff --git a/themes/hyde-djula/base.html b/themes/hyde-djula/base.html new file mode 100644 index 00000000..3fe57e8d --- /dev/null +++ b/themes/hyde-djula/base.html @@ -0,0 +1,53 @@ + + + + {{ config.title }} + + + + + + + {% if injections.head %} + {% for injection in injections.head %} + {{ injection | safe }} + {% endfor %} + {% endif %} + + + +
+ {% block content %}{% endblock %} +
+ {% if injections.body %} + {% for injection in injections.body %} + {{ injection | safe }} + {% endfor %} + {% endif %} +
+
+ Unless otherwise credited all material + {% if config.license %} + {{ config.license }} + {% else %} + + Creative Commons License + + {% endif %} + by {{ config.author }} + +
+ + diff --git a/themes/hyde-djula/css/cc-by-sa.png b/themes/hyde-djula/css/cc-by-sa.png new file mode 100644 index 00000000..c67509f1 Binary files /dev/null and b/themes/hyde-djula/css/cc-by-sa.png differ diff --git a/themes/hyde-djula/css/logo_large.jpg b/themes/hyde-djula/css/logo_large.jpg new file mode 100644 index 00000000..c4b820d2 Binary files /dev/null and b/themes/hyde-djula/css/logo_large.jpg differ diff --git a/themes/hyde-djula/css/logo_medium.jpg b/themes/hyde-djula/css/logo_medium.jpg new file mode 100644 index 00000000..b4257e6a Binary files /dev/null and b/themes/hyde-djula/css/logo_medium.jpg differ diff --git a/themes/hyde-djula/css/logo_small.jpg b/themes/hyde-djula/css/logo_small.jpg new file mode 100644 index 00000000..ea5c6091 Binary files /dev/null and b/themes/hyde-djula/css/logo_small.jpg differ diff --git a/themes/hyde-djula/css/style.css b/themes/hyde-djula/css/style.css new file mode 100644 index 00000000..44351fba --- /dev/null +++ b/themes/hyde-djula/css/style.css @@ -0,0 +1,100 @@ +#content { background: #fff; padding-top: 1em } +#header { float: right; margin-left: 1em; margin-bottom: 1em } +#coleslaw-logo { float: right; } +a { text-decoration: none; color: #992900 } +a.anchor { color: black } +.date { font-style: italic } +.title { margin-left: 1em } +.article-meta { margin-left: 2.2em; margin-bottom: 2.2em } +.archive-title { font-size: 1em } .article-title { font-size: 2em } +.article-content { margin-left: 2.2em } +.fineprint { text-align: center; font-size: .9em; margin-top: .5em } +.tag-low { font-size: .8em; font-weight: 200 } +.tag-medium { font-size: 1.2em; font-weight: 600 } +.tag-high { font-size: 1.8em; font-weight: 800 } +.navigation { font-size: 1.2em; border-bottom: 1px solid } +body { background-color: white; font-family: Vollkorn; font-size: 14pt } +pre { overflow: auto; margin-left: 1em; padding: 0.5em; border-left: 1px dashed; + background-color: white; padding: .75em .5em; font-family: (unquote mono-font) } +tt { font-size: .9em; font-family: (unquote mono-font) } + +/* Stolen from lisppaste for the colorize output of 3bmd */ +.paste { background-color: #F4F4F4; color: black; } +.paste:hover { background-color: #F4F4F4; color: black; } +.symbol { color : #770055; background-color : transparent; border: 0px; margin: 0px;} +.special { color : #FF5000; background-color : inherit; } +.keyword { color : #770000; background-color : inherit; } +.comment { color : #007777; background-color : inherit; } +.string { color : #777777; background-color : inherit; } +.atom { color : #314F4F; background-color : inherit; } +.macro { color : #FF5000; background-color : inherit; } +.variable { color : #36648B; background-color : inherit; } +.function { color : #8B4789; background-color : inherit; } +.attribute { color : #FF5000; background-color : inherit; } +.character { color : #0055AA; background-color : inherit; } +.syntaxerror { color : #FF0000; background-color : inherit; } +.diff-deleted { color : #5F2121; background-color : inherit; } +.diff-added { color : #215F21; background-color : inherit; } +span.paren1 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren1:hover { color : inherit; background-color : #BAFFFF; } +span.paren2 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren2:hover { color : inherit; background-color : #FFCACA; } +span.paren3 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren3:hover { color : inherit; background-color : #FFFFBA; } +span.paren4 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren4:hover { color : inherit; background-color : #CACAFF; } +span.paren5 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren5:hover { color : inherit; background-color : #CAFFCA; } +span.paren6 { background-color : inherit; -webkit-transition: background-color 0.2s linear; } +span.paren6:hover { color : inherit; background-color : #FFBAFF; } + +@media (max-width: 680px) { + + #content { + padding-top: 0em + } + + .title { + margin-left: 0.1em; + } + + .article-meta { + margin-bottom: 1em; + } + + .article-meta, .article-content { + float: left; + margin-left: 0em; + margin-right: 0em; + width: 90%; + padding-left: 5%; + } + + .article, .article-content { + margin-left: 0em; + text-align: justify; + } + + img { + display: block; + margin-left: auto; + margin-right: auto; + width: 100%; + } + + #coleslaw-logo { + float: none; + } + + #coleslaw-logo img { + margin-left: auto; + margin-right: auto; + float: none; + width: auto; + } + + .fineprint a img { + width: auto; + clear: both; + } +} diff --git a/themes/hyde-djula/index.html b/themes/hyde-djula/index.html new file mode 100644 index 00000000..73d3b066 --- /dev/null +++ b/themes/hyde-djula/index.html @@ -0,0 +1,34 @@ +{% extends "./base.html" %} + +{% block content %} +

{{ $index.title }}

+ {% for obj in index.content %} +
+ {{ obj.title }} +
posted on {{ obj.date }}
+
{{ obj.text | safe }}
+
+ {% endfor %} +
+ {% if prev %} Previous {% endif %} + {% if next %} Next {% endif %} +
+ {% if tags %} +
+

This blog covers + {% for tag in tags %} + {{ tag.name }} + {% if not forloop.last %}, {% endif %} + {% endfor %} +

+ {% endif %} + {% if months %} +
+

View content from + {% for month in months %} + {{ month.name }} + {% if not forloop.last %}, {% endif %} + {% endfor %} +

+ {% endif %} +{% endblock %} diff --git a/themes/hyde-djula/post.html b/themes/hyde-djula/post.html new file mode 100644 index 00000000..2bf66030 --- /dev/null +++ b/themes/hyde-djula/post.html @@ -0,0 +1,31 @@ +{% extends "./base.html" %} + +{% block content %} +
+

{{ post.title }}

+
+ {% if post.tags %} + Tagged as {% for tag in post.tags %} + {{ tag.name }} + {% if not forloop.last %}, {% endif %} + {% endfor %} + {% endif %} +
+
+ {% if post.date %} + Written on {{ post.date }} + {% endif %} +
+
+
+ {{ post.text | safe }} +
+
{{ \n }} + {% if prev %} + Previous
+ {% endif %} + {% if next %} + Next
+ {% endif %} +
+{% endblock %} diff --git a/themes/readable/base.tmpl b/themes/readable/base.tmpl index 2ef6dbb1..34277f74 100644 --- a/themes/readable/base.tmpl +++ b/themes/readable/base.tmpl @@ -16,7 +16,15 @@ {/foreach} {/if} - + {\n} + {if $config} + CONFIG + {else} + NO CONFIG{\n} + {/if} + config: {$config}{\n} + domain: {$config.domain}{\n} + author: {$config.author}{\n}
@@ -37,7 +45,9 @@
-
+ {\n} + {$link} + {\n}
{$raw |noAutoescape}