@richiardiandrea I have finally had some time today for looking at these things. Your second question is easier (adding things to global metadata), so I'm going to start with that. Here's a task I've written to include recent posts in global metadata:
(deftask recent-posts
"Adds the `n` most recent posts to global metadata as `:recent-posts`"
[n num-posts NUMPOSTS int "The number of posts to store"]
(with-pre-wrap fileset
(let [options (merge +recent-posts-defaults+ *opts*)
global-meta (pm/get-global-meta fileset)
recent (->> (pm/get-meta fileset)
(filter post?)
(sort-by :date-published #(compare %2 %1))
(take (:num-posts options)))]
(perun/report-info "recent-posts" "added %s posts to metadata" (count recent))
(pm/set-global-meta fileset (assoc global-meta :recent-posts recent)))))
nice!
How to generalize that now :) because this can apply to any "global" properties you want to pass around in all website's pages
A few thoughts - I think you should be able to modify this to get tags from the entries instead. Also, I think maybe that your use-case should be an automatic feature of the tags
task.
Yep basically I need a task that let me append to global starting from the entries (no filtering)
Will start from the above
Maybe contribute back if I like what I am doing :)
that sounds great!
for your other question about paginating the results of assortment
- it is possible to write a grouper
function that would do what you want, but it is not as easy out of the box as I'd like. I'm still thinking about how best to improve assortment
, but in the meantime, would an example of a grouper
function help?
@bhagany I think I will not paginate in the first version so low priority ;) I have a grouper function that does that..was just wondering whether I was missing something
okay, sounds good - you aren't missing anything π
It was such a nice experience to work with perun especially using Deraen's boot-livereload
The only thing is that I am compiling less at every watch so it is kind of a slower refreshing experience
ah, hrm. it compiles even without a css change?
I think perun should be able to help with that, if you wouldn't mind posting that less task
Yes no well, I rolled my own less task because I am using the js less compiler..but I haven't implemented the check for previously changed files
okay, you may want to look into using io.perun.content-task
- it is basically an abstraction of the file-watching pattern that you just need to plug a rendering function into
@bhagany oh that's cool
the task is this: https://github.com/degree9/boot-css/pull/1
so maybe I should chain the two somehow
nice! looking
@bhagany in the above, is post?
a perun function?
ah, no sorry -
(defn post?
[{:keys [path]}]
(.startsWith path "public/posts/"))
it's pretty specific to my particular usage
oh ok gotcha
can some meta on the fileset obj can be used as well? do we have any available?
yep, you can call io.perun.meta/get-global-meta
in any task to get the current global metadata
(it takes the fileset)
(and I just corrected that namespace, sorry)
np π
so there is no metadata on each individual entry of the fileset, only "global" am I right?
there is metadata on each entry
my post?
filter is using the :path
key of that metadata, on each entry, for instance
ah that, right
so if I had a :post
entry I can just read that one
yeah, assuming you've put it there by some means, like metadata at the top of a markdown file, or meta
arguments passed to perun tasks
yep that was the plan π
but I guess I will stick to your task for now, I have a folder for the posts as well
sounds good π
and here you go, here is the other simple one:
(deftask all-tags
"Adds all the found tags as :all-tags global-meta"
[]
(with-pre-wrap fileset
(let [options (merge +recent-posts-defaults+ *opts*)
global-meta (pmeta/get-global-meta fileset)
all-tags (->> (pmeta/get-meta fileset)
(filter post?)
(mapcat :tags)
(vec))]
(pcore/report-info "all-tags" "added %s to metadata" all-tags)
(pmeta/set-global-meta fileset (assoc global-meta :all-tags all-tags)))))
looks great!
I actually need dedupication there π
ahhhh. right
hrm... does lessc report the files it writes?
I don't think it does...
okay, I'll see if I can work around that
I was checking content-task
and I saw that it needs more things in there...
yeah, my intuition says that you'd be able to use other things that perun defines for those other arguments, but I'm not absolutely sure
also the all-tags
seems not to work because it needs to happen after rendering the posts...
ah... yes
uhm, actually even :recent-posts
does not display in the individual posts
yeah, my needs allow me to call recent-posts
after the initial rendering
but I'm assuming you need the tags on each page, in a menu or sidebar of some sort?
yep
okay, I have a solution for you. well, actually, an example
I tried just now to render twice, I get a frankestain, but I see the tags and the posts
ah, you're on the right track
one sec
https://github.com/bhagany/nicerthantriton.com/blob/master/build.boot#L147-L149
I'm calling render
twice there, but I'm using two different render functions
the second one basically wraps the content produced by the first one
uhm...
in your case, you could do the initial render of the content that's unique to each page, then collect metadata, then render each again
let me bend my mind for a sec, not sure I get this π
no worries, I'm here to help π
so my second renderer would render only the menu/sidebar?
yes, right
if that doesn't appeal to you, I think there's another way too, if you'd like to hear it
I'd like to, just to see if it is less code change
okay. is the metadata you need to generate your sidebar at the head of your markdown files?
yes, basically :tags
+ :recent-posts
for now
okay, if you take a look at the markdown task, you'll see that it's the composition of two simpler tasks: yaml-metadata
and markdown*
ah!
that would allow you to split up the work that markdown
does, so that metadata is collected, then you can run your custom tasks, and then markdown*
yep that would work for :tags
, not for :recent-posts
if I understand correctly
oh well
unless I only display :title
and :headline
I'm not sure I follow
uhm ok let me try first your suggestion
checking those tasks..
okay, let me know if you have any questions
thanks a lot π really appreaciate!
@bhagany that first solution does not seem to work for me...I basically call a page
function already...which wraps...but moving the sidebar is not enough, the content also changes...rendering twice I thought would replace the file but for some reason it does not
Ah if the content also changes, then yeah, that wouldnβt work
Iβm confused about the file replacement not happening though
yeah me too...I am investigating
it looks like the rendered the second time around has the content of the first render
yes so :content
now contains the whole html
Ah, yes, sorry I wasnβt clearer about that
Itβs going to progressively build up the html, from the inside out
You can take a look at the rendering functions for http://nicerthantriton.com to see
ok now I see why that works π
@bhagany sorry if I bombard
Youβre fine, go ahead :)
but it is not hmtl
I see now in :content
π
I see a string containing hiccup
After which task?
now I do:
(perun/render :out-dir posts-dir :renderer '<http://com.andrearichiardi.blog.post/render-content|com.andrearichiardi.blog.post/render-content> :filterer post?)
(recent-posts)
(all-tags)
(perun/render :out-dir posts-dir :renderer '<http://com.andrearichiardi.blog.post/render-page|com.andrearichiardi.blog.post/render-page>)
i see you are doing an into
the second time in page
so I was expecting hiccup in there...
oh wait
so the first time :content
is set to whatever the first render returns
is it converted to string?
yes, I think it'll be the file contents as a string
I'm trying to understand why I have that into
though...
yeah it looks like your return html5
stuff from post...
I think maybe that's just leftover from an earlier iteration of this code...
before I modified render
to work this way, I used function composition to achieve what I wanted, and in that case, I think that content was a hiccup data structure
and now that it's a string it kind of accidentally works
if my first renderer wrap thing with hiccup.core/html5
, then I receive hiccup
as data in the second render
in the :content
key?
yep
that's really odd...
so this works:
(defn render-content [{global-meta :meta entries :entries entry :entry}]
(html5 ;; I should not need this, maybe perun bug?
[:div.twelve.wide.column
"<!-- Post -->"
[:div.ui.right.floated.basic.segment
[:div.ui.compact.segments
[:div.ui.segment
[:a.ui.medium.image {:href (:canonical-url entry)}
[:img {:src (or (:image entry) "<http://p-hold.com/300/250>")}]]]
(when-let [sponsor-img (:sponsor-image entry)]
[:div.ui.right.aligned.basic.secondary.segment
[:div "Sponsored by"
[:a.ui.tiny.image {:href (:sponsor-url entry)}
[:img {:src sponsor-img}]]]])]]
[:div (:content entry)]
"<!-- End Post -->"]))
(defn render-page [{global-meta :meta entries :entries entry :entry}]
(let [all-tags (or (:all-tags entry) (into #{} (mapcat :tags) entries))
latest-posts (or (:latest-posts entry) (take 3 entries))
active-tags (->> [(:tag entry)] (keep identity) (into #{}))]
(base/page
global-meta
[:div.ui.centered.main.stackable.reverse.grid.container {:role "content"}
(:content entry) ;; will receive the html from render-content above
"<!-- Sidebar -->"
(base/sidebar all-tags latest-posts active-tags)
"<!-- End Sidebar -->"])))
thanks, was just going to ask for that π
oh, that works
I missed that part
so yes, that's what I would expect - you were expecting not to have to call html5
?
yep in render-content
okay, yeah, render
isn't tied to any particular html renderer, so it's up to you to figure out how you want to return html
but the return of your render function needs to be the string that you want written to the file
(also, it doesn't have to be html)
lhm
so :content
just needs to be a string
yes, right
let me try one thing
@bhagany fun!
(ns <http://com.andrearichiardi.blog.post|com.andrearichiardi.blog.post>
(:require [clojure.edn :as edn]
[com.andrearichiardi.blog.base :as base]))
(defn render-content [{global-meta :meta entries :entries entry :entry}]
(pr-str
[:div.twelve.wide.column
"<!-- Post -->"
[:div.ui.right.floated.basic.segment
[:div.ui.compact.segments
[:div.ui.segment
[:a.ui.medium.image {:href (:canonical-url entry)}
[:img {:src (or (:image entry) "<http://p-hold.com/300/250>")}]]]
(when-let [sponsor-img (:sponsor-image entry)]
[:div.ui.right.aligned.basic.secondary.segment
[:div "Sponsored by"
[:a.ui.tiny.image {:href (:sponsor-url entry)}
[:img {:src sponsor-img}]]]])]]
[:div (:content entry)]
"<!-- End Post -->"]))
(defn render-page [{global-meta :meta entries :entries entry :entry}]
(let [all-tags (or (:all-tags entry) (into #{} (mapcat :tags) entries))
latest-posts (or (:latest-posts entry) (take 3 entries))
active-tags (->> [(:tag entry)] (keep identity) (into #{}))]
(base/page
global-meta
[:div.ui.centered.main.stackable.reverse.grid.container {:role "content"}
(edn/read-string (:content entry)) ;; will receive the html from render-content above
"<!-- Sidebar -->"
(base/sidebar all-tags latest-posts active-tags)
"<!-- End Sidebar -->"])))
hehehehehe, so that outputs the hiccup as a string, then?
yes pr-str
outputs clojure data
nice
I feel better to have data there π
this could be a topic for my new blog π
it's interesting, it will definitely be more flexible for subsequent renders
you could serialize and pass a function over π
other question...sometimes yaml errors out with:
ll; mapping values are not allowed here; in 'string', line 4, column 87:
... in a GitHub blog? The answer is: of course you can! At the end ...
^
problem: "mapping values are not allowed here"
problemMark: #object[org.yaml.snakeyaml.error.Mark 0x5cf45f80 " in 'string', line 4, column 87:\n ... in a GitHub blog? The answer is: of course you can! At the end ... \n ^"]
ah maybe a character that means something