add config
This commit is contained in:
parent
2c2d529056
commit
00947ec966
|
@ -105,7 +105,7 @@
|
||||||
- but without overwhelming your computer or bandwidth
|
- but without overwhelming your computer or bandwidth
|
||||||
|
|
||||||
% id = "01H89RFHCQ1XA3BB3BTKXH36CX"
|
% id = "01H89RFHCQ1XA3BB3BTKXH36CX"
|
||||||
- you can disable the JavaScript, and everything will still work
|
- you can disable the JavaScript, and everything will mostly work
|
||||||
|
|
||||||
% id = "01H89RFHCQS2WW7PBP1YV0BEJZ"
|
% id = "01H89RFHCQS2WW7PBP1YV0BEJZ"
|
||||||
- but you may not find the experience favorable
|
- but you may not find the experience favorable
|
||||||
|
@ -123,7 +123,9 @@
|
||||||
+ can you even call it that?
|
+ can you even call it that?
|
||||||
|
|
||||||
% id = "01H89RFHCQ48R7BCZV8JWPVFCY"
|
% id = "01H89RFHCQ48R7BCZV8JWPVFCY"
|
||||||
- have I invented something new here?
|
+ have I invented something new here?
|
||||||
|
|
||||||
|
- the "Choose Your Own Poem" lol
|
||||||
|
|
||||||
% id = "01H89RFHCQAXJ0ST31TP1A104V"
|
% id = "01H89RFHCQAXJ0ST31TP1A104V"
|
||||||
+ ### the treehouse is a mostly statically generated website
|
+ ### the treehouse is a mostly statically generated website
|
||||||
|
|
|
@ -20,6 +20,7 @@ use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::parse::parse_tree_with_diagnostics,
|
cli::parse::parse_tree_with_diagnostics,
|
||||||
|
config::Config,
|
||||||
html::{navmap::build_navigation_map, tree::branches_to_html},
|
html::{navmap::build_navigation_map, tree::branches_to_html},
|
||||||
tree::SemaRoots,
|
tree::SemaRoots,
|
||||||
};
|
};
|
||||||
|
@ -95,7 +96,7 @@ impl Generator {
|
||||||
Ok(())
|
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 treehouse = Treehouse::new();
|
||||||
|
|
||||||
let mut handlebars = Handlebars::new();
|
let mut handlebars = Handlebars::new();
|
||||||
|
@ -103,7 +104,7 @@ impl Generator {
|
||||||
&mut handlebars,
|
&mut handlebars,
|
||||||
&mut treehouse,
|
&mut treehouse,
|
||||||
"tree",
|
"tree",
|
||||||
&dirs.template_dir.join("tree.hbs"),
|
&paths.template_dir.join("tree.hbs"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
struct ParsedTree {
|
struct ParsedTree {
|
||||||
|
@ -116,11 +117,11 @@ impl Generator {
|
||||||
for path in &self.tree_files {
|
for path in &self.tree_files {
|
||||||
let utf8_filename = path.to_string_lossy();
|
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") {
|
let target_path = if tree_path == OsStr::new("index.tree") {
|
||||||
dirs.target_dir.join("index.html")
|
paths.target_dir.join("index.html")
|
||||||
} else {
|
} else {
|
||||||
dirs.target_dir.join(tree_path).with_extension("html")
|
paths.target_dir.join(tree_path).with_extension("html")
|
||||||
};
|
};
|
||||||
debug!("generating: {path:?} -> {target_path:?}");
|
debug!("generating: {path:?} -> {target_path:?}");
|
||||||
|
|
||||||
|
@ -162,12 +163,19 @@ impl Generator {
|
||||||
branches_to_html(
|
branches_to_html(
|
||||||
&mut tree,
|
&mut tree,
|
||||||
&mut treehouse,
|
&mut treehouse,
|
||||||
|
config,
|
||||||
parsed_tree.file_id,
|
parsed_tree.file_id,
|
||||||
&roots.branches,
|
&roots.branches,
|
||||||
);
|
);
|
||||||
treehouse.roots.insert(parsed_tree.tree_path, roots);
|
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) {
|
let templated_html = match handlebars.render("tree", &template_data) {
|
||||||
Ok(html) => html,
|
Ok(html) => html,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
@ -196,37 +204,38 @@ impl Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Dirs<'a> {
|
pub struct Paths<'a> {
|
||||||
pub target_dir: &'a Path,
|
pub target_dir: &'a Path,
|
||||||
pub static_dir: &'a Path,
|
pub static_dir: &'a Path,
|
||||||
pub template_dir: &'a Path,
|
pub template_dir: &'a Path,
|
||||||
pub content_dir: &'a Path,
|
pub content_dir: &'a Path,
|
||||||
|
|
||||||
|
pub config_file: &'a Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
pub fn regenerate(paths: &Paths<'_>) -> anyhow::Result<()> {
|
||||||
pub struct TemplateData {
|
|
||||||
pub tree: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
|
|
||||||
let start = Instant::now();
|
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");
|
info!("cleaning target directory");
|
||||||
let _ = std::fs::remove_dir_all(dirs.target_dir);
|
let _ = std::fs::remove_dir_all(paths.target_dir);
|
||||||
std::fs::create_dir_all(dirs.target_dir)?;
|
std::fs::create_dir_all(paths.target_dir)?;
|
||||||
|
|
||||||
info!("copying static directory to target directory");
|
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");
|
info!("generating standalone pages");
|
||||||
let mut generator = Generator::default();
|
let mut generator = Generator::default();
|
||||||
generator.add_directory_rec(dirs.content_dir)?;
|
generator.add_directory_rec(paths.content_dir)?;
|
||||||
let treehouse = generator.generate_all_files(dirs)?;
|
let treehouse = generator.generate_all_files(&config, paths)?;
|
||||||
|
|
||||||
info!("generating navigation map");
|
info!("generating navigation map");
|
||||||
let navigation_map = build_navigation_map(&treehouse, "index");
|
let navigation_map = build_navigation_map(&treehouse, "index");
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
dirs.target_dir.join("navmap.js"),
|
paths.target_dir.join("navmap.js"),
|
||||||
navigation_map.to_javascript(),
|
navigation_map.to_javascript(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -238,10 +247,10 @@ pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn regenerate_or_report_error(dirs: &Dirs<'_>) {
|
pub fn regenerate_or_report_error(paths: &Paths<'_>) {
|
||||||
info!("regenerating site content");
|
info!("regenerating site content");
|
||||||
|
|
||||||
match regenerate(dirs) {
|
match regenerate(paths) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(error) => eprintln!("error: {error:?}"),
|
Err(error) => eprintln!("error: {error:?}"),
|
||||||
}
|
}
|
||||||
|
|
25
crates/treehouse/src/config.rs
Normal file
25
crates/treehouse/src/config.rs
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ use pulldown_cmark::{BrokenLink, LinkType};
|
||||||
use treehouse_format::pull::BranchKind;
|
use treehouse_format::pull::BranchKind;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
config::Config,
|
||||||
html::EscapeAttribute,
|
html::EscapeAttribute,
|
||||||
state::{FileId, Treehouse},
|
state::{FileId, Treehouse},
|
||||||
tree::{attributes::Content, SemaBranchId},
|
tree::{attributes::Content, SemaBranchId},
|
||||||
|
@ -14,6 +15,7 @@ use super::{markdown, EscapeHtml};
|
||||||
pub fn branch_to_html(
|
pub fn branch_to_html(
|
||||||
s: &mut String,
|
s: &mut String,
|
||||||
treehouse: &mut Treehouse,
|
treehouse: &mut Treehouse,
|
||||||
|
config: &Config,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
branch_id: SemaBranchId,
|
branch_id: SemaBranchId,
|
||||||
) {
|
) {
|
||||||
|
@ -110,7 +112,8 @@ pub fn branch_to_html(
|
||||||
if let Content::Link(link) = &branch.attributes.content {
|
if let Content::Link(link) = &branch.attributes.content {
|
||||||
write!(
|
write!(
|
||||||
s,
|
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),
|
EscapeAttribute(link),
|
||||||
EscapeHtml(link),
|
EscapeHtml(link),
|
||||||
)
|
)
|
||||||
|
@ -122,7 +125,8 @@ pub fn branch_to_html(
|
||||||
if let Content::Link(link) = &branch.attributes.content {
|
if let Content::Link(link) = &branch.attributes.content {
|
||||||
write!(
|
write!(
|
||||||
s,
|
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),
|
EscapeAttribute(link),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -144,7 +148,7 @@ pub fn branch_to_html(
|
||||||
let num_children = branch.children.len();
|
let num_children = branch.children.len();
|
||||||
for i in 0..num_children {
|
for i in 0..num_children {
|
||||||
let child_id = treehouse.tree.branch(branch_id).children[i];
|
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>");
|
s.push_str("</ul>");
|
||||||
}
|
}
|
||||||
|
@ -159,12 +163,13 @@ pub fn branch_to_html(
|
||||||
pub fn branches_to_html(
|
pub fn branches_to_html(
|
||||||
s: &mut String,
|
s: &mut String,
|
||||||
treehouse: &mut Treehouse,
|
treehouse: &mut Treehouse,
|
||||||
|
config: &Config,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
branches: &[SemaBranchId],
|
branches: &[SemaBranchId],
|
||||||
) {
|
) {
|
||||||
s.push_str("<ul>");
|
s.push_str("<ul>");
|
||||||
for &child in branches {
|
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>");
|
s.push_str("</ul>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,13 @@ use std::path::Path;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use cli::{
|
use cli::{
|
||||||
fix::fix_file_cli,
|
fix::fix_file_cli,
|
||||||
regenerate::{self, regenerate_or_report_error, Dirs},
|
regenerate::{self, regenerate_or_report_error, Paths},
|
||||||
Command, ProgramArgs,
|
Command, ProgramArgs,
|
||||||
};
|
};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod config;
|
||||||
mod html;
|
mod html;
|
||||||
mod paths;
|
mod paths;
|
||||||
mod state;
|
mod state;
|
||||||
|
@ -19,8 +20,9 @@ async fn fallible_main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Command::Regenerate(regenerate_args) => {
|
Command::Regenerate(regenerate_args) => {
|
||||||
let dirs = Dirs {
|
let dirs = Paths {
|
||||||
target_dir: Path::new("target/site"),
|
target_dir: Path::new("target/site"),
|
||||||
|
config_file: Path::new("treehouse.toml"),
|
||||||
|
|
||||||
// NOTE: These are intentionally left unconfigurable from within 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.
|
// because this is is one of those things that should be consistent between sites.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// This is definitely not a three.js ripoff.
|
||||||
|
|
||||||
import { navigationMap } from "/navmap.js";
|
import { navigationMap } from "/navmap.js";
|
||||||
|
|
||||||
const branchStateKey = "treehouse.openBranches";
|
const branchStateKey = "treehouse.openBranches";
|
||||||
|
@ -68,7 +70,7 @@ class LinkedBranch extends Branch {
|
||||||
|
|
||||||
async loadTreePromise(_initiator) {
|
async loadTreePromise(_initiator) {
|
||||||
try {
|
try {
|
||||||
let response = await fetch(`/${this.linkedTree}.html`);
|
let response = await fetch(`${TREEHOUSE_SITE}/${this.linkedTree}.html`);
|
||||||
if (response.status == 404) {
|
if (response.status == 404) {
|
||||||
throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`;
|
throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +109,7 @@ function expandDetailsRecursively(element) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToPage(page) {
|
function navigateToPage(page) {
|
||||||
window.location.pathname = `/${page}.html`
|
window.location.href = `${TREEHOUSE_SITE}/${page}.html`
|
||||||
}
|
}
|
||||||
|
|
||||||
async function navigateToBranch(fragment) {
|
async function navigateToBranch(fragment) {
|
||||||
|
|
|
@ -9,18 +9,19 @@
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ site }}/static/css/main.css">
|
<link rel="stylesheet" href="{{ config.site }}/static/css/main.css">
|
||||||
<link rel="stylesheet" href="{{ site }}/static/css/tree.css">
|
<link rel="stylesheet" href="{{ config.site }}/static/css/tree.css">
|
||||||
<link rel="stylesheet" href="{{ site }}/static/font/font.css">
|
<link rel="stylesheet" href="{{ config.site }}/static/font/font.css">
|
||||||
|
|
||||||
<script type="module" src="{{ site }}/navmap.js"></script>
|
<script>const TREEHOUSE_SITE = `{{ config.site }}`;</script>
|
||||||
<script type="module" src="{{ site }}/static/js/tree.js"></script>
|
<script type="module" src="{{ config.site }}/navmap.js"></script>
|
||||||
<script type="module" src="{{ site }}/static/js/usability.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>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav>
|
<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">
|
<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"
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
d="M8 3H7H6V4V5H4V6H6V9V10H7H10V12H11V10H12H13V9V8V7H12H11H10V8V9H7V6H8H9V5V4V3H8ZM12 9H11V8H12V9ZM7 5V4H8V5H7ZM3 5H2V6H3V5ZM10 13H11V14H10V13Z"
|
d="M8 3H7H6V4V5H4V6H6V9V10H7H10V12H11V10H12H13V9V8V7H12H11H10V8V9H7V6H8H9V5V4V3H8ZM12 9H11V8H12V9ZM7 5V4H8V5H7ZM3 5H2V6H3V5ZM10 13H11V14H10V13Z"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# User settings go here. These are (string, string) key-value pairs.
|
site = "http://localhost:8080"
|
||||||
# They are available under `config.user`.
|
|
||||||
[user]
|
[user]
|
||||||
title = "treehouse"
|
title = "liquidex's treehouse"
|
||||||
author = "liquidex"
|
author = "liquidex"
|
||||||
|
|
||||||
|
[links]
|
||||||
|
"stitchkit/repo" = "https://github.com/liquidev/stitchkit"
|
||||||
|
"dawd3/repo" = "https://github.com/liquidev/dawd3"
|
||||||
|
|
Loading…
Reference in a new issue