feat: reworked the category editing

This commit is contained in:
2026-07-24 09:00:12 +02:00
parent d9085cf681
commit 7a3c5683e7
23 changed files with 471 additions and 193 deletions

View File

@@ -446,6 +446,7 @@ pub fn add_category(
category.to_string(),
CategorySettings {
title: None,
titles: BTreeMap::new(),
render_in_lists: true,
show_title: true,
post_template_slug: None,
@@ -642,6 +643,7 @@ mod tests {
"article".to_string(),
CategorySettings {
title: None,
titles: BTreeMap::new(),
render_in_lists: true,
show_title: true,
post_template_slug: None,
@@ -662,6 +664,7 @@ mod tests {
"news".to_string(),
CategorySettings {
title: Some("News Archive".to_string()),
titles: BTreeMap::from([("de".into(), "Nachrichten".into())]),
render_in_lists: false,
show_title: true,
post_template_slug: Some("article".to_string()),
@@ -674,11 +677,13 @@ mod tests {
let content = std::fs::read_to_string(dir.path().join("meta/category-meta.json")).unwrap();
let json: serde_json::Value = serde_json::from_str(&content).unwrap();
assert_eq!(json["news"]["title"], "News Archive");
assert_eq!(json["news"]["titles"]["de"], "Nachrichten");
assert_eq!(json["news"]["renderInLists"], false);
assert_eq!(json["news"]["showTitle"], true);
let read = read_category_meta_json(dir.path()).unwrap();
assert_eq!(read["news"].title.as_deref(), Some("News Archive"));
assert_eq!(read["news"].title_for("de", "en"), Some("Nachrichten"));
}
#[test]
@@ -689,6 +694,7 @@ mod tests {
"zebra".to_string(),
CategorySettings {
title: Some("Zebra".into()),
titles: BTreeMap::new(),
render_in_lists: true,
show_title: false,
post_template_slug: Some("post".into()),
@@ -699,6 +705,7 @@ mod tests {
"alpha".to_string(),
CategorySettings {
title: None,
titles: BTreeMap::new(),
render_in_lists: false,
show_title: true,
post_template_slug: None,
@@ -903,6 +910,7 @@ mod tests {
"article".to_string(),
CategorySettings {
title: None,
titles: BTreeMap::new(),
render_in_lists: true,
show_title: true,
post_template_slug: None,

View File

@@ -1427,6 +1427,7 @@ mod tests {
"news".to_string(),
crate::model::metadata::CategorySettings {
title: Some("News".into()),
titles: std::collections::BTreeMap::new(),
render_in_lists: false,
show_title: true,
post_template_slug: Some("article".into()),

View File

@@ -1546,6 +1546,7 @@ mod tests {
"hidden".to_string(),
crate::model::CategorySettings {
title: None,
titles: std::collections::BTreeMap::new(),
render_in_lists: false,
show_title: true,
post_template_slug: None,
@@ -1556,6 +1557,7 @@ mod tests {
"featured".to_string(),
crate::model::CategorySettings {
title: None,
titles: std::collections::BTreeMap::new(),
render_in_lists: true,
show_title: false,
post_template_slug: None,

View File

@@ -1,3 +1,5 @@
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
pub const SUPPORTED_PICO_THEMES: [&str; 20] = [
@@ -107,6 +109,23 @@ pub struct CategorySettings {
pub show_title: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub titles: BTreeMap<String, String>,
}
impl CategorySettings {
pub fn title_for(&self, language: &str, main_language: &str) -> Option<&str> {
if language.eq_ignore_ascii_case(main_language) {
self.title.as_deref()
} else {
self.titles
.iter()
.find(|(candidate, _)| candidate.eq_ignore_ascii_case(language))
.map(|(_, title)| title.as_str())
}
.map(str::trim)
.filter(|title| !title.is_empty())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -177,6 +196,7 @@ mod tests {
fn category_settings_camel_case() {
let settings = CategorySettings {
title: Some("Article".into()),
titles: BTreeMap::new(),
render_in_lists: false,
show_title: true,
post_template_slug: Some("article-tpl".into()),
@@ -189,6 +209,22 @@ mod tests {
assert!(json.contains("postTemplateSlug"));
}
#[test]
fn category_settings_select_title_for_render_language() {
let settings = CategorySettings {
title: Some("Artikel".into()),
titles: std::collections::BTreeMap::from([("en".into(), "Articles".into())]),
render_in_lists: true,
show_title: true,
post_template_slug: None,
list_template_slug: None,
};
assert_eq!(settings.title_for("de", "de"), Some("Artikel"));
assert_eq!(settings.title_for("en", "de"), Some("Articles"));
assert_eq!(settings.title_for("fr", "de"), None);
}
#[test]
fn tag_entry_roundtrip() {
let tag = TagEntry {

View File

@@ -921,9 +921,7 @@ fn build_language_routes(
let slug = slugify(&category);
let display_name = category_settings
.get(&category)
.and_then(|settings| settings.title.as_deref())
.map(str::trim)
.filter(|title| !title.is_empty())
.and_then(|settings| settings.title_for(language, main_language(metadata)))
.unwrap_or(&category);
routes.extend(paginated_route_specs(
&records,

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use bds_core::db::Database;
use bds_core::db::queries::project::insert_project;
@@ -254,6 +254,21 @@ fn mixed_source_languages_use_the_main_language_at_canonical_urls() {
metadata.main_language = Some("de".into());
metadata.blog_languages = vec!["de".into(), "en".into()];
bds_core::engine::meta::write_project_json(dir.path(), &metadata).unwrap();
write_category_meta_json(
dir.path(),
&HashMap::from([(
"article".into(),
CategorySettings {
title: Some("Artikel".into()),
titles: BTreeMap::from([("en".into(), "Articles".into())]),
render_in_lists: true,
show_title: true,
post_template_slug: None,
list_template_slug: None,
},
)]),
)
.unwrap();
insert_template(
db.conn(),
&Template {
@@ -391,6 +406,12 @@ fn mixed_source_languages_use_the_main_language_at_canonical_urls() {
let english_index = std::fs::read_to_string(output.join("en/index.html")).unwrap();
assert!(english_index.contains("English translation body"));
assert!(!english_index.contains(">English translation</a></h2>"));
let german_category =
std::fs::read_to_string(output.join("category/article/index.html")).unwrap();
let english_category =
std::fs::read_to_string(output.join("en/category/article/index.html")).unwrap();
assert!(german_category.contains("<h1 class=\"archive-heading\">Artikel</h1>"));
assert!(english_category.contains("<h1 class=\"archive-heading\">Articles</h1>"));
assert!(
output
.join("2024/03/12/german-private/index.html")
@@ -725,6 +746,7 @@ fn generation_respects_category_list_settings_and_writes_bundled_images() {
"hidden".to_string(),
CategorySettings {
title: None,
titles: BTreeMap::new(),
render_in_lists: false,
show_title: true,
post_template_slug: None,
@@ -735,6 +757,7 @@ fn generation_respects_category_list_settings_and_writes_bundled_images() {
"featured".to_string(),
CategorySettings {
title: Some("Featured Archive".to_string()),
titles: BTreeMap::from([("de".into(), "Ausgewählt".into())]),
render_in_lists: true,
show_title: false,
post_template_slug: None,