blindforge/src/templates.rs
2026-07-25 20:27:47 +02:00

122 lines
2.7 KiB
Rust

use std::{collections::BTreeMap, iter::Peekable};
use log::warn;
use trillium_askama::Template;
#[derive(Template)]
#[template(path = "home.html")]
pub struct Home {}
#[derive(Template)]
#[template(path = "repo.html")]
pub struct Repo {
pub content: String,
pub root: Directory,
}
#[derive(Clone, Template)]
#[template(
source = r#"
{% match self %}
{% when Entry::Directory(dir) %}
<li class="tree-dir">
<details>
<summary><span class="filename">{{ dir.name|escape }}</span></summary>
<ul class="tree">
{% for entry in dir.entries.values() %}
{{ entry.render()? }}
{% endfor %}
</ul>
</details>
</li>
{% when Entry::File(file) %}
<li class="tree-file"><span class="filename">{{ file.name|escape }}</span></li>
{% endmatch %}
"#,
ext = "html",
escape = "none"
)]
pub enum Entry {
Directory(Directory),
File(File),
}
#[derive(Clone)]
pub struct File {
pub name: String,
pub path: String,
pub hash: String,
}
#[derive(Clone, Default)]
pub struct Directory {
pub name: String,
pub path: String,
pub entries: BTreeMap<String, Entry>,
}
impl Entry {
fn name(&self) -> &str {
match self {
Entry::Directory(dir) => &dir.name,
Entry::File(file) => &file.name,
}
}
}
impl PartialEq<Entry> for Entry {
fn eq(&self, other: &Entry) -> bool {
self.name() == other.name()
}
}
impl PartialOrd<Entry> for Entry {
fn partial_cmp(&self, other: &Entry) -> Option<std::cmp::Ordering> {
self.name().partial_cmp(other.name())
}
}
impl Directory {
/// Insert
pub fn insert<'a>(&mut self, entry: Entry, mut path: Peekable<impl Iterator<Item = &'a str>>) {
let Some(next_path_level) = path.next() else {
warn!("Cannot insert entry: no more path");
return;
};
if path.peek().is_some() {
// Directory
if let Some(parent) = self.entries.get_mut(next_path_level) {
// Directory exists
match parent {
Entry::Directory(dir) => dir.insert(entry, path),
Entry::File(_file) => {
warn!("Cannot insert entry: file");
}
}
} else {
//warn!("Cannot insert entry: not found");
// Need to create directory
let mut new_dir_path = self.path.clone();
new_dir_path.push_str(next_path_level);
let mut parent = Directory {
name: next_path_level.into(),
path: new_dir_path,
entries: BTreeMap::new(),
};
parent.insert(entry, path);
self.entries
.insert(next_path_level.into(), Entry::Directory(parent));
}
} else {
// File
self.entries.insert(entry.name().to_string(), entry);
}
}
pub fn find<'a>(&self, mut path: impl Iterator<Item = &'a str>) -> Option<&str> {
match self.entries.get(path.next()?)? {
Entry::Directory(directory) => directory.find(path),
Entry::File(file) => Some(&file.hash),
}
}
}