table: Improve sort icon color and fix stripe row display. (#578)
- Improve sort icon color: <img width="139" alt="image" src="https://github.com/user-attachments/assets/6374c26a-4555-4735-953b-dbd961fe5b31" /> - Avoid duplicate border when enabled fixed column. <img width="587" alt="image" src="https://github.com/user-attachments/assets/6e186d29-5d8a-404e-b160-20c2af6a16fa" /> TODO - [x] The extra rows not show when `stripe` is true.
This commit is contained in:
parent
649e765729
commit
e658aeee96
4 changed files with 160 additions and 101 deletions
|
|
@ -1,4 +1,15 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevrons-up-down">
|
||||
<path opacity="0.5" d="m7 15 5 5 5-5"/>
|
||||
<path d="m7 9 5-5 5 5"/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-chevrons-up-down"
|
||||
>
|
||||
<path opacity="0.2" d="m7 15 5 5 5-5" />
|
||||
<path d="m7 9 5-5 5 5" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 340 B |
|
|
@ -1,4 +1,15 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevrons-up-down">
|
||||
<path d="m7 15 5 5 5-5"/>
|
||||
<path opacity="0.5" d="m7 9 5-5 5 5"/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-chevrons-up-down"
|
||||
>
|
||||
<path d="m7 15 5 5 5-5" />
|
||||
<path opacity="0.2" d="m7 9 5-5 5 5" />
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 340 B |
|
|
@ -200,52 +200,44 @@ impl StockTableDelegate {
|
|||
Column::new("price", "Price", Some(ColSort::Default)),
|
||||
Column::new("change", "Chg", Some(ColSort::Default)),
|
||||
Column::new("change_percent", "Chg%", Some(ColSort::Default)),
|
||||
Column::new("volume", "Volume", Some(ColSort::Default)),
|
||||
Column::new("turnover", "Turnover", Some(ColSort::Default)),
|
||||
Column::new("market_cap", "Market Cap", Some(ColSort::Default)),
|
||||
Column::new("ttm", "TTM", Some(ColSort::Default)),
|
||||
Column::new("five_mins_ranking", "5m Ranking", Some(ColSort::Default)),
|
||||
Column::new("th60_days_ranking", "60d Ranking", Some(ColSort::Default)),
|
||||
Column::new("year_change_percent", "Year Chg%", Some(ColSort::Default)),
|
||||
Column::new("bid", "Bid", Some(ColSort::Default)),
|
||||
Column::new("bid_volume", "Bid Vol", Some(ColSort::Default)),
|
||||
Column::new("ask", "Ask", Some(ColSort::Default)),
|
||||
Column::new("ask_volume", "Ask Vol", Some(ColSort::Default)),
|
||||
Column::new("open", "Open", Some(ColSort::Default)),
|
||||
Column::new("prev_close", "Prev Close", Some(ColSort::Default)),
|
||||
Column::new("high", "High", Some(ColSort::Default)),
|
||||
Column::new("low", "Low", Some(ColSort::Default)),
|
||||
Column::new("turnover_rate", "Turnover Rate", Some(ColSort::Default)),
|
||||
Column::new("rise_rate", "Rise Rate", Some(ColSort::Default)),
|
||||
Column::new("amplitude", "Amplitude", Some(ColSort::Default)),
|
||||
Column::new("pe_status", "P/E", Some(ColSort::Default)),
|
||||
Column::new("pb_status", "P/B", Some(ColSort::Default)),
|
||||
Column::new("volume_ratio", "Volume Ratio", Some(ColSort::Default)),
|
||||
Column::new("bid_ask_ratio", "Bid Ask Ratio", Some(ColSort::Default)),
|
||||
Column::new(
|
||||
"latest_pre_close",
|
||||
"Latest Pre Close",
|
||||
Some(ColSort::Default),
|
||||
),
|
||||
Column::new(
|
||||
"latest_post_close",
|
||||
"Latest Post Close",
|
||||
Some(ColSort::Default),
|
||||
),
|
||||
Column::new("pre_market_cap", "Pre Mkt Cap", Some(ColSort::Default)),
|
||||
Column::new("pre_market_percent", "Pre Mkt%", Some(ColSort::Default)),
|
||||
Column::new("pre_market_change", "Pre Mkt Chg", Some(ColSort::Default)),
|
||||
Column::new("post_market_cap", "Post Mkt Cap", Some(ColSort::Default)),
|
||||
Column::new("post_market_percent", "Post Mkt%", Some(ColSort::Default)),
|
||||
Column::new("post_market_change", "Post Mkt Chg", Some(ColSort::Default)),
|
||||
Column::new("float_cap", "Float Cap", Some(ColSort::Default)),
|
||||
Column::new("shares", "Shares", Some(ColSort::Default)),
|
||||
Column::new("shares_float", "Float Shares", Some(ColSort::Default)),
|
||||
Column::new("day_5_ranking", "5d Ranking", Some(ColSort::Default)),
|
||||
Column::new("day_10_ranking", "10d Ranking", Some(ColSort::Default)),
|
||||
Column::new("day_30_ranking", "30d Ranking", Some(ColSort::Default)),
|
||||
Column::new("day_120_ranking", "120d Ranking", Some(ColSort::Default)),
|
||||
Column::new("day_250_ranking", "250d Ranking", Some(ColSort::Default)),
|
||||
Column::new("volume", "Volume", None),
|
||||
Column::new("turnover", "Turnover", None),
|
||||
Column::new("market_cap", "Market Cap", None),
|
||||
Column::new("ttm", "TTM", None),
|
||||
Column::new("five_mins_ranking", "5m Ranking", None),
|
||||
Column::new("th60_days_ranking", "60d Ranking", None),
|
||||
Column::new("year_change_percent", "Year Chg%", None),
|
||||
Column::new("bid", "Bid", None),
|
||||
Column::new("bid_volume", "Bid Vol", None),
|
||||
Column::new("ask", "Ask", None),
|
||||
Column::new("ask_volume", "Ask Vol", None),
|
||||
Column::new("open", "Open", None),
|
||||
Column::new("prev_close", "Prev Close", None),
|
||||
Column::new("high", "High", None),
|
||||
Column::new("low", "Low", None),
|
||||
Column::new("turnover_rate", "Turnover Rate", None),
|
||||
Column::new("rise_rate", "Rise Rate", None),
|
||||
Column::new("amplitude", "Amplitude", None),
|
||||
Column::new("pe_status", "P/E", None),
|
||||
Column::new("pb_status", "P/B", None),
|
||||
Column::new("volume_ratio", "Volume Ratio", None),
|
||||
Column::new("bid_ask_ratio", "Bid Ask Ratio", None),
|
||||
Column::new("latest_pre_close", "Latest Pre Close", None),
|
||||
Column::new("latest_post_close", "Latest Post Close", None),
|
||||
Column::new("pre_market_cap", "Pre Mkt Cap", None),
|
||||
Column::new("pre_market_percent", "Pre Mkt%", None),
|
||||
Column::new("pre_market_change", "Pre Mkt Chg", None),
|
||||
Column::new("post_market_cap", "Post Mkt Cap", None),
|
||||
Column::new("post_market_percent", "Post Mkt%", None),
|
||||
Column::new("post_market_change", "Post Mkt Chg", None),
|
||||
Column::new("float_cap", "Float Cap", None),
|
||||
Column::new("shares", "Shares", None),
|
||||
Column::new("shares_float", "Float Shares", None),
|
||||
Column::new("day_5_ranking", "5d Ranking", None),
|
||||
Column::new("day_10_ranking", "10d Ranking", None),
|
||||
Column::new("day_30_ranking", "30d Ranking", None),
|
||||
Column::new("day_120_ranking", "120d Ranking", None),
|
||||
Column::new("day_250_ranking", "250d Ranking", None),
|
||||
],
|
||||
loop_selection: true,
|
||||
col_resize: true,
|
||||
|
|
@ -263,7 +255,7 @@ impl StockTableDelegate {
|
|||
|
||||
fn update_stocks(&mut self, size: usize) {
|
||||
self.stocks = random_stocks(size);
|
||||
self.is_eof = false;
|
||||
self.is_eof = size <= 50;
|
||||
self.loading = false;
|
||||
self.full_loading = false;
|
||||
}
|
||||
|
|
@ -477,6 +469,17 @@ impl TableDelegate for StockTableDelegate {
|
|||
ColSort::Descending => b.id.cmp(&a.id),
|
||||
_ => a.id.cmp(&b.id),
|
||||
}),
|
||||
"symbol" => self.stocks.sort_by(|a, b| match sort {
|
||||
ColSort::Descending => b.symbol.cmp(&a.symbol),
|
||||
_ => a.id.cmp(&b.id),
|
||||
}),
|
||||
"change" | "change_percent" => self.stocks.sort_by(|a, b| match sort {
|
||||
ColSort::Descending => b
|
||||
.change
|
||||
.partial_cmp(&a.change)
|
||||
.unwrap_or(std::cmp::Ordering::Equal),
|
||||
_ => a.id.cmp(&b.id),
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -652,6 +655,7 @@ impl TableStory {
|
|||
fn toggle_col_resize(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
|
||||
self.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().col_resize = *checked;
|
||||
table.refresh(cx);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
|
@ -659,6 +663,7 @@ impl TableStory {
|
|||
fn toggle_col_order(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
|
||||
self.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().col_order = *checked;
|
||||
table.refresh(cx);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
|
@ -666,6 +671,7 @@ impl TableStory {
|
|||
fn toggle_col_sort(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
|
||||
self.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().col_sort = *checked;
|
||||
table.refresh(cx);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
|
@ -673,6 +679,7 @@ impl TableStory {
|
|||
fn toggle_col_selection(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
|
||||
self.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().col_selection = *checked;
|
||||
table.refresh(cx);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -753,9 +753,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn render_cell(&self, col_ix: usize, _cx: &mut ViewContext<Self>) -> Div {
|
||||
let col_width = self.col_groups[col_ix].width;
|
||||
let col_padding = self.col_groups[col_ix].padding;
|
||||
let Some(col_group) = self.col_groups.get(col_ix) else {
|
||||
return div();
|
||||
};
|
||||
|
||||
let col_width = col_group.width;
|
||||
let col_padding = col_group.padding;
|
||||
|
||||
div()
|
||||
.w(col_width)
|
||||
|
|
@ -1037,11 +1042,9 @@ where
|
|||
// Render left fixed columns
|
||||
this.child(
|
||||
h_flex()
|
||||
.id("table-head-fixed-left")
|
||||
.relative()
|
||||
.h_full()
|
||||
.bg(cx.theme().table_head)
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().border)
|
||||
.children(
|
||||
self.col_groups
|
||||
.iter()
|
||||
|
|
@ -1049,6 +1052,18 @@ where
|
|||
.enumerate()
|
||||
.map(|(col_ix, _)| self.render_th(col_ix, cx)),
|
||||
)
|
||||
.child(
|
||||
// Fixed columns border
|
||||
div()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.right_0()
|
||||
.bottom_0()
|
||||
.w_0()
|
||||
.flex_shrink_0()
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().border),
|
||||
)
|
||||
.child(
|
||||
canvas(
|
||||
move |bounds, cx| {
|
||||
|
|
@ -1102,6 +1117,7 @@ where
|
|||
row_ix: usize,
|
||||
rows_count: usize,
|
||||
left_cols_count: usize,
|
||||
col_sizes: Rc<Vec<gpui::Size<Pixels>>>,
|
||||
cols_count: usize,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> impl IntoElement {
|
||||
|
|
@ -1109,13 +1125,6 @@ where
|
|||
let is_stripe_row = self.stripe && row_ix % 2 != 0;
|
||||
let is_selected = self.selected_row == Some(row_ix);
|
||||
let view = cx.view().clone();
|
||||
let col_sizes: Rc<Vec<gpui::Size<Pixels>>> = Rc::new(
|
||||
self.col_groups
|
||||
.iter()
|
||||
.skip(left_cols_count)
|
||||
.map(|col| col.bounds.size)
|
||||
.collect(),
|
||||
);
|
||||
|
||||
if row_ix < rows_count {
|
||||
self.delegate
|
||||
|
|
@ -1135,13 +1144,12 @@ where
|
|||
this.bg(cx.theme().table_hover)
|
||||
}
|
||||
})
|
||||
.children(if left_cols_count > 0 {
|
||||
.when(left_cols_count > 0, |this| {
|
||||
// Left fixed columns
|
||||
Some(
|
||||
this.child(
|
||||
h_flex()
|
||||
.relative()
|
||||
.h_full()
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().table_row_border)
|
||||
.children({
|
||||
let mut items = Vec::with_capacity(left_cols_count);
|
||||
|
||||
|
|
@ -1155,10 +1163,20 @@ where
|
|||
});
|
||||
|
||||
items
|
||||
}),
|
||||
})
|
||||
.child(
|
||||
// Fixed columns border
|
||||
div()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.right_0()
|
||||
.bottom_0()
|
||||
.w_0()
|
||||
.flex_shrink_0()
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().border),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
|
|
@ -1265,6 +1283,34 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculate the extra rows needed to fill the table empty space when `stripe` is true.
|
||||
fn calculate_extra_rows_needed(&self, rows_count: usize) -> usize {
|
||||
if !self.stripe {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut extra_rows_needed = 0;
|
||||
|
||||
let row_height = self.size.table_row_height();
|
||||
let total_height = self
|
||||
.vertical_scroll_handle
|
||||
.0
|
||||
.borrow()
|
||||
.base_handle
|
||||
.bounds()
|
||||
.size
|
||||
.height;
|
||||
|
||||
let actual_height = row_height * rows_count as f32;
|
||||
let remaining_height = total_height - actual_height;
|
||||
|
||||
if remaining_height > px(0.) {
|
||||
extra_rows_needed = (remaining_height / row_height).ceil() as usize;
|
||||
}
|
||||
|
||||
extra_rows_needed
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn measure_render_td(
|
||||
&mut self,
|
||||
|
|
@ -1341,35 +1387,7 @@ where
|
|||
let left_cols_count = self.fixed_cols.left;
|
||||
let rows_count = self.delegate.rows_count(cx);
|
||||
let loading = self.delegate.loading(cx);
|
||||
|
||||
let row_height = self
|
||||
.vertical_scroll_handle
|
||||
.0
|
||||
.borrow()
|
||||
.last_item_size
|
||||
.map(|size| size.item.height);
|
||||
let total_height = self
|
||||
.vertical_scroll_handle
|
||||
.0
|
||||
.borrow()
|
||||
.base_handle
|
||||
.bounds()
|
||||
.size
|
||||
.height;
|
||||
|
||||
// Calculate the extra rows needed to fill the table for stripe style.
|
||||
let mut extra_rows_needed = 0;
|
||||
if self.stripe {
|
||||
if let Some(row_height) = row_height {
|
||||
if row_height > px(0.) {
|
||||
let actual_height = row_height * rows_count as f32;
|
||||
let remaining_height = total_height - actual_height;
|
||||
if remaining_height > px(0.) {
|
||||
extra_rows_needed = (remaining_height / row_height).ceil() as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let extra_rows_needed = self.calculate_extra_rows_needed(rows_count);
|
||||
|
||||
let inner_table = v_flex()
|
||||
.key_context("Table")
|
||||
|
|
@ -1405,6 +1423,17 @@ where
|
|||
rows_count + extra_rows_needed,
|
||||
{
|
||||
move |table, visible_range, cx| {
|
||||
// We must calculate the col sizes here, because the col sizes
|
||||
// need render_th first, then that method will set the bounds of each col.
|
||||
let col_sizes: Rc<Vec<gpui::Size<Pixels>>> = Rc::new(
|
||||
table
|
||||
.col_groups
|
||||
.iter()
|
||||
.skip(left_cols_count)
|
||||
.map(|col| col.bounds.size)
|
||||
.collect(),
|
||||
);
|
||||
|
||||
table.load_more_if_need(rows_count, visible_range.end, cx);
|
||||
table.update_visible_range_if_need(
|
||||
visible_range.clone(),
|
||||
|
|
@ -1430,6 +1459,7 @@ where
|
|||
row_ix,
|
||||
rows_count,
|
||||
left_cols_count,
|
||||
col_sizes.clone(),
|
||||
cols_count,
|
||||
cx,
|
||||
));
|
||||
|
|
|
|||
Loading…
Reference in a new issue