add config

This commit is contained in:
liquidex 2023-08-27 15:59:52 +02:00
parent 2c2d529056
commit 00947ec966
8 changed files with 91 additions and 41 deletions

View file

@ -105,7 +105,7 @@
- but without overwhelming your computer or bandwidth
% id = "01H89RFHCQ1XA3BB3BTKXH36CX"
- you can disable the JavaScript, and everything will still work
- you can disable the JavaScript, and everything will mostly work
% id = "01H89RFHCQS2WW7PBP1YV0BEJZ"
- but you may not find the experience favorable
@ -123,7 +123,9 @@
+ can you even call it that?
% id = "01H89RFHCQ48R7BCZV8JWPVFCY"
- have I invented something new here?
+ have I invented something new here?
- the "Choose Your Own Poem" lol
% id = "01H89RFHCQAXJ0ST31TP1A104V"
+ ### the treehouse is a mostly statically generated website

View file

@ -20,6 +20,7 @@ use walkdir::WalkDir;
use crate::{
cli::parse::parse_tree_with_diagnostics,
config::Config,
html::{navmap::build_navigation_map, tree::branches_to_html},
tree::SemaRoots,
};
@ -95,7 +96,7 @@ impl Generator {
Ok(())
}
fn generate_all_files(&self, dirs: &Dirs<'_>) -> anyhow::Result<Treehouse> {
fn generate_all_files(&self, config: &Config, paths: &Paths<'_>) -> anyhow::Result<Treehouse> {
let mut treehouse = Treehouse::new();
let mut handlebars = Handlebars::new();
@ -103,7 +104,7 @@ impl Generator {
&mut handlebars,
&mut treehouse,
"tree",
&dirs.template_dir.join("tree.hbs"),
&paths.template_dir.join("tree.hbs"),
)?;
struct ParsedTree {
@ -116,11 +117,11 @@ impl Generator {
for path in &self.tree_files {
let utf8_filename = path.to_string_lossy();
let tree_path = path.strip_prefix(dirs.content_dir).unwrap_or(path);
let tree_path = path.strip_prefix(paths.content_dir).unwrap_or(path);
let target_path = if tree_path == OsStr::new("index.tree") {
dirs.target_dir.join("index.html")
paths.target_dir.join("index.html")
} else {
dirs.target_dir.join(tree_path).with_extension("html")
paths.target_dir.join(tree_path).with_extension("html")
};
debug!("generating: {path:?} -> {target_path:?}");
@ -162,12 +163,19 @@ impl Generator {
branches_to_html(
&mut tree,
&mut treehouse,
config,
parsed_tree.file_id,
&roots.branches,
);
treehouse.roots.insert(parsed_tree.tree_path, roots);
let template_data = TemplateData { tree };
#[derive(Serialize)]
pub struct TemplateData<'a> {
pub config: &'a Config,
pub tree: String,
}
let template_data = TemplateData { config, tree };
let templated_html = match handlebars.render("tree", &template_data) {
Ok(html) => html,
Err(error) => {
@ -196,37 +204,38 @@ impl Generator {
}
#[derive(Debug, Clone, Copy)]
pub struct Dirs<'a> {
pub struct Paths<'a> {
pub target_dir: &'a Path,
pub static_dir: &'a Path,
pub template_dir: &'a Path,
pub content_dir: &'a Path,
pub config_file: &'a Path,
}
#[derive(Serialize)]
pub struct TemplateData {
pub tree: String,
}
pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
pub fn regenerate(paths: &Paths<'_>) -> anyhow::Result<()> {
let start = Instant::now();
info!("loading config");
let mut config = Config::load(paths.config_file)?;
config.site = std::env::var("TREEHOUSE_SITE").unwrap_or(config.site);
info!("cleaning target directory");
let _ = std::fs::remove_dir_all(dirs.target_dir);
std::fs::create_dir_all(dirs.target_dir)?;
let _ = std::fs::remove_dir_all(paths.target_dir);
std::fs::create_dir_all(paths.target_dir)?;
info!("copying static directory to target directory");
copy_dir(dirs.static_dir, dirs.target_dir.join("static"))?;
copy_dir(paths.static_dir, paths.target_dir.join("static"))?;
info!("generating standalone pages");
let mut generator = Generator::default();
generator.add_directory_rec(dirs.content_dir)?;
let treehouse = generator.generate_all_files(dirs)?;
generator.add_directory_rec(paths.content_dir)?;
let treehouse = generator.generate_all_files(&config, paths)?;
info!("generating navigation map");
let navigation_map = build_navigation_map(&treehouse, "index");
std::fs::write(
dirs.target_dir.join("navmap.js"),
paths.target_dir.join("navmap.js"),
navigation_map.to_javascript(),
)?;
@ -238,10 +247,10 @@ pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
Ok(())
}
pub fn regenerate_or_report_error(dirs: &Dirs<'_>) {
pub fn regenerate_or_report_error(paths: &Paths<'_>) {
info!("regenerating site content");
match regenerate(dirs) {
match regenerate(paths) {
Ok(_) => (),
Err(error) => eprintln!("error: {error:?}"),
}

View file

@ -0,0 +1,25 @@
use std::{collections::HashMap, path::Path};
use anyhow::Context;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
/// Website root; used when generating links.
/// Can also be specified using the environment variable `$TREEHOUSE_SITE`. (this is the
/// preferred way of setting this in production, so as not to clobber treehouse.toml.)
pub site: String,
/// User-defined keys.
pub user: HashMap<String, String>,
/// Links exported to Markdown for use with reference syntax `[text][key]`.
pub links: HashMap<String, String>,
}
impl Config {
pub fn load(path: &Path) -> anyhow::Result<Self> {
let string = std::fs::read_to_string(path).context("cannot read config file")?;
toml_edit::de::from_str(&string).context("error in config file")
}
}

View file

@ -4,6 +4,7 @@ use pulldown_cmark::{BrokenLink, LinkType};
use treehouse_format::pull::BranchKind;
use crate::{
config::Config,
html::EscapeAttribute,
state::{FileId, Treehouse},
tree::{attributes::Content, SemaBranchId},
@ -14,6 +15,7 @@ use super::{markdown, EscapeHtml};
pub fn branch_to_html(
s: &mut String,
treehouse: &mut Treehouse,
config: &Config,
file_id: FileId,
branch_id: SemaBranchId,
) {
@ -110,7 +112,8 @@ pub fn branch_to_html(
if let Content::Link(link) = &branch.attributes.content {
write!(
s,
"<noscript><a class=\"navigate icon-go\" href=\"{}.html\">Go to linked tree: <code>{}</code></a></noscript>",
"<noscript><a class=\"navigate icon-go\" href=\"{}/{}.html\">Go to linked tree: <code>{}</code></a></noscript>",
EscapeAttribute(&config.site),
EscapeAttribute(link),
EscapeHtml(link),
)
@ -122,7 +125,8 @@ pub fn branch_to_html(
if let Content::Link(link) = &branch.attributes.content {
write!(
s,
"<a class=\"icon icon-go\" href=\"{}.html\" title=\"linked tree\"></a>",
"<a class=\"icon icon-go\" href=\"{}/{}.html\" title=\"linked tree\"></a>",
EscapeAttribute(&config.site),
EscapeAttribute(link),
)
.unwrap();
@ -144,7 +148,7 @@ pub fn branch_to_html(
let num_children = branch.children.len();
for i in 0..num_children {
let child_id = treehouse.tree.branch(branch_id).children[i];
branch_to_html(s, treehouse, file_id, child_id);
branch_to_html(s, treehouse, config, file_id, child_id);
}
s.push_str("</ul>");
}
@ -159,12 +163,13 @@ pub fn branch_to_html(
pub fn branches_to_html(
s: &mut String,
treehouse: &mut Treehouse,
config: &Config,
file_id: FileId,
branches: &[SemaBranchId],
) {
s.push_str("<ul>");
for &child in branches {
branch_to_html(s, treehouse, file_id, child);
branch_to_html(s, treehouse, config, file_id, child);
}
s.push_str("</ul>");
}

View file

@ -3,12 +3,13 @@ use std::path::Path;
use clap::Parser;
use cli::{
fix::fix_file_cli,
regenerate::{self, regenerate_or_report_error, Dirs},
regenerate::{self, regenerate_or_report_error, Paths},
Command, ProgramArgs,
};
use log::{error, info};
mod cli;
mod config;
mod html;
mod paths;
mod state;
@ -19,8 +20,9 @@ async fn fallible_main() -> anyhow::Result<()> {
match args.command {
Command::Regenerate(regenerate_args) => {
let dirs = Dirs {
let dirs = Paths {
target_dir: Path::new("target/site"),
config_file: Path::new("treehouse.toml"),
// NOTE: These are intentionally left unconfigurable from within treehouse.toml
// because this is is one of those things that should be consistent between sites.

View file

@ -1,3 +1,5 @@
// This is definitely not a three.js ripoff.
import { navigationMap } from "/navmap.js";
const branchStateKey = "treehouse.openBranches";
@ -68,7 +70,7 @@ class LinkedBranch extends Branch {
async loadTreePromise(_initiator) {
try {
let response = await fetch(`/${this.linkedTree}.html`);
let response = await fetch(`${TREEHOUSE_SITE}/${this.linkedTree}.html`);
if (response.status == 404) {
throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`;
}
@ -107,7 +109,7 @@ function expandDetailsRecursively(element) {
}
function navigateToPage(page) {
window.location.pathname = `/${page}.html`
window.location.href = `${TREEHOUSE_SITE}/${page}.html`
}
async function navigateToBranch(fragment) {

View file

@ -9,18 +9,19 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ site }}/static/css/main.css">
<link rel="stylesheet" href="{{ site }}/static/css/tree.css">
<link rel="stylesheet" href="{{ site }}/static/font/font.css">
<link rel="stylesheet" href="{{ config.site }}/static/css/main.css">
<link rel="stylesheet" href="{{ config.site }}/static/css/tree.css">
<link rel="stylesheet" href="{{ config.site }}/static/font/font.css">
<script type="module" src="{{ site }}/navmap.js"></script>
<script type="module" src="{{ site }}/static/js/tree.js"></script>
<script type="module" src="{{ site }}/static/js/usability.js"></script>
<script>const TREEHOUSE_SITE = `{{ config.site }}`;</script>
<script type="module" src="{{ config.site }}/navmap.js"></script>
<script type="module" src="{{ config.site }}/static/js/tree.js"></script>
<script type="module" src="{{ config.site }}/static/js/usability.js"></script>
</head>
<body>
<nav>
<a href="{{ site }}/" title="Back to homepage">
<a href="{{ config.site }}/" title="Back to homepage">
<svg class="logo" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M8 3H7H6V4V5H4V6H6V9V10H7H10V12H11V10H12H13V9V8V7H12H11H10V8V9H7V6H8H9V5V4V3H8ZM12 9H11V8H12V9ZM7 5V4H8V5H7ZM3 5H2V6H3V5ZM10 13H11V14H10V13Z"

View file

@ -1,5 +1,9 @@
# User settings go here. These are (string, string) key-value pairs.
# They are available under `config.user`.
site = "http://localhost:8080"
[user]
title = "treehouse"
title = "liquidex's treehouse"
author = "liquidex"
[links]
"stitchkit/repo" = "https://github.com/liquidev/stitchkit"
"dawd3/repo" = "https://github.com/liquidev/dawd3"