Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Themeing support #87

Merged
merged 5 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/content/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ title = "Bartholomew"
# logo = "URL to logo"
base_url = "http://localhost:3000"
about = "This site is generated with Bartholomew, the Spin micro-CMS. And this message is in site.toml."
theme = "fermyon"

[extra]
copyright = "The Site Authors"
Expand All @@ -31,6 +32,7 @@ It has a few pre-defined fields:
- logo: a URL or static path to your logo
- base_url: a base URL that templates can use to construct full URLs to content. This can be overridden by setting the `-e BASE_URL="https://example.com"` environment variable for Spin.
- about: a brief description of the site
- theme: the name of the theme for the website from the `/themes/` folder

You can define your own fields in the `[extra]` section. Anything in `[extra]` is not
used by the system itself. But it's a useful way to pass information from one central
Expand Down
84 changes: 84 additions & 0 deletions docs/content/themes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
title = "Bartholomew themes"
date = "2022-07-20T22:44:01.300319091Z"

[extra]

---

Bartholomew supports theming which allows for easy customization of the site along with the user defined tempaltes.

## Adding a theme

Once the initial site has been setup using the [quickstart section](/quickstart). Create a themes folder where you will be able to download different themes.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved
```bash
mkdir themes
```

Once the folder is created, different themes can be added as submodules to the folder which can then in turn be used to theme the site.

```bash
cd themes
git submodule add <Source_to_the_theme>
```

Multiple themes can be added to the themes directory but only one of them will be active at a given time as described in the next section.

## Configuring the site to use the theme

To choose a theme for the website, the `theme` attribute in `config/site.toml` must be configured, where the value is the name of the theme as found in the `themes/` folder.

```toml
title = "Bartholomew Documentation"
base_url = "http://localhost:3000"
about = "The Micro-CMS for WebAssembly and Spin"
theme = "<theme-directory>"

[extra]
copyright = "Fermyon"
github = "https://github.com/fermyon/bartholomew"
twitter = "https://twitter.com/fermyontech"
ga_measurement_id = ""

date_style = "%B %e, %Y"
```
One more step that needs to be done before themes are fully available to the site is to the change the static file server component in `spin.toml` configuration so that it provides the static assets of the selected theme. The convention of mounting the static assets of the themes before the user defined static assets is recommened.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved

```
.
.
.

[[component]]
source = "modules/spin_static_fs.wasm"
id = "fileserver"
files = [ {source = "themes/<name of theme>/static", destination ="/"}, { source = "static/", destination = "/" }, ]
[component.trigger]
route = "/static/..."

```


## Template precedence

When a theme is enabled for a site, both the user defined and theme-provided assets like the templates, scripts and static assets will be available. In case that a theme provided asset and user provided asset have the same name, the user-defined asset takes precedence. This allows for the user to override the theme to allow for customization.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved

As an example, if both `templates/main.hbs` and `themes/<name of thene>/templates/main.hbs` exist, the user defined `templates/main.hbs` takes precedence leading to the rendering engine using the user defined template overriding the theme.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved

## Creating a Theme

Creating a theme for Bartholomew is easy. Create a new folder and initialize it.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved

```
mkdir custom_theme
cd custom_theme
git init
```

Once the git repository is initialized, create the three required directories.
```
mkdir templates scripts static
```

Create the custom theme by placing the handlebar templates in the `template/` folder while the Rhai scripts are places in the `scripts/` folder. All the static assets like the images, JS and CSS are placed in the static folder. For reference on creating templates, refer to the [templates section](/templates).
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved

Once the required changes are done, commit and push the changes to a remote repository, so as to allow for the theme to cloned as a submodule that can be used for themeing a site.
karthik2804 marked this conversation as resolved.
Show resolved Hide resolved
Binary file modified docs/modules/bartholomew.wasm
Binary file not shown.
4 changes: 2 additions & 2 deletions docs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"sass": "^1.49.9"
},
"scripts": {
"spin": "nodemon --watch content --watch static --watch templates --ext md,rhai,hbs,css,js --verbose --legacy-watch --signal SIGINT --exec 'spin up --file spin.toml'",
"spin": "nodemon --watch content --watch static --watch templates --watch themes --ext md,rhai,hbs,css,js --verbose --legacy-watch --signal SIGINT --exec 'spin up --file spin.toml'",
"styles": "npx parcel build static/sass/styles.scss --dist-dir static/css --no-optimize"
}
}
4 changes: 2 additions & 2 deletions docs/spin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ trigger = { type = "http", base = "/" }
[[component]]
source = "modules/bartholomew.wasm"
id = "bartholomew"
files = [ "content/**/*" , "templates/*", "scripts/*", "config/*"]
files = [ "content/**/*" , "templates/*", "themes/**/*", "scripts/*", "config/*"]
[component.trigger]
route = "/..."

[[component]]
source = "modules/spin_static_fs.wasm"
id = "fileserver"
files = [ { source = "static/", destination = "/" } ]
files = [{ source = "static/", destination = "/" }, ]
[component.trigger]
route = "/static/..."
1 change: 1 addition & 0 deletions docs/templates/content_sidebar.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<li><a href="{{site.info.base_url}}/quickstart">Quickstart</a></li>
<li><a href="{{site.info.base_url}}/templates">Templates</a></li>
<li><a href="{{site.info.base_url}}/configuration">Configuration</a></li>
<li><a href="{{site.info.base_url}}/themes">Themes</a></li>
<li><a href="{{site.info.base_url}}/scripting">Scripting</a></li>
<li><a href="{{site.info.base_url}}/markdown">Markdown guide</a></li>
</ul>
Expand Down
Empty file added docs/templates/index.hbs
Empty file.
10 changes: 10 additions & 0 deletions src/bartholomew.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,18 @@ pub fn render(req: Request) -> Result<Response> {
}
eprintln!("Base URL: {:?}", &config.base_url);

// If a theme is specifed, create theme path
let theme_dir = if config.theme.is_some() {
let mut path: PathBuf = PathBuf::from(THEME_PATH);
path.push(config.theme.as_ref().unwrap());
Some(path)
} else {
None
};

let mut engine = template::Renderer::new(
PathBuf::from(TEMPLATE_PATH),
theme_dir,
PathBuf::from(SCRIPT_PATH),
PathBuf::from(CONTENT_PATH),
);
Expand Down
1 change: 1 addition & 0 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::io::Write;

pub const CONTENT_PATH: &str = "/content/";
pub const TEMPLATE_PATH: &str = "/templates/";
pub const THEME_PATH: &str = "/themes/";
pub const SCRIPT_PATH: &str = "/scripts/";
pub const CONFIG_FILE: &str = "/config/site.toml";

Expand Down
31 changes: 29 additions & 2 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct SiteInfo {
pub logo: Option<String>,
pub base_url: Option<String>,
pub about: Option<String>,
pub theme: Option<String>,
pub extra: BTreeMap<String, String>,
}

Expand Down Expand Up @@ -71,6 +72,7 @@ impl From<Content> for PageValues {
/// Renderer can execute a handlebars template and render the results into HTML.
pub struct Renderer<'a> {
pub template_dir: PathBuf,
pub theme_dir: Option<PathBuf>,
pub script_dir: PathBuf,
pub content_dir: PathBuf,
pub show_unpublished: bool,
Expand All @@ -79,9 +81,15 @@ pub struct Renderer<'a> {

impl<'a> Renderer<'a> {
/// Create a new renderer with the necessary directories attached.
pub fn new(template_dir: PathBuf, script_dir: PathBuf, content_dir: PathBuf) -> Self {
pub fn new(
template_dir: PathBuf,
theme_dir: Option<PathBuf>,
script_dir: PathBuf,
content_dir: PathBuf,
) -> Self {
Renderer {
template_dir,
theme_dir,
script_dir,
content_dir,
show_unpublished: false,
Expand All @@ -97,15 +105,34 @@ impl<'a> Renderer<'a> {
/// Load the template directory.
pub fn load_template_dir(&mut self) -> Result<(), anyhow::Error> {
self.register_helpers();

// If there is a theme, load the templates provided by it first
// Allows for user defined tempaltes to take precedence
if self.theme_dir.is_some() {
let mut templates = self.theme_dir.as_ref().unwrap().to_owned();
templates.push("templates");
self.handlebars
.register_templates_directory(".hbs", templates)?;
}
self.handlebars
.register_templates_directory(".hbs", &self.template_dir)?;
Ok(())
}

/// Load the scripts directory
pub fn load_script_dir(&mut self) -> anyhow::Result<()> {
let mut theme_scripts: Vec<PathBuf> = Vec::new();

// If theme has scripts,load it first to follow proper precedence
if self.theme_dir.is_some() {
let mut theme_scripts_path = self.theme_dir.as_ref().unwrap().to_owned();
theme_scripts_path.push("scripts");
theme_scripts = crate::content::all_files(theme_scripts_path)?;
}
let user_scripts = crate::content::all_files(self.script_dir.clone())?;
// TODO: rewrite all_files so we don't need to clone here.
let scripts = crate::content::all_files(self.script_dir.clone())?;
let scripts = [theme_scripts, user_scripts].concat();

for script in scripts {
// Relative file name without extension. Note that we skip any file
// that doesn't have this.
Expand Down