75 lines
2.2 KiB
Rust
75 lines
2.2 KiB
Rust
use serde::Serialize;
|
|
use std::path::Path;
|
|
|
|
const INDEX_TEMPLATE: &str = include_str!("../assets/index.html");
|
|
const NOT_FOUND_TEMPLATE: &str = include_str!("../assets/404.html");
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
pub struct AppProject {
|
|
pub name: String,
|
|
pub route_path: String,
|
|
}
|
|
|
|
pub fn scan_projects(root: &Path) -> Vec<AppProject> {
|
|
let mut projects = Vec::new();
|
|
|
|
let Ok(read_dir) = std::fs::read_dir(root) else {
|
|
return projects;
|
|
};
|
|
|
|
for item in read_dir.flatten() {
|
|
let path = item.path();
|
|
let name = item.file_name().to_string_lossy().to_string();
|
|
|
|
if name.starts_with('.') {
|
|
continue;
|
|
}
|
|
|
|
if path.is_dir() {
|
|
let has_index = path.join("index.html").exists() || path.join("index.htm").exists();
|
|
if has_index {
|
|
let route_path = format!("/{}/", name);
|
|
projects.push(AppProject { name, route_path });
|
|
}
|
|
}
|
|
}
|
|
|
|
projects.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
|
|
projects
|
|
}
|
|
|
|
pub fn render_dashboard(projects: &[AppProject]) -> String {
|
|
let mut cards_html = String::new();
|
|
|
|
for proj in projects {
|
|
// 提取首字符作为圆形头像字母
|
|
let initial = proj.name.chars().next().unwrap_or('A').to_uppercase().to_string();
|
|
|
|
cards_html.push_str(&format!(
|
|
r#"
|
|
<a class="site-item" href="{url}" title="{name}">
|
|
<div class="site-avatar">{initial}</div>
|
|
<div class="site-info">
|
|
<span class="site-name">{name}</span>
|
|
<span class="site-desc">本地托管应用 • {url}</span>
|
|
</div>
|
|
</a>
|
|
"#,
|
|
url = proj.route_path,
|
|
name = proj.name,
|
|
initial = initial
|
|
));
|
|
}
|
|
|
|
let final_cards = if cards_html.is_empty() {
|
|
r#"<div class="empty-state">当前目录下暂无含有 index.html 的前端项目</div>"#.to_string()
|
|
} else {
|
|
cards_html
|
|
};
|
|
|
|
INDEX_TEMPLATE.replace("__CARDS__", &final_cards)
|
|
}
|
|
|
|
pub fn render_not_found(path: &str) -> String {
|
|
NOT_FOUND_TEMPLATE.replace("__PATH__", path)
|
|
} |