Skip to content

Commit

Permalink
Support clean urls by default.
Browse files Browse the repository at this point in the history
  • Loading branch information
svetlyak40wt committed Apr 29, 2024
1 parent 6a6a640 commit 551e476
Show file tree
Hide file tree
Showing 21 changed files with 255 additions and 116 deletions.
49 changes: 34 additions & 15 deletions docs/difference-from-coleslaw.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,32 @@
"
Staticl config is constructed from lisp function calls and you can benefit from IDE's code completion.
Variable `config` was renamed to `site`.
post -> content
pubdate -> site.pubdate.
site.sitenav -> site.navigation.items also for items inside navigation now have a \"title\" slot instead of \"name\" and also navigation menu can contain submenus, but this requires a special support from the theme. If an item has slot \"item\", then it is a submenu.
The first important variable `config` was renamed to `site`. Secondly, variables `post` and `index` were renamed to `content`. That is it - content of any page, be it a post or a generic page is available as `content` variable inside the template.
index -> content
index.content -> content.items
prev -> content.prev
next -> content.next
tags -> content.tags
obj.date -> obj.created_at
## Changes in navigation
The `site.sitenav` list was renamed to `site.navigation.items`. Also items inside the navigation now have a `title` slot instead of `name` and also navigation menu can contain submenus, but this requires a special support from the theme. If an item has a slot `item`, then it is a submenu. Themes ported from the Coleslaw do not support this submenues.
## Index pages
For index pages a list of items was also moved and now instead of `index.content` a `content.items` should be used.
### Index objects
For objects in `content.items` attribute `obj.text` was renamed to `obj.excerpt`. It is a HTML, so `noAutoescape` filter should be applied (as you did in Coleslaw themes too).
## Other field renames
- `pubdate -> site.pubdate`
- `obj.date -> obj.created_at`
- `post.date -> content.created_at`
- `post.text -> content.html`
- `tags -> content.tags`
- `prev -> content.prev`
- `next -> content.next`
## Working with dates
For templates base on Closure Template, StatiCL defines these filters:
Expand All @@ -23,15 +37,20 @@ For templates base on Closure Template, StatiCL defines these filters:
To define additional filters, inherit your template class from CLOSURE-TEMPLATE and define a method for REGISTER-USER-FILTERS generic-function.
Instead of makin 1.html and symlinking to it from index.html, StatiCL just generates first page as index.html and other pages as 2.html, 3.html, etc.
URLs
## URLs
Templates in Coleslaw used {$site.domain}/ as a prefix to each URL. With StatiCL all URLs are formatted in advance before
variables are passed to the template and you don't have to concatenate string to get a proper URL in a template.
Additional formats
Also, note, that instead of making 1.html and symlinking to it from index.html for post indices, StatiCL just generates first page as index.html and other pages as 2.html, 3.html, etc..
## Pages layout
Coleslaw uses a subfolder `pages/` to keep content of all site pages and put them to the root of the site. Staticl does not implement this logic - it generates an output page with the same path as an original file. For example, if previousl with Coleslaw you put `/pages/about.post` to get `/about.html` page, with Staticl you write `/about.post` source file to generate `/about.html` or `/about/index.html` (depending on clean urls setting).
## Additional formats
* (ql:quickload :staticl/format/spinneret)
Expand Down
2 changes: 1 addition & 1 deletion example/.staticlrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
:url "https://example.com/"
:navigation (menu (item "Blog (EN)" "/blog/")
(item "Blog (RU)" "/ru/blog/")
(item "About" "/about.html"))
(item "About" "/about/"))
:pipeline (list (load-content)
(filter (:path "ru/")
(prev-next-links)
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions qlfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
("quicklisp" .
(:class qlot/source/dist:source-dist
:initargs (:distribution "http://beta.quicklisp.org/dist/quicklisp.txt" :%version :latest)
:initargs (:distribution "https://beta.quicklisp.org/dist/quicklisp.txt" :%version :latest)
:version "2023-10-21"))
("ultralisp" .
(:class qlot/source/dist:source-dist
:initargs (:distribution "http://dist.ultralisp.org/" :%version :latest)
:version "20240330015000"))
:initargs (:distribution "https://dist.ultralisp.org/" :%version :latest)
:version "20240428124000"))
("slynk" .
(:class qlot/source/github:source-github
:initargs (:repos "svetlyak40wt/sly" :ref nil :branch "patches" :tag nil)
Expand Down
73 changes: 73 additions & 0 deletions src/clean-urls.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
(uiop:define-package #:staticl/clean-urls
(:use #:cl)
(:import-from #:staticl/site
#:clean-urls-p
#:site)
(:import-from #:str
#:ends-with-p)
(:import-from #:serapeum
#:->)
(:export #:transform-url
#:transform-filename))
(in-package #:staticl/clean-urls)


(-> clean-url (string)
(values string &optional))

(defun clean-url (url)
(cond
((ends-with-p "/index.html" url)
(subseq url 0 (1+ (- (length url)
(length "/index.html")))))
((ends-with-p ".html" url)
(concatenate 'string
(subseq url 0 (- (length url)
(length ".html")))
"/"))
(t
url)))


(-> clean-pathname (pathname)
(values pathname &optional))

(defun clean-pathname (filename)
(cond
((and (string-equal (pathname-type filename)
"html")
(not (string-equal (pathname-name filename)
"index")))
(merge-pathnames
(make-pathname :directory (list :relative (pathname-name filename))
:name "index"
:type "html")
filename))
(t
filename)))


(defgeneric transform-url (site url)
(:documentation "Converts the URL to the form that should be used on the site.
If the site has the clean-urls setting enabled, then the URL like /some/page.html will be converted
to /some/page/. If clean-urls is not enabled, the URL will remain unchanged.")
(:method ((site site) (url string))
(cond
((clean-urls-p site)
(clean-url url))
(t
url))))


(defgeneric transform-filename (site filename)
(:documentation "Converts the pathname to the form that should be used to write content to the disk.
If the site has the clean-urls setting enabled, then the filename like some/page.html will be converted
to some/page/index.html. If clean-urls is not enabled, the pathname will remain unchanged.")
(:method ((site site) (filename pathname))
(cond
((and (clean-urls-p site))
(clean-pathname filename))
(t
filename))))
31 changes: 18 additions & 13 deletions src/content.lisp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
(uiop:define-package #:staticl/content
(:use #:cl)
(:import-from #:staticl/theme
#:template-vars)
(:import-from #:serapeum
#:->
#:dict)
Expand All @@ -13,6 +11,7 @@
#:site-content-root
#:site)
(:import-from #:alexandria
#:curry
#:with-output-to-file
#:length=)
(:import-from #:staticl/utils
Expand Down Expand Up @@ -45,6 +44,8 @@
(:import-from #:staticl/content/html-content
#:content-html-excerpt
#:content-html)
(:import-from #:staticl/clean-urls
#:transform-filename)
(:export #:supported-content-types
#:content-type
#:content
Expand Down Expand Up @@ -249,10 +250,14 @@
(merge-pathnames
(merge-pathnames (make-pathname :type "html")
relative-path)
stage-dir))))
stage-dir)))

(:method :around ((site site) (content content) (stage-dir pathname))
(transform-filename site
(call-next-method))))


(defmethod object-url ((content content-from-file) &key &allow-other-keys)
(defmethod object-url ((site site) (content content-from-file) &key &allow-other-keys)
(or (slot-value content 'url)
(let* ((root (current-root))
(relative-path (enough-namestring (content-file content)
Expand All @@ -267,8 +272,8 @@

(:method ((site site) (content content) (stream stream))
(let* ((theme (site-theme site))
(content-vars (template-vars content))
(site-vars (template-vars site))
(content-vars (template-vars site content))
(site-vars (template-vars site site))
(vars (dict "site" site-vars
"content" content-vars))
(template-name (content-template content)))
Expand All @@ -280,9 +285,9 @@
(:documentation "Returns an additional list content objects such as RSS feeds or sitemaps."))


(defmethod template-vars :around ((content content) &key (hash (dict)))
(defmethod template-vars :around ((site site) (content content) &key (hash (dict)))
(loop with result = (if (next-method-p)
(call-next-method content :hash hash)
(call-next-method site content :hash hash)
(values hash))
for key being the hash-key of (content-metadata content)
using (hash-value value)
Expand All @@ -295,7 +300,7 @@
;; Here we need transform CLOS objects to hash-tables
;; to make their fields accessable in the template
(standard-object
(template-vars value))
(template-vars site value))
;; Other types are passed as is:
(t
value)))
Expand All @@ -319,7 +324,7 @@
(content-format content))))


(defmethod template-vars ((content content-from-file) &key (hash (dict)))
(defmethod template-vars ((site site) (content content-from-file) &key (hash (dict)))
(setf (gethash "title" hash)
(content-title content)
(gethash "html" hash)
Expand All @@ -343,13 +348,13 @@
)

(if (next-method-p)
(call-next-method content :hash hash)
(call-next-method site content :hash hash)
(values hash)))


(defmethod template-vars ((content content-with-tags-mixin) &key (hash (dict)))
(defmethod template-vars ((site site) (content content-with-tags-mixin) &key (hash (dict)))
(setf (gethash "tags" hash)
(mapcar #'template-vars
(mapcar (curry #'template-vars site)
(content-tags content)))

(if (next-method-p)
Expand Down
1 change: 0 additions & 1 deletion src/core.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
(:import-from #:staticl/current-root
#:with-current-root)
(:import-from #:staticl/url
#:object-url
#:with-base-url)
(:nicknames #:staticl/core)
(:export #:generate
Expand Down
10 changes: 5 additions & 5 deletions src/feeds/base.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@
(defmethod staticl/content:write-content-to-stream ((site site) (feed-file feed-file) stream)
(loop for item in (content-items feed-file)
for feed-entry = (make-instance 'org.shirakumo.feeder:entry
:id (staticl/url:object-url item :full t)
:link (staticl/url:object-url item :full t)
:id (staticl/url:object-url site item :full t)
:link (staticl/url:object-url site item :full t)
:title (staticl/content:content-title item)
:summary (staticl/content/html-content:content-html-excerpt item)
:content (staticl/content::content-html item))
collect feed-entry into entries
finally
(let* ((feed (make-instance 'org.shirakumo.feeder:feed
:id (staticl/url:object-url site :full t)
:link (staticl/url:object-url site :full t)
:id (staticl/url:object-url site site :full t)
:link (staticl/url:object-url site site :full t)
:title (staticl/site:site-title site)
:summary (staticl/site:site-description site)
:content entries))
Expand All @@ -92,7 +92,7 @@
(plump:serialize plump-node stream))))


(defmethod object-url ((feed-file feed-file) &key &allow-other-keys)
(defmethod object-url ((site site) (feed-file feed-file) &key &allow-other-keys)
(let* ((root (current-root))
(relative-path (enough-namestring (target-path feed-file)
root)))
Expand Down
10 changes: 5 additions & 5 deletions src/index/base.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@



(defmethod template-vars ((content index-page) &key (hash (dict)))
(defmethod template-vars ((site site) (content index-page) &key (hash (dict)))
(flet ((item-vars (item)
(dict "url"
(staticl/url:object-url item)
(staticl/url:object-url site item)
"title"
(staticl/content:content-title item)
"created-at"
Expand All @@ -110,19 +110,19 @@
(when (prev-page content)
(dict
"url"
(staticl/url:object-url (prev-page content))))
(staticl/url:object-url site (prev-page content))))
(gethash "next" hash)
(when (next-page content)
(dict
"url"
(staticl/url:object-url (next-page content))))))
(staticl/url:object-url site (next-page content))))))

(if (next-method-p)
(call-next-method content :hash hash)
(values hash)))


(defmethod object-url ((index index-page) &key &allow-other-keys)
(defmethod object-url ((site site) (index index-page) &key &allow-other-keys)
(let* ((root (current-root))
(relative-path (enough-namestring (page-target-path index)
root)))
Expand Down
5 changes: 4 additions & 1 deletion src/index/paginated.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@

(defmethod staticl/pipeline:process-items ((site site) (index paginated-index) content-items)
(loop with only-posts = (remove-if-not #'postp content-items)
for batch in (serapeum:batches only-posts (page-size index))
with sorted-posts = (sort only-posts
#'local-time:timestamp>
:key #'staticl/content:content-created-at )
for batch in (serapeum:batches sorted-posts (page-size index))
for page-number upfrom 1
collect (make-instance 'index-page
:title (funcall (page-title-fn index)
Expand Down
6 changes: 4 additions & 2 deletions src/links/link.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#:->)
(:import-from #:staticl/url
#:object-url)
(:import-from #:staticl/site
#:site)
(:export
#:link))
(in-package #:staticl/links/link)
Expand All @@ -32,9 +34,9 @@
:content content))


(defmethod staticl/theme:template-vars ((link link) &key (hash (dict)))
(defmethod staticl/theme:template-vars ((site site) (link link) &key (hash (dict)))
(dict* hash
"url"
(object-url (link-content link))
(object-url site (link-content link))
"title"
(content-title (link-content link))))
2 changes: 1 addition & 1 deletion src/plugins/sitemap.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

(defmethod write-content-to-stream ((site site) (sitemap sitemap-file) (stream stream))
(render-sitemap (loop for item in (sitemap-content sitemap)
collect (make-url (object-url item :full t)
collect (make-url (object-url site item :full t)
:changefreq :weekly
:priority 0.5))
:stream stream))
Expand Down
12 changes: 12 additions & 0 deletions src/site-url.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(uiop:define-package #:staticl/site-url
(:use #:cl)
(:import-from #:staticl/site
#:site-url
#:site)
(:import-from #:staticl/url
#:object-url))
(in-package #:staticl/site-url)


(defmethod object-url ((site site) (obj site) &key &allow-other-keys)
(site-url obj))
Loading

0 comments on commit 551e476

Please sign in to comment.