~subsetpark/bagatto

ref: 19aea03fe23fe5486890912df7dc4a936ce617a3 bagatto/demo/basic-site/index.janet -rw-r--r-- 5.8 KiB
19aea03f — Zach Smith Basic site demo 4 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
### index.janet
###
### A basic Bagatto demo site.
### 
### This Janet module lays out a minimal, but complete, website using
### Bagatto. We'll use it to explore some of the basic functionality
### of the program.

#
# Global Config
#

## `bagatto/set-output-dir!` will set the top level of the directory
## hierarchy that files are created in. This is quite useful, as it
## allows us to use relative directories elsewhere when linking within
## the site.
(bagatto/set-output-dir! "site")

#
# Helper Functions
#

## Define a utility function that takes a file path and returns the
## basename of the file *without* the extension. For instance, it will
## take "foo/bar/baz.md" and return "baz".
##
## This function makes use of the `path` library, as we see in the call
## to `path/basename`. `path/` will be injected into the evaluation
## environment by the Bagatto executable, so we don't need to import
## it.
(defn- basename [path]
  (->> (path/basename path)
       (string/split ".")
       (first)))

# 
# Data Specification
#

### The first value we need to define is `data`, which is the *data
### specification* for our site. It is a simple key-value data
### structure which maps specification names to specifications. Each
### data spec contains an `attrs` and an optional `src` value. If it
### only contains `attrs`, the value at `attrs` will be included
### directly into the site data. If it contains `src`, the value at
### `src` will be evaluated to load one or more *source files*, and
### the value at `attrs` will be treated as a function that's applied
### to each source file, and expected to return the metadata used in
### rendering the site.

## Define a simple *parser function*. Every parser takes two arguments:
## the contents of a file, and the base attributes, and returns the
## same attributes with some additional information added.
##
## This parser uses the `basename` function to add a single `:basename`
## attribute.
(defn parse-page [_contents attrs]
  (let [basename (basename (attrs :path))]
    (put attrs :basename basename)))

(def data {# :config is a literal struct containing some site-wide
           # metadata.
           :config {:attrs {:title "Bagatto Demo"
                            :description "A minimal website"
                            :author "Z. D. Smith"}}
           # :css is a reference to a single file. As the parser, we
           # specify `bagatto/parse-base`, which simply returns the
           # base :path and :contents attributes.
           :css {:src "styles.css"
                 :attrs bagatto/parse-base}
           # :pages is a reference to all the files that match a
           # wildcard. It uses `bagatto/slurp-*`, which is a function
           # which takes a wildcard and will return a new function
           # that will load all the files that match it.
           #
           # `bagatto/*` will simply list all the files (for later
           # copying); `bagatto/slurp-*` will read them all into
           # memory as well.
           #
           # We will use our `parse-page` function defined
           # above as the parser.
           :pages {:src (bagatto/slurp-* "pages/*.md")
                   :attrs parse-page}})

#
# Site Specification
#

## The second value we need to define is `site`, which will be the
## *site specification* for our site. A site specification maps
## specification names to individual specification entries. Each site
## spec will define one or more files to write by giving the path and
## contents of the new files. The names are not used by Bagatto, but
## are useful to the site author for organizational purposes.

## Define a path generator function. A path generator takes two
## arguments: the site data and a single item. It should output the
## path to be written for a file generated from that item.
##
## In this case the single item will be each of the entries in
## `:pages`, above. `page-path` will be a function; it calls
## `bagatto/%p`, which is a convenient way to generate path generator
## functions. `bagatto/%p` provides a simple dsl for defining
## paths. Here we specify a path that looks like this:
## "pages/{{ (slugify (item :basename)) }}.html".
(def page-path (bagatto/%p "pages" '%i :basename '% ".html"))

(def site {# :index is a single file whose path we can specify as a
           # literal string.
           #
           # To specify the contents of the index we call
           # `bagatto/renderer` which returns a *renderer
           # function*. `bagatto/renderer` takes a template path, and
           # optional attributes to merge into the template
           # arguments. It will return a function which will take the
           # site data and output the contents of the index.
           :index {:dest "index.html"
                   :out (bagatto/renderer "templates/index" {:root "./"})}
           # :css uses `:some` to refer directly to an entry in the
           # data specification. It doesn't provide an `:out` value;
           # therefore, Bagatto will just copy the file directly into
           # the path specified at `:dest`.
           :css {:some :css
                 :dest "css/styles.css"}
           # :pages uses `:each` to iterate over all the entries in
           # the data specification `:pages`. Because this
           # specification will output multiple files, `dest` has to
           # be a function, not a literal path value. It will be
           # called in turn on each of the pages and should output a
           # unique path for each one.
           #
           # Similarly, the renderer specified in this entry will be
           # called once for each page, and will output the contents
           # of the generate web page.
           :pages {:each :pages
                   :dest page-path
                   :out (bagatto/renderer "templates/page" {:root "../"})}})