parent
847008825f
commit
634706beec
3 changed files with 104 additions and 40 deletions
|
@ -60,7 +60,7 @@ impl Domain {
|
||||||
Document::new(&self.name, path, self.dir.parent().unwrap().to_path_buf())
|
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();
|
let mut base_path = self.dir.clone();
|
||||||
|
|
||||||
for p in path.split('/') {
|
for p in path.split('/') {
|
||||||
|
@ -71,44 +71,31 @@ impl Domain {
|
||||||
|
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
|
|
||||||
|
let mut is_doc = false;
|
||||||
|
|
||||||
for entry in dir_content {
|
for entry in dir_content {
|
||||||
let url_path = format!("{path}/{entry}");
|
let url_path = format!("{path}/{entry}");
|
||||||
let is_doc = read_dir(&base_path.join(entry))
|
if entry.starts_with("index_") && entry.ends_with(".html") {
|
||||||
.into_iter()
|
is_doc = true;
|
||||||
.any(|x| x.starts_with("index_") && x.ends_with(".html"));
|
continue;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret.push(PathEntry(self.name.clone(), url_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret
|
(ret, is_doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum PathEntry {
|
pub struct PathEntry(String, String);
|
||||||
Path(String, String),
|
|
||||||
Document(Document),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathEntry {
|
impl PathEntry {
|
||||||
pub fn url(&self) -> String {
|
pub fn url(&self) -> String {
|
||||||
match self {
|
format!("/d/{}/{}", self.0, self.1)
|
||||||
PathEntry::Path(domain, path) => format!("/d/{domain}/{path}"),
|
|
||||||
PathEntry::Document(document) => document.url(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> String {
|
pub fn path(&self) -> &String {
|
||||||
match self {
|
&self.1
|
||||||
PathEntry::Path(_, path) => path.to_string(),
|
|
||||||
PathEntry::Document(document) => document.path.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +157,13 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn versions(&self) -> Vec<String> {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,11 @@ pub async fn download_favicon(domain: &str) -> Option<Vec<u8>> {
|
||||||
|
|
||||||
pub async fn download_fav_for(site: &str) {
|
pub async fn download_fav_for(site: &str) {
|
||||||
if let Some(fav) = download_favicon(site).await {
|
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);
|
||||||
log::info!("Writting favicon for {site}");
|
if !fav_path.exists() {
|
||||||
|
std::fs::write(fav_path, fav).unwrap();
|
||||||
|
log::info!("Writting favicon for {site}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use based::{
|
||||||
use maud::{html, PreEscaped};
|
use maud::{html, PreEscaped};
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
|
|
||||||
use crate::archive::{PathEntry, WebsiteArchive};
|
use crate::archive::WebsiteArchive;
|
||||||
|
|
||||||
pub async fn render_page(content: PreEscaped<String>, ctx: RequestContext) -> StringResponse {
|
pub async fn render_page(content: PreEscaped<String>, ctx: RequestContext) -> StringResponse {
|
||||||
based::page::render_page(
|
based::page::render_page(
|
||||||
|
@ -17,6 +17,7 @@ pub async fn render_page(content: PreEscaped<String>, ctx: RequestContext) -> St
|
||||||
&Shell::new(
|
&Shell::new(
|
||||||
html! {
|
html! {
|
||||||
script src="https://cdn.tailwindcss.com" {};
|
script src="https://cdn.tailwindcss.com" {};
|
||||||
|
meta name="viewport" content="width=device-width, initial-scale=1.0" {};
|
||||||
},
|
},
|
||||||
html! {},
|
html! {},
|
||||||
Some("bg-zinc-950 text-white min-h-screen flex pt-8 justify-center".to_string()),
|
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..>")]
|
#[get("/d/<domain>/<paths..>")]
|
||||||
pub async fn domain_info_route(
|
pub async fn domain_info_route(
|
||||||
ctx: RequestContext,
|
ctx: RequestContext,
|
||||||
|
@ -80,19 +110,56 @@ pub async fn domain_info_route(
|
||||||
arc: &State<WebsiteArchive>,
|
arc: &State<WebsiteArchive>,
|
||||||
) -> StringResponse {
|
) -> StringResponse {
|
||||||
let domain = arc.get_domain(domain);
|
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! {
|
let content = html! {
|
||||||
h2 class="text-xl font-bold mb-4" { (domain.name) };
|
h2 class="text-xl font-bold mb-4 flex items-center" {
|
||||||
div class="max-w-md mx-auto p-4 bg-neutral-900 rounded-lg shadow-md" {
|
img class="p-2" src=(format!("/favicon/{}", &domain.name)) {};
|
||||||
ul class="space-y-2" {
|
a href=(format!("/d/{}", &domain.name)) { (domain.name) };
|
||||||
@for path in paths {
|
(slash_seperator())
|
||||||
a href=(path.url()) class="flex items-center gap-2 p-3 border bg-neutral-800 rounded hover:shadow-lg transition" {
|
(gen_path_header(path_seperations, &domain.name))
|
||||||
@if matches!(path, PathEntry::Document(_)) {
|
};
|
||||||
(arrow_icon("red"))
|
|
||||||
|
@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 {
|
} @else {
|
||||||
(arrow_icon("blue"))
|
(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()) };
|
span class="font-medium" { (path.path()) };
|
||||||
};
|
};
|
||||||
|
@ -100,6 +167,7 @@ pub async fn domain_info_route(
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
render_page(content, ctx).await
|
render_page(content, ctx).await
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue