~subsetpark/bagatto

ref: 9043a6ba21a42ef4be5874eee0e5d665c6ecb2c9 bagatto/demo/index.janet -rw-r--r-- 6.8 KiB
9043a6ba — Zach Smith Sourcehut doesnt support SVGs 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
### `index.janet`

### A demo index file for Bagatto.

### This simple module demonstrates the basic functionality of the
### Bagatto program, by defining a simple website.

## We can keep our code organized by splitting it out into multiple
## files. We can then import modules from our index file in the
## normal fashion.
(import helpers)

#
# Bagatto API
#

## Bagatto offers the ability to set default values for any of the
## attributes that it expects to find in a data or site specification
## (which we'll see below). Here we set the `attrs` default to
## `jdn-parser`, which means that, in our `data` struct, if we don't
## specify an attrs attribute, Bagatto will assume it refers to a jdn
## file.
(bagatto/set-defaults! {:attrs bagatto/parse-jdn})
(bagatto/set-output-dir! "site")

#
# Data Helpers
#

## A `parse` function is called for every source file that's loaded
## by Bagatto. It takes two arguments: the contents of the file, and
## some pre-generated attributes that are present for every file.
##
## The attributes available by default are:
## * :path - The path of the file from the index
## * :contents - The contents of the file
##
## (Thus providing the source as the first argument is a little
## unnecessary, but slightly more convenient.)
(defn parse-post [src attrs]
  (let [seq (helpers/int)]
    (put attrs :title (string "Blog Post " seq))
    (put attrs :seq seq))
  (bagatto/parse-mmarkdown src attrs))

#
# Data
#

## A Bagatto index module has to define two variables:
## * `data` is a struct mapping data entry *names* to data *specifications*.
## * `site` is a struct describing all of the files that are to be
##   generated, given the input from `data`. Each site specification
##   also has a *name*, though in this case the names are just to make
##   it easier to read by a human author.

# Our `data` struct has several entries:
# * `config` is a static *attrs* struct, containing arbitrary values
#   to be used in rendering the site.
# * `posts` is a specification using `bagatto/slurp-*`, which accepts a
#   file path wildcard and will stream back all the files that match
#   it. Since it will stream multiple files, `post-attrs` is a
#   function which will be called on each file.
# * `static` uses `bagatto/*`, which operates similarly but just
#   returns the file paths that match the wildcard, and doesn't
#   stream the file contents themselves.
# We also have two examples that specify file paths as :src directly,
# and call different attrs functions on them.
(def data {:config {:attrs {:title "A Demo Bagatto Config"}}
           :posts {:src (bagatto/slurp-* "posts/*.md")
                   :attrs parse-post}
           :static {:src (bagatto/* "static/*")
                    :attrs bagatto/parse-base}
           :config-json {:src "config.json"
                         :attrs bagatto/parse-json}
           # NB: We don't specify `:attrs` here; we set a default
           # value above.
           :config-file {:src "config.jdn"}})

#
# Site
#

## To render a new file, Bagatto calls two functions on the attributes
## that were generated in the data step.
##
## The *path* function takes two arguments - the data generated for
## the whole site in the first step, followed by the attributes for
## the specific source file in question. Since data sources can and
## often will refer to multiple files (as we'll see below), these
## functions will be called for each file, and the second argument
## will change each time.
##
## The *path* function should return the file path that the generated
## file should be placed in.

# Here we use the bagatto/%p function to generate a path function for
# us. It exposes a simple DSL and returns a function that will take
# the site data and a post, and return the path for that post.
(def make-post-path (bagatto/%p "posts" '%i :title '% ".html"))

# We can use another generator function, bagatto/path-copier, in the
# case of static paths. This returns a function which will take an
# item and return a new path with the new base (in this case,
# "site/static" followed by the filename of the item.
(def make-static-path (bagatto/path-copier "static"))

# The index file doesn't need a function to determine its path
# (there's only one of them, and it won't depend on the attributes of
# the index), so we can specify it as a simple string.
(def index-path "index.html")

## The *out* function has the same argument signature as the
## *dest* function. It is also called once for each source file. It
## should return the contents of the new file.

# Here we use the bagatto/renderer function to generate a renderer
# function. It returns a function that will take the site data and a
# post and call `bagatto/render` on the specified template, with the
# site and the post as arguments.
(def render-post (bagatto/renderer "templates/post" {:root "../"}))

# The Posts index is generated from the site data and lists out all
# the posts. Therefore, it isn't rendered out of a specific source
# file. We will only call it once, with the site data as the only
# argument, since there is no series of items that are all being
# rendered.
# 
# The bagatto/renderer function will generate functions that can
# accept only one argument---just the site data---without any specific
# item being rendered. The only difference will be that the `:_item`
# attribute won't be available in the template.
(def render-post-index (bagatto/renderer "templates/posts" {:root "./"}))

# Likewise, our `site` struct has three entries---there doesn't have
# to be any clean mapping between entries in `data` and entries in
# `struct`.
#
# * `post-index` is a single file that lists all the posts. Its path
#   is static; its contents are rendered by the `post-index`
#   function, which takes as a single argument the entire output of
#   the data step, and returns the contents of the new file.
# * `posts` is a site specification which will result in multiple
#   files: one for each element of the `posts` site data. To map it
#   back to that site data, we include an additional attribute,
#   `:each`, which refers to an entry found in the site data table.
#
#   Since we've specified an `:each` attribute, both `make-post-path` and
#   `render-post` will take two arguments: the overall site data, as
#   well as the attributes of the specific data entry from `posts`
#   being rendered in that call.
# * `static` includes an `:each` entry, which means it will map over
#   the multiple entries found in `(data :static)`, but no
#   `:contents`. This means that it will simply use `make-static-path`
#   to generate a new path, then copy the file from the original path
#   to the new one.
(def site {:post-index {:dest index-path
                        :out render-post-index}
           :posts {:each :posts
                   :dest make-post-path
                   :out render-post}
           :static {:each :static
                    :dest make-static-path}})