feat: reworked the category editing
This commit is contained in:
@@ -89,6 +89,7 @@ pub enum Message {
|
||||
ToggleSidebar,
|
||||
TogglePanel,
|
||||
OpenSettingsSection(crate::views::settings_view::SettingsSection),
|
||||
OpenTagsSection(TagsSection),
|
||||
|
||||
// Sidebar resize
|
||||
SidebarResizeStart,
|
||||
@@ -1678,6 +1679,22 @@ impl BdsApp {
|
||||
self.sync_menu_state();
|
||||
Task::none()
|
||||
}
|
||||
Message::OpenTagsSection(section) => {
|
||||
self.sidebar_view = SidebarView::Tags;
|
||||
self.sidebar_visible = true;
|
||||
self.open_singleton_tab(TabType::Tags, "tabBar.tags");
|
||||
if self.settings_state.is_none() {
|
||||
self.settings_state = Some(self.hydrate_settings_state());
|
||||
}
|
||||
if self.tags_view_state.is_none() {
|
||||
self.reload_tags_state();
|
||||
}
|
||||
if let Some(state) = self.tags_view_state.as_mut() {
|
||||
state.section = section;
|
||||
}
|
||||
self.sync_menu_state();
|
||||
Task::none()
|
||||
}
|
||||
Message::SidebarResizeStart => {
|
||||
self.sidebar_dragging = true;
|
||||
Task::none()
|
||||
@@ -7582,6 +7599,9 @@ impl BdsApp {
|
||||
title: meta
|
||||
.and_then(|value| value.title.clone())
|
||||
.unwrap_or_else(|| name.clone()),
|
||||
translated_titles: meta
|
||||
.map(|value| value.titles.clone())
|
||||
.unwrap_or_default(),
|
||||
render_in_lists: meta.map(|value| value.render_in_lists).unwrap_or(true),
|
||||
show_title: meta.map(|value| value.show_title).unwrap_or(true),
|
||||
post_template_slug: meta
|
||||
@@ -8225,9 +8245,13 @@ impl BdsApp {
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingsMsg::CategoryTitleChanged(name, value) => {
|
||||
SettingsMsg::CategoryTitleChanged(name, language, value) => {
|
||||
if let Some(row) = state.categories.iter_mut().find(|row| row.name == name) {
|
||||
row.title = value;
|
||||
if language.eq_ignore_ascii_case(&state.main_language) {
|
||||
row.title = value;
|
||||
} else {
|
||||
row.translated_titles.insert(language, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingsMsg::CategoryRenderInListsChanged(name, value) => {
|
||||
@@ -8261,6 +8285,15 @@ impl BdsApp {
|
||||
row.name.clone(),
|
||||
bds_core::model::metadata::CategorySettings {
|
||||
title: Some(row.title.clone()).filter(|title| !title.trim().is_empty()),
|
||||
titles: row
|
||||
.translated_titles
|
||||
.iter()
|
||||
.filter(|(language, title)| {
|
||||
!language.eq_ignore_ascii_case(&state.main_language)
|
||||
&& !title.trim().is_empty()
|
||||
})
|
||||
.map(|(language, title)| (language.clone(), title.clone()))
|
||||
.collect(),
|
||||
render_in_lists: row.render_in_lists,
|
||||
show_title: row.show_title,
|
||||
post_template_slug: (!row.post_template_slug.is_empty())
|
||||
@@ -8313,6 +8346,7 @@ impl BdsApp {
|
||||
bds_core::model::metadata::CategorySettings {
|
||||
title: Some(row.title.clone())
|
||||
.filter(|title| !title.trim().is_empty()),
|
||||
titles: std::collections::BTreeMap::new(),
|
||||
render_in_lists: row.render_in_lists,
|
||||
show_title: row.show_title,
|
||||
post_template_slug: None,
|
||||
@@ -9047,6 +9081,9 @@ impl BdsApp {
|
||||
}
|
||||
}
|
||||
TabType::Tags => {
|
||||
if self.settings_state.is_none() {
|
||||
self.settings_state = Some(self.hydrate_settings_state());
|
||||
}
|
||||
if self.tags_view_state.is_none() {
|
||||
let project_id = self
|
||||
.active_project
|
||||
@@ -13048,6 +13085,35 @@ mod tests {
|
||||
assert!(meta.semantic_similarity_enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_category_persists_main_and_translated_titles() {
|
||||
let (db, project, tmp) = setup();
|
||||
let mut app = make_app(db, project, &tmp);
|
||||
let mut state = app.hydrate_settings_state();
|
||||
state.main_language = "de".into();
|
||||
state.blog_languages = vec!["de".into(), "en".into()];
|
||||
app.settings_state = Some(state);
|
||||
|
||||
let _ = app.handle_settings_msg(SettingsMsg::CategoryTitleChanged(
|
||||
"article".into(),
|
||||
"de".into(),
|
||||
"Artikel".into(),
|
||||
));
|
||||
let _ = app.handle_settings_msg(SettingsMsg::CategoryTitleChanged(
|
||||
"article".into(),
|
||||
"en".into(),
|
||||
"Articles".into(),
|
||||
));
|
||||
let _ = app.handle_settings_msg(SettingsMsg::SaveCategory("article".into()));
|
||||
|
||||
let categories = bds_core::engine::meta::read_category_meta_json(tmp.path()).unwrap();
|
||||
assert_eq!(categories["article"].title.as_deref(), Some("Artikel"));
|
||||
assert_eq!(
|
||||
categories["article"].title_for("en", "de"),
|
||||
Some("Articles")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_category_and_reset_defaults_updates_metadata_files() {
|
||||
let (db, project, tmp) = setup();
|
||||
|
||||
@@ -159,7 +159,7 @@ pub fn text_editor_style(_theme: &Theme, status: text_editor::Status) -> text_ed
|
||||
}
|
||||
}
|
||||
|
||||
fn select_style(_theme: &Theme, status: pick_list::Status) -> pick_list::Style {
|
||||
pub(crate) fn select_style(_theme: &Theme, status: pick_list::Status) -> pick_list::Style {
|
||||
let border_color = match status {
|
||||
pick_list::Status::Hovered | pick_list::Status::Opened => FOCUS_COLOR,
|
||||
pick_list::Status::Active => BORDER_COLOR,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use iced::widget::text::Shaping;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_editor, text_input};
|
||||
use iced::{Alignment, Color, Element, Length};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use bds_core::engine::ai::AiEndpointKind;
|
||||
use bds_core::i18n::UiLocale;
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::components::inputs;
|
||||
use crate::i18n::{t, tw};
|
||||
use crate::i18n::t;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AiModelOption {
|
||||
@@ -41,7 +42,6 @@ pub struct AiModeViewState {
|
||||
pub enum SettingsSection {
|
||||
Project,
|
||||
Editor,
|
||||
Content,
|
||||
AI,
|
||||
Technology,
|
||||
Publishing,
|
||||
@@ -53,6 +53,7 @@ pub enum SettingsSection {
|
||||
pub struct SettingsCategoryRow {
|
||||
pub name: String,
|
||||
pub title: String,
|
||||
pub translated_titles: BTreeMap<String, String>,
|
||||
pub render_in_lists: bool,
|
||||
pub show_title: bool,
|
||||
pub post_template_slug: String,
|
||||
@@ -82,6 +83,7 @@ pub fn default_category_rows() -> Vec<SettingsCategoryRow> {
|
||||
.map(|name| SettingsCategoryRow {
|
||||
name: (*name).to_string(),
|
||||
title: (*name).to_string(),
|
||||
translated_titles: BTreeMap::new(),
|
||||
render_in_lists: true,
|
||||
show_title: true,
|
||||
post_template_slug: String::new(),
|
||||
@@ -96,7 +98,6 @@ impl SettingsSection {
|
||||
&[
|
||||
Self::Project,
|
||||
Self::Editor,
|
||||
Self::Content,
|
||||
Self::AI,
|
||||
Self::Technology,
|
||||
Self::Publishing,
|
||||
@@ -109,7 +110,6 @@ impl SettingsSection {
|
||||
match self {
|
||||
Self::Project => "settings.nav.project",
|
||||
Self::Editor => "settings.nav.editor",
|
||||
Self::Content => "settings.nav.content",
|
||||
Self::AI => "settings.nav.ai",
|
||||
Self::Technology => "settings.nav.technology",
|
||||
Self::Publishing => "settings.nav.publishing",
|
||||
@@ -141,7 +141,7 @@ pub struct SettingsViewState {
|
||||
pub diff_view_style: String,
|
||||
pub wrap_long_lines: bool,
|
||||
pub hide_unchanged_regions: bool,
|
||||
// Content
|
||||
// Categories (Tags workspace)
|
||||
pub categories: Vec<SettingsCategoryRow>,
|
||||
pub new_category_name: String,
|
||||
pub template_options: Vec<String>,
|
||||
@@ -312,7 +312,7 @@ pub enum SettingsMsg {
|
||||
// Content
|
||||
AddCategoryNameChanged(String),
|
||||
AddCategory,
|
||||
CategoryTitleChanged(String, String),
|
||||
CategoryTitleChanged(String, String, String),
|
||||
CategoryRenderInListsChanged(String, bool),
|
||||
CategoryShowTitleChanged(String, bool),
|
||||
CategoryPostTemplateChanged(String, String),
|
||||
@@ -445,7 +445,6 @@ fn render_section<'a>(
|
||||
let content: Element<'a, Message> = match section {
|
||||
SettingsSection::Project => section_project(state, locale),
|
||||
SettingsSection::Editor => section_editor(state, locale),
|
||||
SettingsSection::Content => section_content(state, locale),
|
||||
SettingsSection::AI => section_ai(state, locale),
|
||||
SettingsSection::Technology => section_technology(state, locale),
|
||||
SettingsSection::Publishing => section_publishing(state, locale),
|
||||
@@ -631,143 +630,6 @@ fn section_editor<'a>(state: &'a SettingsViewState, locale: UiLocale) -> Element
|
||||
.into()
|
||||
}
|
||||
|
||||
fn section_content<'a>(state: &'a SettingsViewState, locale: UiLocale) -> Element<'a, Message> {
|
||||
let template_options = std::iter::once(String::new())
|
||||
.chain(state.template_options.iter().cloned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let category_rows = state
|
||||
.categories
|
||||
.iter()
|
||||
.fold(column![].spacing(8), |column, category| {
|
||||
let title = inputs::labeled_input(
|
||||
&tw(
|
||||
locale,
|
||||
"settings.categoryTitle",
|
||||
&[("category", &category.name)],
|
||||
),
|
||||
"",
|
||||
&category.title,
|
||||
{
|
||||
let name = category.name.clone();
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryTitleChanged(name.clone(), value))
|
||||
}
|
||||
},
|
||||
);
|
||||
let post_template = inputs::labeled_select(
|
||||
&t(locale, "settings.categoryPostTemplate"),
|
||||
&template_options,
|
||||
Some(&category.post_template_slug),
|
||||
{
|
||||
let name = category.name.clone();
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryPostTemplateChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
}
|
||||
},
|
||||
);
|
||||
let list_template = inputs::labeled_select(
|
||||
&t(locale, "settings.categoryListTemplate"),
|
||||
&template_options,
|
||||
Some(&category.list_template_slug),
|
||||
{
|
||||
let name = category.name.clone();
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryListTemplateChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
}
|
||||
},
|
||||
);
|
||||
let toggles = column![
|
||||
inputs::labeled_checkbox(
|
||||
&t(locale, "settings.categoryRenderInLists"),
|
||||
category.render_in_lists,
|
||||
{
|
||||
let name = category.name.clone();
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryRenderInListsChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
}
|
||||
},
|
||||
),
|
||||
inputs::labeled_checkbox(
|
||||
&t(locale, "settings.categoryShowTitles"),
|
||||
category.show_title,
|
||||
{
|
||||
let name = category.name.clone();
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryShowTitleChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
}
|
||||
},
|
||||
),
|
||||
]
|
||||
.spacing(6);
|
||||
let actions = row![
|
||||
button(text(t(locale, "common.save")).size(13))
|
||||
.on_press(Message::Settings(SettingsMsg::SaveCategory(
|
||||
category.name.clone()
|
||||
)))
|
||||
.style(inputs::primary_button)
|
||||
.padding([6, 12]),
|
||||
button(text(t(locale, "common.remove")).size(13))
|
||||
.on_press_maybe((!category.is_protected).then(|| Message::Settings(
|
||||
SettingsMsg::RemoveCategory(category.name.clone())
|
||||
)))
|
||||
.style(inputs::danger_button)
|
||||
.padding([6, 12]),
|
||||
]
|
||||
.spacing(8);
|
||||
|
||||
column.push(
|
||||
inputs::card(
|
||||
column![
|
||||
text(category.name.clone()).size(15).color(Color::WHITE),
|
||||
title,
|
||||
toggles,
|
||||
row![post_template, list_template].spacing(12),
|
||||
actions,
|
||||
]
|
||||
.spacing(8),
|
||||
)
|
||||
.padding(12),
|
||||
)
|
||||
});
|
||||
|
||||
let add_row = row![
|
||||
inputs::labeled_input(
|
||||
&t(locale, "settings.addCategory"),
|
||||
"news",
|
||||
&state.new_category_name,
|
||||
|value| Message::Settings(SettingsMsg::AddCategoryNameChanged(value)),
|
||||
),
|
||||
button(text(t(locale, "common.add")).size(13))
|
||||
.on_press(Message::Settings(SettingsMsg::AddCategory))
|
||||
.style(inputs::primary_button)
|
||||
.padding([6, 12]),
|
||||
button(text(t(locale, "settings.resetCategories")).size(13))
|
||||
.on_press(Message::Settings(SettingsMsg::ResetCategoriesToDefaults))
|
||||
.style(inputs::secondary_button)
|
||||
.padding([6, 12]),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(Alignment::End);
|
||||
|
||||
column![category_rows, add_row]
|
||||
.spacing(12)
|
||||
.padding([0, 16])
|
||||
.into()
|
||||
}
|
||||
|
||||
fn section_ai<'a>(state: &'a SettingsViewState, locale: UiLocale) -> Element<'a, Message> {
|
||||
let online = ai_mode_block(
|
||||
&state.online_ai,
|
||||
|
||||
@@ -1234,7 +1234,6 @@ pub fn view(
|
||||
let sections: &[(&str, Option<SettingsSection>)] = &[
|
||||
("settings.nav.project", Some(SettingsSection::Project)),
|
||||
("settings.nav.editor", Some(SettingsSection::Editor)),
|
||||
("settings.nav.content", Some(SettingsSection::Content)),
|
||||
("settings.nav.ai", Some(SettingsSection::AI)),
|
||||
("settings.nav.technology", Some(SettingsSection::Technology)),
|
||||
("settings.nav.publishing", Some(SettingsSection::Publishing)),
|
||||
@@ -1269,21 +1268,31 @@ pub fn view(
|
||||
iced::widget::Column::with_children(items).spacing(1).into()
|
||||
}
|
||||
SidebarView::Tags => {
|
||||
// Per sidebar_views.allium TagsNav: 3 fixed-order sections
|
||||
let sections = ["tags.nav.cloud", "tags.nav.manage", "tags.nav.merge"];
|
||||
let sections = [
|
||||
(
|
||||
"tags.nav.cloud",
|
||||
crate::views::tags_view::TagsSection::Cloud,
|
||||
),
|
||||
(
|
||||
"tags.nav.manage",
|
||||
crate::views::tags_view::TagsSection::Manage,
|
||||
),
|
||||
(
|
||||
"tags.nav.merge",
|
||||
crate::views::tags_view::TagsSection::Merge,
|
||||
),
|
||||
(
|
||||
"tags.nav.categories",
|
||||
crate::views::tags_view::TagsSection::Categories,
|
||||
),
|
||||
];
|
||||
let items: Vec<Element<'static, Message>> = sections
|
||||
.iter()
|
||||
.map(|key| {
|
||||
.map(|(key, section)| {
|
||||
let label = t(locale, key);
|
||||
let label_text = text(label).size(12).shaping(Shaping::Advanced);
|
||||
button(container(label_text).width(Length::Fill))
|
||||
.on_press(Message::OpenTab(Tab {
|
||||
id: "tags".to_string(),
|
||||
tab_type: TabType::Tags,
|
||||
title: t(locale, "tabBar.tags"),
|
||||
is_transient: false,
|
||||
is_dirty: false,
|
||||
}))
|
||||
.on_press(Message::OpenTagsSection(*section))
|
||||
.padding([5, 8])
|
||||
.width(Length::Fill)
|
||||
.style(item_style)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use iced::widget::{Space, button, column, container, row, scrollable, text, text_input};
|
||||
use iced::widget::{
|
||||
Space, button, checkbox, column, container, pick_list, row, scrollable, text, text_input,
|
||||
};
|
||||
use iced::{Alignment, Background, Color, Element, Length, Theme};
|
||||
|
||||
use bds_core::i18n::UiLocale;
|
||||
@@ -9,6 +11,7 @@ use bds_core::model::Tag;
|
||||
use crate::app::Message;
|
||||
use crate::components::inputs;
|
||||
use crate::i18n::{t, tw};
|
||||
use crate::views::settings_view::{SettingsMsg, SettingsViewState};
|
||||
|
||||
const DEFAULT_TAG_COLOR: &str = "#6495ed";
|
||||
const COLOR_PRESETS: [&str; 17] = [
|
||||
@@ -24,6 +27,7 @@ pub enum TagsSection {
|
||||
Manage,
|
||||
Merge,
|
||||
Discover,
|
||||
Categories,
|
||||
}
|
||||
|
||||
/// State for the tags view.
|
||||
@@ -116,7 +120,11 @@ pub enum TagsMsg {
|
||||
}
|
||||
|
||||
/// Render the tags management view.
|
||||
pub fn view<'a>(state: &'a TagsViewState, locale: UiLocale) -> Element<'a, Message> {
|
||||
pub fn view<'a>(
|
||||
state: &'a TagsViewState,
|
||||
settings: &'a SettingsViewState,
|
||||
locale: UiLocale,
|
||||
) -> Element<'a, Message> {
|
||||
let section_nav = inputs::card(
|
||||
row![
|
||||
section_tab(
|
||||
@@ -139,6 +147,11 @@ pub fn view<'a>(state: &'a TagsViewState, locale: UiLocale) -> Element<'a, Messa
|
||||
state.section == TagsSection::Discover,
|
||||
TagsSection::Discover
|
||||
),
|
||||
section_tab(
|
||||
&t(locale, "tags.nav.categories"),
|
||||
state.section == TagsSection::Categories,
|
||||
TagsSection::Categories
|
||||
),
|
||||
]
|
||||
.spacing(6),
|
||||
)
|
||||
@@ -149,6 +162,7 @@ pub fn view<'a>(state: &'a TagsViewState, locale: UiLocale) -> Element<'a, Messa
|
||||
TagsSection::Manage => view_manage(state, locale),
|
||||
TagsSection::Merge => view_merge(state, locale),
|
||||
TagsSection::Discover => view_discover(state, locale),
|
||||
TagsSection::Categories => view_categories(settings, locale),
|
||||
};
|
||||
|
||||
column![section_nav, content]
|
||||
@@ -158,6 +172,215 @@ pub fn view<'a>(state: &'a TagsViewState, locale: UiLocale) -> Element<'a, Messa
|
||||
.into()
|
||||
}
|
||||
|
||||
fn view_categories<'a>(state: &'a SettingsViewState, locale: UiLocale) -> Element<'a, Message> {
|
||||
const NAME_WIDTH: f32 = 120.0;
|
||||
const TITLE_WIDTH: f32 = 170.0;
|
||||
const TOGGLE_WIDTH: f32 = 110.0;
|
||||
const TEMPLATE_WIDTH: f32 = 150.0;
|
||||
const ACTION_WIDTH: f32 = 150.0;
|
||||
|
||||
let mut languages = vec![state.main_language.clone()];
|
||||
for language in &state.blog_languages {
|
||||
if !languages
|
||||
.iter()
|
||||
.any(|existing| existing.eq_ignore_ascii_case(language))
|
||||
{
|
||||
languages.push(language.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let header_cell = |label: String, width| {
|
||||
container(text(label).size(12).color(inputs::LABEL_COLOR))
|
||||
.width(Length::Fixed(width))
|
||||
.into()
|
||||
};
|
||||
let mut header: Vec<Element<'a, Message>> =
|
||||
vec![header_cell(t(locale, "tags.name"), NAME_WIDTH)];
|
||||
header.extend(languages.iter().map(|language| {
|
||||
header_cell(
|
||||
tw(locale, "categories.title", &[("language", language)]),
|
||||
TITLE_WIDTH,
|
||||
)
|
||||
}));
|
||||
header.extend([
|
||||
header_cell(t(locale, "settings.categoryRenderInLists"), TOGGLE_WIDTH),
|
||||
header_cell(t(locale, "settings.categoryShowTitles"), TOGGLE_WIDTH),
|
||||
header_cell(t(locale, "settings.categoryPostTemplate"), TEMPLATE_WIDTH),
|
||||
header_cell(t(locale, "settings.categoryListTemplate"), TEMPLATE_WIDTH),
|
||||
header_cell(t(locale, "categories.actions"), ACTION_WIDTH),
|
||||
]);
|
||||
|
||||
let template_options = std::iter::once(String::new())
|
||||
.chain(state.template_options.iter().cloned())
|
||||
.collect::<Vec<_>>();
|
||||
let mut table = column![iced::widget::Row::with_children(header).spacing(8)].spacing(8);
|
||||
for category in &state.categories {
|
||||
let mut cells: Vec<Element<'a, Message>> = vec![
|
||||
container(text(category.name.clone()).size(13))
|
||||
.width(Length::Fixed(NAME_WIDTH))
|
||||
.into(),
|
||||
];
|
||||
cells.extend(languages.iter().map(|language| {
|
||||
let value = if language.eq_ignore_ascii_case(&state.main_language) {
|
||||
&category.title
|
||||
} else {
|
||||
category
|
||||
.translated_titles
|
||||
.get(language)
|
||||
.map(String::as_str)
|
||||
.unwrap_or("")
|
||||
};
|
||||
let name = category.name.clone();
|
||||
let language = language.clone();
|
||||
text_input("", value)
|
||||
.on_input(move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryTitleChanged(
|
||||
name.clone(),
|
||||
language.clone(),
|
||||
value,
|
||||
))
|
||||
})
|
||||
.padding([7, 9])
|
||||
.style(inputs::field_style)
|
||||
.width(Length::Fixed(TITLE_WIDTH))
|
||||
.into()
|
||||
}));
|
||||
let name = category.name.clone();
|
||||
cells.push(
|
||||
container(
|
||||
checkbox("", category.render_in_lists).on_toggle(move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryRenderInListsChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
}),
|
||||
)
|
||||
.width(Length::Fixed(TOGGLE_WIDTH))
|
||||
.into(),
|
||||
);
|
||||
let name = category.name.clone();
|
||||
cells.push(
|
||||
container(checkbox("", category.show_title).on_toggle(move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryShowTitleChanged(name.clone(), value))
|
||||
}))
|
||||
.width(Length::Fixed(TOGGLE_WIDTH))
|
||||
.into(),
|
||||
);
|
||||
let name = category.name.clone();
|
||||
cells.push(
|
||||
pick_list(
|
||||
template_options.clone(),
|
||||
Some(category.post_template_slug.clone()),
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryPostTemplateChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
},
|
||||
)
|
||||
.padding([7, 9])
|
||||
.style(inputs::select_style)
|
||||
.width(Length::Fixed(TEMPLATE_WIDTH))
|
||||
.into(),
|
||||
);
|
||||
let name = category.name.clone();
|
||||
cells.push(
|
||||
pick_list(
|
||||
template_options.clone(),
|
||||
Some(category.list_template_slug.clone()),
|
||||
move |value| {
|
||||
Message::Settings(SettingsMsg::CategoryListTemplateChanged(
|
||||
name.clone(),
|
||||
value,
|
||||
))
|
||||
},
|
||||
)
|
||||
.padding([7, 9])
|
||||
.style(inputs::select_style)
|
||||
.width(Length::Fixed(TEMPLATE_WIDTH))
|
||||
.into(),
|
||||
);
|
||||
cells.push(
|
||||
container(
|
||||
row![
|
||||
button(text(t(locale, "common.save")).size(12))
|
||||
.on_press(Message::Settings(SettingsMsg::SaveCategory(
|
||||
category.name.clone(),
|
||||
)))
|
||||
.style(inputs::primary_button)
|
||||
.padding([6, 10]),
|
||||
button(text(t(locale, "common.remove")).size(12))
|
||||
.on_press_maybe((!category.is_protected).then(|| Message::Settings(
|
||||
SettingsMsg::RemoveCategory(category.name.clone()),
|
||||
)))
|
||||
.style(inputs::danger_button)
|
||||
.padding([6, 10]),
|
||||
]
|
||||
.spacing(6),
|
||||
)
|
||||
.width(Length::Fixed(ACTION_WIDTH))
|
||||
.into(),
|
||||
);
|
||||
table = table.push(
|
||||
iced::widget::Row::with_children(cells)
|
||||
.spacing(8)
|
||||
.align_y(Alignment::Center),
|
||||
);
|
||||
}
|
||||
|
||||
let add = inputs::card(
|
||||
row![
|
||||
inputs::labeled_input(
|
||||
&t(locale, "settings.addCategory"),
|
||||
"news",
|
||||
&state.new_category_name,
|
||||
|value| Message::Settings(SettingsMsg::AddCategoryNameChanged(value)),
|
||||
),
|
||||
button(text(t(locale, "common.add")).size(13))
|
||||
.on_press(Message::Settings(SettingsMsg::AddCategory))
|
||||
.style(inputs::primary_button)
|
||||
.padding([6, 12]),
|
||||
button(text(t(locale, "settings.resetCategories")).size(13))
|
||||
.on_press(Message::Settings(SettingsMsg::ResetCategoriesToDefaults))
|
||||
.style(inputs::secondary_button)
|
||||
.padding([6, 12]),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(Alignment::End),
|
||||
);
|
||||
let table_width = NAME_WIDTH
|
||||
+ TITLE_WIDTH * languages.len() as f32
|
||||
+ TOGGLE_WIDTH * 2.0
|
||||
+ TEMPLATE_WIDTH * 2.0
|
||||
+ ACTION_WIDTH
|
||||
+ 8.0 * (languages.len() + 5) as f32
|
||||
+ 24.0;
|
||||
let table = scrollable(
|
||||
inputs::card(table)
|
||||
.padding(12)
|
||||
.width(Length::Fixed(table_width)),
|
||||
)
|
||||
.direction(scrollable::Direction::Horizontal(
|
||||
inputs::compact_scrollbar(),
|
||||
))
|
||||
.style(inputs::scrollable_style)
|
||||
.width(Length::Fill);
|
||||
|
||||
scrollable(
|
||||
column![
|
||||
inputs::card(text(t(locale, "categories.section")).size(18)).padding(16),
|
||||
add,
|
||||
table,
|
||||
]
|
||||
.spacing(12)
|
||||
.padding(16),
|
||||
)
|
||||
.direction(scrollable::Direction::Vertical(inputs::compact_scrollbar()))
|
||||
.style(inputs::scrollable_style)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn section_tab<'a>(label: &str, active: bool, section: TagsSection) -> Element<'a, Message> {
|
||||
button(text(label.to_string()).size(13))
|
||||
.on_press(Message::Tags(TagsMsg::SetSection(section)))
|
||||
|
||||
@@ -506,8 +506,8 @@ fn route_content_area<'a>(
|
||||
}
|
||||
}
|
||||
ContentRoute::Tags => {
|
||||
if let Some(state) = tags_view_state {
|
||||
tags_view::view(state, locale)
|
||||
if let (Some(state), Some(settings)) = (tags_view_state, settings_state) {
|
||||
tags_view::view(state, settings, locale)
|
||||
} else {
|
||||
loading_view(locale)
|
||||
}
|
||||
@@ -646,7 +646,7 @@ fn route_kind<'a>(
|
||||
}
|
||||
TabType::Chat => ContentRoute::Chat(tab_id),
|
||||
TabType::Tags => {
|
||||
if tags_view_state.is_some() {
|
||||
if tags_view_state.is_some() && settings_state.is_some() {
|
||||
ContentRoute::Tags
|
||||
} else {
|
||||
ContentRoute::Loading
|
||||
|
||||
Reference in New Issue
Block a user