update ui
Some checks failed
ci/woodpecker/push/build Pipeline failed

This commit is contained in:
JMARyA 2024-12-29 22:57:39 +01:00
parent 847008825f
commit 634706beec
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
3 changed files with 104 additions and 40 deletions

View file

@ -60,7 +60,7 @@ impl Domain {
Document::new(&self.name, path, self.dir.parent().unwrap().to_path_buf())
}
pub fn paths(&self, path: &str) -> Vec<PathEntry> {
pub fn paths(&self, path: &str) -> (Vec<PathEntry>, bool) {
let mut base_path = self.dir.clone();
for p in path.split('/') {
@ -71,44 +71,31 @@ impl Domain {
let mut ret = Vec::new();
let mut is_doc = false;
for entry in dir_content {
let url_path = format!("{path}/{entry}");
let is_doc = read_dir(&base_path.join(entry))
.into_iter()
.any(|x| x.starts_with("index_") && x.ends_with(".html"));
if is_doc {
ret.push(PathEntry::Document(Document::new(
&self.name,
&url_path,
self.dir.parent().unwrap().to_path_buf(),
)));
} else {
ret.push(PathEntry::Path(self.name.clone(), url_path));
}
if entry.starts_with("index_") && entry.ends_with(".html") {
is_doc = true;
continue;
}
ret
ret.push(PathEntry(self.name.clone(), url_path));
}
(ret, is_doc)
}
}
pub enum PathEntry {
Path(String, String),
Document(Document),
}
pub struct PathEntry(String, String);
impl PathEntry {
pub fn url(&self) -> String {
match self {
PathEntry::Path(domain, path) => format!("/d/{domain}/{path}"),
PathEntry::Document(document) => document.url(),
}
format!("/d/{}/{}", self.0, self.1)
}
pub fn path(&self) -> String {
match self {
PathEntry::Path(_, path) => path.to_string(),
PathEntry::Document(document) => document.path.clone(),
}
pub fn path(&self) -> &String {
&self.1
}
}
@ -170,7 +157,13 @@ impl Document {
}
pub fn versions(&self) -> Vec<String> {
read_dir(&self.doc_dir())
let mut res: Vec<String> = read_dir(&self.doc_dir())
.into_iter()
.filter(|x| x.starts_with("index_") && x.ends_with(".html"))
.collect();
res.sort();
res.reverse();
res
}
}

View file

@ -17,9 +17,12 @@ pub async fn download_favicon(domain: &str) -> Option<Vec<u8>> {
pub async fn download_fav_for(site: &str) {
if let Some(fav) = download_favicon(site).await {
std::fs::write(std::path::Path::new("./favicon").join(site), fav).unwrap();
let fav_path = std::path::Path::new("./favicon").join(site);
if !fav_path.exists() {
std::fs::write(fav_path, fav).unwrap();
log::info!("Writting favicon for {site}");
}
}
}
pub async fn download_favicons_for_sites(sites: &[String]) {

View file

@ -7,7 +7,7 @@ use based::{
use maud::{html, PreEscaped};
use rocket::{get, State};
use crate::archive::{PathEntry, WebsiteArchive};
use crate::archive::WebsiteArchive;
pub async fn render_page(content: PreEscaped<String>, ctx: RequestContext) -> StringResponse {
based::page::render_page(
@ -17,6 +17,7 @@ pub async fn render_page(content: PreEscaped<String>, ctx: RequestContext) -> St
&Shell::new(
html! {
script src="https://cdn.tailwindcss.com" {};
meta name="viewport" content="width=device-width, initial-scale=1.0" {};
},
html! {},
Some("bg-zinc-950 text-white min-h-screen flex pt-8 justify-center".to_string()),
@ -72,6 +73,35 @@ pub fn arrow_icon(color: &str) -> PreEscaped<String> {
}
}
pub fn slash_seperator() -> PreEscaped<String> {
html! {
p class="font-bold p-2 text-gray-400" { " / " };
}
}
pub fn gen_path_link(
path: &str,
index: usize,
path_seperations: &[&str],
domain: &str,
) -> PreEscaped<String> {
let upto: Vec<&str> = path_seperations.iter().take(index + 1).cloned().collect();
html! {
a href=(format!("/d/{}/{}", domain, upto.join("/"))) { (path)}
}
}
pub fn gen_path_header(path_seperations: Vec<&str>, domain: &str) -> PreEscaped<String> {
html! {
@for (index, path) in path_seperations.iter().enumerate() {
(gen_path_link(path, index, &path_seperations, domain))
@if index < path_seperations.len()-1 {
(slash_seperator())
};
};
}
}
#[get("/d/<domain>/<paths..>")]
pub async fn domain_info_route(
ctx: RequestContext,
@ -80,26 +110,64 @@ pub async fn domain_info_route(
arc: &State<WebsiteArchive>,
) -> StringResponse {
let domain = arc.get_domain(domain);
let paths = domain.paths(paths.to_str().unwrap());
let document = domain.path(paths.to_str().unwrap());
let versions: Vec<String> = document
.versions()
.into_iter()
.map(|x| {
x.trim_start_matches("index_")
.trim_end_matches(".html")
.to_string()
})
.collect();
let (path_entries, is_doc) = domain.paths(paths.to_str().unwrap());
let path_seperations: Vec<&str> = paths.to_str().unwrap().split('/').collect();
let content = html! {
h2 class="text-xl font-bold mb-4" { (domain.name) };
div class="max-w-md mx-auto p-4 bg-neutral-900 rounded-lg shadow-md" {
ul class="space-y-2" {
@for path in paths {
a href=(path.url()) class="flex items-center gap-2 p-3 border bg-neutral-800 rounded hover:shadow-lg transition" {
@if matches!(path, PathEntry::Document(_)) {
(arrow_icon("red"))
} @else {
(arrow_icon("blue"))
h2 class="text-xl font-bold mb-4 flex items-center" {
img class="p-2" src=(format!("/favicon/{}", &domain.name)) {};
a href=(format!("/d/{}", &domain.name)) { (domain.name) };
(slash_seperator())
(gen_path_header(path_seperations, &domain.name))
};
@if !versions.is_empty() {
div class="max-w-md mx-auto p-4 bg-neutral-900 rounded-lg shadow-md mb-8" {
h3 class="font-bold mb-2" { "Saved Versions:" };
@for (index, ver) in versions.into_iter().enumerate() {
a href=(format!("/s/{}/{}?time={}", &domain.name, paths.to_str().unwrap(), ver)) class="text-xs text-blue-400" {
@if index == 0 {
(format!("Latest ({ver})"))
} @else {
(ver)
}
};
}
};
}
@if path_entries.is_empty() && !is_doc {
div class="max-w-md mx-auto p-4 bg-neutral-900 rounded-lg shadow-md" {
p class="p-4 text-xl" { "Nothing found" };
}
}
@if !path_entries.is_empty() {
div class="max-w-md mx-auto p-4 bg-neutral-900 rounded-lg shadow-md" {
h3 class="font-bold mb-2" { "Paths:" };
ul class="space-y-2" {
@for path in path_entries {
a href=(path.url()) class="flex items-center gap-2 p-3 border bg-neutral-800 rounded hover:shadow-lg transition" {
(arrow_icon("blue"))
span class="font-medium" { (path.path()) };
};
};
};
};
};
};
render_page(content, ctx).await
}