feat(ui): rename External tab to Browser and add toolbar browse action

This commit is contained in:
LynithDev 2026-08-01 11:46:15 +02:00
parent d61f6e6655
commit 2e7bc89dbc
2 changed files with 37 additions and 21 deletions

View file

@ -222,7 +222,7 @@ fn make_row(
pub(super) enum Tab {
All,
Category(String),
External,
Browser,
Local,
}
@ -231,7 +231,7 @@ impl Tab {
match self {
Tab::All => "All".to_string(),
Tab::Category(c) => c.clone(),
Tab::External => "External".to_string(),
Tab::Browser => "Browser".to_string(),
Tab::Local => "Local".to_string(),
}
}
@ -241,8 +241,8 @@ impl Tab {
// Every package assigned to the cluster, regardless of origin.
Tab::All => true,
Tab::Category(c) => p.categories.iter().any(|pc| pc == c),
// External = remote provider content that is NOT provided by a bundle.
Tab::External => p.is_remote() && !p.in_bundle(),
// Browser = remote provider content that is NOT provided by a bundle.
Tab::Browser => p.is_remote() && !p.in_bundle(),
Tab::Local => !p.is_remote(),
}
}
@ -269,7 +269,7 @@ fn build_tabs(categories: &[String], items: &[PackageEntry]) -> Vec<Tab> {
}
}
// Category tabs are hidden when empty; All + External + Local are always shown.
// Category tabs are hidden when empty; All + Browser + Local are always shown.
let mut tabs: Vec<Tab> = vec![Tab::All];
tabs.extend(
cats.into_iter()
@ -277,7 +277,7 @@ fn build_tabs(categories: &[String], items: &[PackageEntry]) -> Vec<Tab> {
.filter(|t| items.iter().any(|p| t.matches(p))),
);
tabs.push(Tab::External);
tabs.push(Tab::Browser);
tabs.push(Tab::Local);
tabs
}
@ -348,7 +348,7 @@ impl Component for PackageManager {
let tab_filter = tabs.get(active_idx);
let content_kind = match tab_filter {
Some(Tab::External) => ContentKind::External,
Some(Tab::Browser) => ContentKind::Browser,
Some(Tab::Local) => ContentKind::Local,
_ => ContentKind::Other,
};
@ -380,6 +380,8 @@ impl Component for PackageManager {
sort_mode,
enabled_filter,
layout,
cluster_id,
package_type,
))
.maybe_child(session_live.then(|| views::running_notice(noun_plural)))
.child(ContentBox::new(

View file

@ -114,6 +114,8 @@ pub(super) fn toolbar_bar(
current_sort: SortMode,
enabled_filter: State<EnabledFilter>,
layout: State<ViewLayout>,
cluster_id: i64,
package_type: &'static str,
) -> impl IntoElement {
let tab_items = tabs.iter().enumerate().map(|(i, tab)| {
let mut active = active;
@ -172,6 +174,15 @@ pub(super) fn toolbar_bar(
.segment(Segment::new(ViewLayout::List).icon(IconType::ParagraphWrap))
.segment(Segment::new(ViewLayout::Grid).icon(IconType::DotsGrid)),
)
.child(
Button::new()
.primary()
.height(Size::px(34.))
.font_size(12.)
.on_press(move |_| open_browser(cluster_id, package_type))
.child(Icon::new(IconType::Plus).size(15.))
.text("Add Content"),
)
.into_element()
}
@ -462,23 +473,26 @@ fn add_from_file_button(
.text("Add from file")
}
/// Opens the content browser scoped to this cluster and package type.
fn open_browser(cluster_id: i64, package_type: &'static str) {
let _ = RouterContext::get().push(Route::Browser {
cluster_id,
package_type: package_type.to_string(),
pick_cluster: false,
});
}
fn browse_button(cluster_id: i64, package_type: &'static str) -> impl IntoElement {
Button::new()
.primary()
.on_press(move |_| {
let _ = RouterContext::get().push(Route::Browser {
cluster_id,
package_type: package_type.to_string(),
pick_cluster: false,
});
})
.on_press(move |_| open_browser(cluster_id, package_type))
.child(Icon::new(IconType::SearchMd).size(14.))
.text("Browse Content")
}
#[derive(Clone, Copy, PartialEq)]
pub(super) enum ContentKind {
External,
Browser,
Local,
Other,
}
@ -556,7 +570,7 @@ impl Component for ContentBox {
});
let empty = (count == 0).then(|| match kind {
ContentKind::External => external_empty(cluster_id, package_type).into_element(),
ContentKind::Browser => browser_empty(cluster_id, package_type).into_element(),
ContentKind::Local => {
local_empty(cluster_id, content_type, dispatch.clone(), noun_plural).into_element()
}
@ -565,9 +579,9 @@ impl Component for ContentBox {
let header = (count > 0)
.then(|| match kind {
ContentKind::External => {
Some(action_header(browse_button(cluster_id, package_type)).into_element())
}
// The toolbar above already carries a permanent "Add Content"
// button, so this list needs no browse action of its own.
ContentKind::Browser => None,
ContentKind::Local => Some(
action_header(add_from_file_button(
cluster_id,
@ -699,9 +713,9 @@ fn empty_state(noun_plural: &'static str) -> impl IntoElement {
.into_element()
}
fn external_empty(cluster_id: i64, package_type: &'static str) -> impl IntoElement {
fn browser_empty(cluster_id: i64, package_type: &'static str) -> impl IntoElement {
empty_shell(IconType::SearchMd)
.child(empty_title("No external content installed."))
.child(empty_title("No content installed from the browser."))
.child(empty_hint(
"Browse providers to add mods, resource packs and more.",
))