M content/language/chapters/1-3_numbers.html => content/language/chapters/1-3_numbers.html +1 -1
@@ 5,7 5,7 @@ date: "2022-08-31"
<h1>Numbers</h1>
-<p>Nujel supports normal decimal notation and treats <code>,</code> and <code>_</code> as whitespace characters so you can split big numbers for increased legibility. There is also special syntax for binary, octal and hexadecimal literals. Scientific notation is <b>not</b> supported.</p>
+<p>Nujel supports normal decimal notation and treats <code>,</code> and <code>_</code> as whitespace characters so you can split big numbers for increased legibility. There is also special syntax for binary, octal and hexadecimal literals, scientific notation however is <b>not</b> supported.</p>
<pre class="source source-nujel">
9 ; probably not that suprising
M main.nuj => main.nuj +2 -1
@@ 8,7 8,7 @@
[import [build :as content/build add-resources] "ssg/content"]
[import [add-default :as loader/add-default] "ssg/loader"]
[import [deploy] "ssg/deployment"]
-[import [load-builtin-themes] "ssg/theme"]
+[import [load-builtin-themes load-components] "ssg/theme"]
[defn main [args]
:export
@@ 18,6 18,7 @@
[-> [context/get "./"]
loader/add-default
load-builtin-themes
+ load-components
content/build
add-resources
deploy]]
M ssg/context.nuj => ssg/context.nuj +1 -0
@@ 7,5 7,6 @@
:content-root-dir "content"
:deploy-dir "deploy"
:theme :default
+ :components @[]
:resources-needed @[]
:loaders @[]]]
M ssg/loader/html-content.nuj => ssg/loader/html-content.nuj +13 -1
@@ 2,10 2,22 @@
[import [get-out-path] "../content"]
[import [render] "../theme"]
+[defn mkdir-safe [full-path]
+ [def parts [split full-path "/"]]
+ [def path #nil]
+ [while parts
+ [set! path [if path
+ [cat path "/" [car parts]]
+ [car parts]]]
+ [cdr! parts]
+ [println path]
+ [mkdir path]]]
+
[defn build [ctx path]
"Loader that just copies the file over"
[def dest-path [get-out-path ctx path]]
- [mkdir [path/dirname dest-path]]
+ [mkdir-safe [path/dirname dest-path]]
+ [println dest-path]
[spit dest-path [render ctx path]]
[return dest-path]]
M ssg/theme.nuj => ssg/theme.nuj +82 -24
@@ 13,11 13,18 @@
[tree/set! [tree/ref ctx :resources-needed] [string->keyword path] [cons path dest-path]]
dest-path]
+[defn load-components [ctx]
+ :export
+ [import [load-components :as theme/load-components] [tree/ref themes [tree/ref ctx :theme]]]
+ [theme/load-components ctx]
+ ctx]
+
[defn render [ctx path]
:export
"Apply a theme to a particular file in PATH"
[def theme [tree/ref themes [tree/ref ctx :theme]]]
- [import [render :as cur/render] theme]
+ [import [render :as cur/render load-components] theme]
+ [load-components ctx]
[cur/render ctx path]]
[defn theme/split/rec [theme-text start ret]
@@ 76,6 83,28 @@
[def expr [read fm]]
[apply tree/new expr]]
+[def *cur-page-theme-path* #nil]
+[def *cur-page-ctx* #nil]
+[def *cur-page-path* #nil]
+[def *cur-page-meta* #nil]
+[defn set-page-ctx! [ctx path meta theme-path]
+ [when *cur-page-ctx* [exception "Double set page ctx" ctx]]
+ [set! *cur-page-theme-path* theme-path]
+ [set! *cur-page-ctx* ctx]
+ [set! *cur-page-meta* meta]
+ [set! *cur-page-path* path]]
+
+[defn reset-page-ctx! []
+ [when-not *cur-page-ctx* [exception "Double unset page ctx" #nil]]
+ [set! *cur-page-ctx* #nil]
+ [set! *cur-page-meta* #nil]
+ [set! *cur-page-path* #nil]]
+
+[defn get-ctx [] *cur-page-ctx*]
+[defn get-path [] *cur-page-path*]
+[defn get-meta [] *cur-page-meta*]
+[defn get-theme-path [] *cur-page-theme-path*]
+
[defn get-href* [ctx path target]
[def name [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]]
[def depth [- [length [split name "/"]] 1]]
@@ 95,32 124,61 @@
[tree/ref target :title]]
target]]]]
+[defn render-link [target]
+ [render-link* [get-ctx] [get-path] target]]
+
+[defn get-href [target]
+ [get-href* [get-ctx] [get-path] target]]
+
+[defn navigation [depth]
+ [navigation/build [get-ctx] depth]]
+
+[defn include-resource [res-path]
+ [include-resource* [get-ctx] [fmt "{}/{res-path}" [get-theme-path]] res-path]
+ [get-href res-path]]
+
+[defn page-title []
+ [def ct [ref [get-meta] :title]]
+ [if ct
+ [fmt "{} - {}" [ref [get-ctx] :title] ct]
+ [ref [get-ctx] :title]]]
+
+[defn this-href []
+ [string/cut [get-path] [inc [length [tree/ref [get-ctx] :content-root-dir]]]]]
+
+[defn this-prev-next []
+ [tree/ref [tree/ref [get-ctx] :prev-next-nav]
+ [string->keyword [this-href]]]]
+
+[defn this-prev []
+ [and [this-prev-next]
+ [tree/ref [this-prev-next] :prev]]]
+
+[defn this-next []
+ [and [this-prev-next]
+ [tree/ref [this-prev-next] :next]]]
+
+[defn component [name args]
+ [[tree/ref [tree/ref [get-ctx] :components] name] args]]
+
+[defn add-component [ctx name raw-text]
+ :export
+ [tree/set! [tree/ref ctx :components] name [parse-component raw-text]]]
+
+[defn parse-component [raw-text]
+ :export
+ [def theme-parts [cons 'cat [theme/split raw-text]]]
+ [eval `[fn [args] ~theme-parts]]]
+
[defn parse [+theme-path+ raw-theme-text]
:export
"Parse a theme and return a function that can be called with a ctx and path to apply that theme to some content"
[def theme-parts [cons 'cat [theme/split raw-theme-text]]]
[def theme-form `[fn [ctx path]
- [def parts [split-frontmatter [slurp path]]]
- [def *page-meta* [parse-frontmatter [car parts]]]
- [def content [parse-content ctx path [cdr parts] *page-meta*]]
- [def this-href [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]]
- [def this-prev-next [tree/ref [tree/ref ctx :prev-next-nav] [string->keyword this-href]]]
- [def this-prev [and this-prev-next [tree/ref this-prev-next :prev]]]
- [def this-next [and this-prev-next [tree/ref this-prev-next :next]]]
-
- [defn render-link [target]
- [render-link* ctx path target]]
- [defn get-href [target]
- [get-href* ctx path target]]
- [defn navigation [depth]
- [navigation/build ctx depth]]
- [defn include-resource [res-path]
- [include-resource* ctx [fmt "{+theme-path+}/{res-path}"] res-path]
- [get-href res-path]]
- [defn page-title []
- [def ct [ref *page-meta* :title]]
- [if ct
- [fmt "{} - {}" [ref ctx :title] ct]
- [ref ctx :title]]]
- ~theme-parts]]
+ [def page-parts [split-frontmatter [slurp path]]]
+ [set-page-ctx! ctx path [parse-frontmatter [car page-parts]] +theme-path+]
+ [def content [parse-content ctx path [cdr page-parts] [get-meta]]]
+ [def ret ~theme-parts]
+ [reset-page-ctx!]
+ [return ret]]]
[eval theme-form]]
M ssg/theme/default.nuj => ssg/theme/default.nuj +9 -1
@@ 1,4 1,4 @@
-[import [parse :as theme/parse] "../theme"]
+[import [parse :as theme/parse add-component] "../theme"]
[def +theme-path+ [fmt "{}/default" *module-path*]]
[def main-template [theme/parse +theme-path+ [slurp [fmt "{+theme-path+}/templates/main.html"]]]]
@@ 8,3 8,11 @@
:export
[main-template ctx path]]
+[defn load-components [ctx]
+ "Load all the partials"
+ :export
+ [add-component ctx :Header [slurp [fmt "{+theme-path+}/components/Header.html"]]]
+ [add-component ctx :Favicon [slurp [fmt "{+theme-path+}/components/Favicon.html"]]]
+ [add-component ctx :Footer [slurp [fmt "{+theme-path+}/components/Footer.html"]]]
+ [add-component ctx :Logo [slurp [fmt "{+theme-path+}/components/Logo.html"]]]
+ [add-component ctx :PrevNextNav [slurp [fmt "{+theme-path+}/components/PrevNextNav.html"]]]]
A ssg/theme/default/components/Favicon.html => ssg/theme/default/components/Favicon.html +4 -0
@@ 0,0 1,4 @@
+{{
+[when [tree/ref [get-ctx] :favicon]
+ [fmt "<link rel=\"icon\" rel=\"icon\" type=\"image/png\" href=\"{}\"/>" [get-href [tree/ref [get-ctx] :favicon]]]]
+}}
A => +8 -0
@@ 0,0 1,8 @@
<div>
by {{ [or [ref [get-ctx] :author] "Anonymous"] }}
</div>
<div>
{{ [and [tree/ref [get-meta] :date]
[cat "Published " [tree/ref [get-meta] :date]]]
}}
</div>
A => +4 -0
@@ 0,0 1,4 @@
<nav class="top-nav">
{{ [component :Logo] }}
{{ [join [sort [map [navigation 0] [fn [v] [render-link v]]]] ""] }}
</nav>
A ssg/theme/default/components/Logo.html => ssg/theme/default/components/Logo.html +4 -0
@@ 0,0 1,4 @@
+{{
+[when [tree/ref [get-ctx] :logo]
+ [fmt "<a class=\"logo-link\" href=\"{}\"><img src=\"{}\"/><span>{}</span></a>" [get-href "index.html"] [get-href [tree/ref [get-ctx] :logo]] [tree/ref [get-ctx] :logo-text]]]
+}}
A ssg/theme/default/components/PrevNextNav.html => ssg/theme/default/components/PrevNextNav.html +5 -0
@@ 0,0 1,5 @@
+{{
+[when [and [not [tree/ref [get-meta] :hide-prev-next]] [or [this-prev] [this-next]]]
+ [cat [fmt "<div class=\"prev-chapter\">{}</div>" [render-link [this-prev]]]
+ [fmt "<div class=\"next-chapter\">{}</div>" [render-link [this-next]]]]]
+}}
M ssg/theme/default/templates/main.html => ssg/theme/default/templates/main.html +5 -29
@@ 5,47 5,23 @@
<meta http-equiv="content-type" content="text/html;" charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ [include-resource "resources/main.css"] }}"/>
- {{
- [when [tree/ref ctx :favicon]
- [fmt "<link rel=\"icon\" rel=\"icon\" type=\"image/png\" href=\"{}\"/>" [get-href [tree/ref ctx :favicon]]]]
- }}
- {{
- [defn render-prev-next-nav []
- [when [and [not [tree/ref *page-meta* :hide-prev-next]] [or this-prev this-next]]
- [cat [fmt "<div class=\"prev-chapter\">{}</div>" [render-link this-prev]]
- [fmt "<div class=\"next-chapter\">{}</div>" [render-link this-next]]]]]
- #nil
- }}
+ {{ [component :Favicon] }}
</head>
<body>
<header>
- <nav class="top-nav">
- {{
- [when [tree/ref ctx :logo]
- [fmt "<a class=\"logo-link\" href=\"{}\"><img src=\"{}\"/><span>{}</span></a>" [get-href "index.html"] [get-href [tree/ref ctx :logo]] [tree/ref ctx :logo-text]]]
- }}
- {{ [join [sort [map [navigation 0] [fn [v] [render-link v]]]] ""] }}
- </nav>
+ {{ [component :Header] }}
</header>
<main>
<nav class="chapter-nav top-chapter-nav">
- {{ [render-prev-next-nav] }}
+ {{ [component :PrevNextNav] }}
</nav>
-
{{ content }}
-
<nav class="chapter-nav bottom-chapter-nav">
- {{ [render-prev-next-nav] }}
+ {{ [component :PrevNextNav] }}
</nav>
</main>
<footer>
- <div>
- by {{ [or [ref ctx :author] "Anonymous"] }}
- </div>
- <div>
- {{ [and [tree/ref *page-meta* :date]
- [cat "Published " [tree/ref *page-meta* :date]]] }}
- </div>
+ {{ [component :Footer] }}
</footer>
</body>
</html>