refactor(ui): 拆分 app/connection_view/widgets 为子组件,对话框归拢 dialogs/
- ui/app/ 拆为门面、events(引擎事件泵)、actions(用户动作)、io(导入导出)、 theme(主题)、titlebar/sidebar/main_area(渲染分区) - ui/connection_view/ 拆为门面、subscribe、messages、publish、vars、util(纯函数) - ui/widgets/ 拆为 select(可搜索下拉)、kv_editor、common(字段行/状态/时间) - 五个对话框归拢 ui/dialogs/,linear-theme.json 随 theme.rs 迁入 ui/app/ - clippy 0 警告,全部路径经门面保持稳定
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
//! 可搜索的枚举下拉:选项模型、委托与统一外观的 Select 包装。
|
||||
|
||||
use gpui_kit::component::searchable_list::{ SearchableListDelegate, SearchableListItem };
|
||||
use gpui_kit::component::select::{ Select, SelectState };
|
||||
use gpui_kit::component::IndexPath;
|
||||
use gpui_kit::{ Entity, SharedString, Window };
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OptionItem {
|
||||
pub value: usize,
|
||||
pub label: SharedString,
|
||||
}
|
||||
|
||||
impl SearchableListItem for OptionItem {
|
||||
type Value = usize;
|
||||
fn title(&self) -> SharedString {
|
||||
self.label.clone()
|
||||
}
|
||||
fn value(&self) -> &usize {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OptionDelegate {
|
||||
pub items: Vec<OptionItem>,
|
||||
}
|
||||
|
||||
impl OptionDelegate {
|
||||
pub fn new(labels: &[&str]) -> Self {
|
||||
Self {
|
||||
items: labels
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, l)| OptionItem {
|
||||
value: i,
|
||||
label: (*l).into(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SearchableListDelegate for OptionDelegate {
|
||||
type Item = OptionItem;
|
||||
fn items_count(&self, _section: usize) -> usize {
|
||||
self.items.len()
|
||||
}
|
||||
fn item(&self, ix: IndexPath) -> Option<&Self::Item> {
|
||||
self.items.get(ix.row)
|
||||
}
|
||||
fn position<V>(&self, _value: &V) -> Option<IndexPath>
|
||||
where
|
||||
Self::Item: SearchableListItem<Value = V>,
|
||||
V: PartialEq,
|
||||
{
|
||||
// 选中项统一通过 IndexPath 构造,无需按值反查
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建字符串枚举下拉状态(在任意实体上下文里调用)。
|
||||
pub fn make_select<C: gpui_kit::AppContext>(
|
||||
labels: &[&str],
|
||||
selected: usize,
|
||||
window: &mut Window,
|
||||
cx: &mut C,
|
||||
) -> Entity<SelectState<OptionDelegate>> {
|
||||
let selected = selected.min(labels.len().saturating_sub(1));
|
||||
cx.new(|cx| {
|
||||
SelectState::new(
|
||||
OptionDelegate::new(labels),
|
||||
Some(IndexPath::new(selected)),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// ─── 字段行 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
/// Select::new 的包装,统一外观。
|
||||
pub fn select_element<D: SearchableListDelegate>(
|
||||
state: &Entity<SelectState<D>>,
|
||||
) -> Select<D>
|
||||
where
|
||||
<D::Item as SearchableListItem>::Value: PartialEq + Clone,
|
||||
{
|
||||
Select::new(state)
|
||||
}
|
||||
Reference in New Issue
Block a user