From c9b5993472a6ce00a0f45a8e6204c8f21547566d Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 15 Jul 2025 11:56:07 +0800 Subject: [PATCH] story: Improve story case style. (#1060) --- Cargo.toml | 3 + crates/story/src/checkbox_story.rs | 109 ++-- crates/story/src/clipboard_story.rs | 52 +- crates/story/src/drawer_story.rs | 4 +- crates/story/src/fixtures/counters.json | 712 ++++++++++++++++++++++++ crates/story/src/input_story.rs | 18 +- crates/story/src/label_story.rs | 6 + crates/story/src/otp_input_story.rs | 16 +- crates/story/src/table_story.rs | 191 +++++-- crates/ui/src/label.rs | 40 +- crates/ui/src/theme/schema.rs | 2 +- themes/molokai.json | 4 +- 12 files changed, 996 insertions(+), 161 deletions(-) create mode 100644 crates/story/src/fixtures/counters.json diff --git a/Cargo.toml b/Cargo.toml index cfaf5f37..a7bda8ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,6 @@ resvg = { opt-level = 3 } rustybuzz = { opt-level = 3 } taffy = { opt-level = 3 } ttf-parser = { opt-level = 3 } + +[workspace.metadata.typos] +files.extend-exclude = ["**/fixtures/*"] diff --git a/crates/story/src/checkbox_story.rs b/crates/story/src/checkbox_story.rs index 94e57f71..b05c2461 100644 --- a/crates/story/src/checkbox_story.rs +++ b/crates/story/src/checkbox_story.rs @@ -66,20 +66,12 @@ impl Render for CheckboxStory { section("Checkbox") .child( Checkbox::new("check1") + .label("A normal checkbox") .checked(self.check1) .on_click(cx.listener(|v, _, _, _| { v.check1 = !v.check1; })), ) - .child( - Checkbox::new("check2") - .small() - .checked(self.check2) - .label("With 中文 Label") - .on_click(cx.listener(|v, _, _, _| { - v.check2 = !v.check2; - })), - ) .child( Checkbox::new("check3") .checked(self.check3) @@ -90,9 +82,39 @@ impl Render for CheckboxStory { ), ) .child( - section("Disabled").child( + section("Without label").child( + Checkbox::new("check1") + .checked(self.check1) + .on_click(cx.listener(|v, _, _, _| { + v.check1 = !v.check1; + })), + ), + ) + .child( + section("Small size").max_w_md().child( + Checkbox::new("check4") + .small() + .checked(self.check2) + .label("A small checkbox") + .on_click(cx.listener(|v, _, _, _| { + v.check2 = !v.check2; + })), + ), + ) + .child( + section("Large size").max_w_md().child( + Checkbox::new("check5") + .large() + .checked(self.check2) + .label("A large checkbox") + .on_click(cx.listener(|v, _, _, _| { + v.check2 = !v.check2; + })), + ), + ) + .child( + section("Disabled").max_w_md().child( h_flex() - .w_full() .items_center() .gap_6() .child( @@ -110,40 +132,39 @@ impl Render for CheckboxStory { ), ) .child( - section("Multi-line Label").child( - v_flex() - .gap_4() - .child( - Checkbox::new("longlong-checkbox") - .large() - .w(px(300.)) - .checked(self.check4) - .label("The long long label text.") - .child(div().text_color(cx.theme().muted_foreground).child( - "This is a long long label text that \ + section("Multi-line").child( + v_flex().gap_4().child( + Checkbox::new("multi-line-checkbox") + .w(px(300.)) + .checked(self.check4) + .label("A multi-line checkbox.") + .child(div().text_color(cx.theme().muted_foreground).child( + "This is a long long label text that \ should wrap when the text is too long.", - )) - .on_click(cx.listener(|v, _, _, _| { - v.check4 = !v.check4; - })), - ) - .child( - Checkbox::new("longlong-markdown-checkbox") - .w(px(300.)) - .checked(self.check5) - .label("Label with description") - .child(div().text_color(cx.theme().muted_foreground).child( - TextView::markdown( - "longlong-markdown-checkbox", - "The [long long label](https://github.com) \ - text used markdown, \ - it should wrap when the text is too long.", - ), - )) - .on_click(cx.listener(|v, _, _, _| { - v.check5 = !v.check5; - })), - ), + )) + .on_click(cx.listener(|v, _, _, _| { + v.check4 = !v.check4; + })), + ), + ), + ) + .child( + section("Rich description (Markdown)").child( + Checkbox::new("longlong-markdown-checkbox") + .w(px(300.)) + .checked(self.check5) + .label("Label with description (Markdown)") + .child(div().text_color(cx.theme().muted_foreground).child( + TextView::markdown( + "longlong-markdown-checkbox", + "The [long long label](https://github.com) \ + text used **Markdown**, \ + it should wrap when the text is too long.", + ), + )) + .on_click(cx.listener(|v, _, _, _| { + v.check5 = !v.check5; + })), ), ), ) diff --git a/crates/story/src/clipboard_story.rs b/crates/story/src/clipboard_story.rs index 897d3a3f..6467ba86 100644 --- a/crates/story/src/clipboard_story.rs +++ b/crates/story/src/clipboard_story.rs @@ -3,12 +3,18 @@ use gpui::{ Styled, Window, }; -use gpui_component::{clipboard::Clipboard, label::Label, link::Link, v_flex, ContextModal}; +use gpui_component::{ + clipboard::Clipboard, + input::{InputState, TextInput}, + label::Label, + v_flex, ContextModal, +}; use crate::section; pub struct ClipboardStory { focus_handle: gpui::FocusHandle, + url_state: Entity, masked: bool, } @@ -27,8 +33,12 @@ impl super::Story for ClipboardStory { } impl ClipboardStory { - pub(crate) fn new(_: &mut Window, cx: &mut App) -> Self { + pub(crate) fn new(window: &mut Window, cx: &mut App) -> Self { + let url_state = + cx.new(|cx| InputState::new(window, cx).default_value("https://github.com")); + Self { + url_state, focus_handle: cx.focus_handle(), masked: false, } @@ -45,12 +55,12 @@ impl Focusable for ClipboardStory { } impl Render for ClipboardStory { fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement { - v_flex().gap_6().child( - section("Copy to Clipboard") - .max_w_md() - .child( + v_flex() + .gap_6() + .child( + section("Clipboard").max_w_md().child( Clipboard::new("clipboard1") - .content(|_, _| Label::new("Click icon to copy")) + .content(|_, _| Label::new("A clipboard button")) .value_fn({ let view = cx.entity().clone(); move |_, cx| { @@ -60,19 +70,21 @@ impl Render for ClipboardStory { .on_copied(|value, window, cx| { window.push_notification(format!("Copied value: {}", value), cx) }), - ) - .child( - Clipboard::new("clipboard2") - .content(|_, _| { - Link::new("link1") - .href("https://github.com") - .child("GitHub") - }) - .value("https://github.com") - .on_copied(|value, window, cx| { - window.push_notification(format!("Copied value: {}", value), cx) - }), ), - ) + ) + .child( + section("With in an Input").max_w_md().child( + TextInput::new(&self.url_state).suffix( + Clipboard::new("clipboard2") + .value_fn({ + let state = self.url_state.clone(); + move |_, cx| state.read(cx).value().clone() + }) + .on_copied(|value, window, cx| { + window.push_notification(format!("Copied value: {}", value), cx) + }), + ), + ), + ) } } diff --git a/crates/story/src/drawer_story.rs b/crates/story/src/drawer_story.rs index e2a00144..ea9c2159 100644 --- a/crates/story/src/drawer_story.rs +++ b/crates/story/src/drawer_story.rs @@ -20,8 +20,8 @@ use gpui_component::{ wry, ActiveTheme as _, ContextModal as _, Icon, IconName, Placement, }; -use crate::section; use crate::TestAction; +use crate::{section, Story}; pub struct ListItemDeletegate { story: WeakEntity, @@ -168,7 +168,7 @@ pub struct DrawerStory { overlay_closable: bool, } -impl super::Story for DrawerStory { +impl Story for DrawerStory { fn title() -> &'static str { "Drawer" } diff --git a/crates/story/src/fixtures/counters.json b/crates/story/src/fixtures/counters.json new file mode 100644 index 00000000..babbac8d --- /dev/null +++ b/crates/story/src/fixtures/counters.json @@ -0,0 +1,712 @@ +[ + { "symbol": "AAPL", "name": "Apple Inc.", "market": "US" }, + { "symbol": "MSFT", "name": "Microsoft Corp.", "market": "US" }, + { "symbol": "GOOGL", "name": "Alphabet Inc. Class A", "market": "US" }, + { "symbol": "AMZN", "name": "Amazon.com Inc.", "market": "US" }, + { "symbol": "META", "name": "Meta Platforms Inc.", "market": "US" }, + { "symbol": "TSLA", "name": "Tesla Inc.", "market": "US" }, + { + "symbol": "BRK.B", + "name": "Berkshire Hathaway Inc. Class B", + "market": "US" + }, + { "symbol": "NVDA", "name": "NVIDIA Corp.", "market": "US" }, + { "symbol": "JPM", "name": "JPMorgan Chase & Co.", "market": "US" }, + { "symbol": "V", "name": "Visa Inc.", "market": "US" }, + { "symbol": "UNH", "name": "UnitedHealth Group Inc.", "market": "US" }, + { "symbol": "MA", "name": "Mastercard Inc.", "market": "US" }, + { "symbol": "HD", "name": "Home Depot Inc.", "market": "US" }, + { "symbol": "PG", "name": "Procter & Gamble Co.", "market": "US" }, + { "symbol": "LLY", "name": "Eli Lilly and Co.", "market": "US" }, + { "symbol": "BAC", "name": "Bank of America Corp.", "market": "US" }, + { "symbol": "XOM", "name": "Exxon Mobil Corp.", "market": "US" }, + { "symbol": "KO", "name": "Coca-Cola Co.", "market": "US" }, + { "symbol": "MRK", "name": "Merck & Co. Inc.", "market": "US" }, + { "symbol": "PEP", "name": "PepsiCo Inc.", "market": "US" }, + { "symbol": "ABBV", "name": "AbbVie Inc.", "market": "US" }, + { "symbol": "AVGO", "name": "Broadcom Inc.", "market": "US" }, + { "symbol": "COST", "name": "Costco Wholesale Corp.", "market": "US" }, + { "symbol": "WMT", "name": "Walmart Inc.", "market": "US" }, + { "symbol": "MCD", "name": "McDonald's Corp.", "market": "US" }, + { "symbol": "ADBE", "name": "Adobe Inc.", "market": "US" }, + { "symbol": "CRM", "name": "Salesforce Inc.", "market": "US" }, + { "symbol": "NFLX", "name": "Netflix Inc.", "market": "US" }, + { "symbol": "TMO", "name": "Thermo Fisher Scientific Inc.", "market": "US" }, + { "symbol": "ACN", "name": "Accenture plc", "market": "US" }, + { "symbol": "LIN", "name": "Linde plc", "market": "US" }, + { "symbol": "TXN", "name": "Texas Instruments Inc.", "market": "US" }, + { "symbol": "QCOM", "name": "Qualcomm Inc.", "market": "US" }, + { "symbol": "NEE", "name": "NextEra Energy Inc.", "market": "US" }, + { + "symbol": "PM", + "name": "Philip Morris International Inc.", + "market": "US" + }, + { "symbol": "HON", "name": "Honeywell International Inc.", "market": "US" }, + { "symbol": "ORCL", "name": "Oracle Corp.", "market": "US" }, + { "symbol": "AMGN", "name": "Amgen Inc.", "market": "US" }, + { "symbol": "INTC", "name": "Intel Corp.", "market": "US" }, + { "symbol": "DHR", "name": "Danaher Corp.", "market": "US" }, + { "symbol": "LOW", "name": "Lowe's Companies Inc.", "market": "US" }, + { "symbol": "UPS", "name": "United Parcel Service Inc.", "market": "US" }, + { "symbol": "SBUX", "name": "Starbucks Corp.", "market": "US" }, + { "symbol": "CVX", "name": "Chevron Corp.", "market": "US" }, + { "symbol": "GS", "name": "Goldman Sachs Group Inc.", "market": "US" }, + { "symbol": "MDT", "name": "Medtronic plc", "market": "US" }, + { "symbol": "AXP", "name": "American Express Co.", "market": "US" }, + { "symbol": "SPGI", "name": "S&P Global Inc.", "market": "US" }, + { "symbol": "BLK", "name": "BlackRock Inc.", "market": "US" }, + { "symbol": "SYK", "name": "Stryker Corp.", "market": "US" }, + { "symbol": "ISRG", "name": "Intuitive Surgical Inc.", "market": "US" }, + { "symbol": "DE", "name": "Deere & Co.", "market": "US" }, + { "symbol": "PLD", "name": "Prologis Inc.", "market": "US" }, + { "symbol": "SCHW", "name": "Charles Schwab Corp.", "market": "US" }, + { "symbol": "BKNG", "name": "Booking Holdings Inc.", "market": "US" }, + { "symbol": "CI", "name": "Cigna Group", "market": "US" }, + { "symbol": "CB", "name": "Chubb Ltd.", "market": "US" }, + { + "symbol": "MMC", + "name": "Marsh & McLennan Companies Inc.", + "market": "US" + }, + { "symbol": "ADP", "name": "Automatic Data Processing Inc.", "market": "US" }, + { "symbol": "LRCX", "name": "Lam Research Corp.", "market": "US" }, + { "symbol": "CME", "name": "CME Group Inc.", "market": "US" }, + { "symbol": "TGT", "name": "Target Corp.", "market": "US" }, + { "symbol": "DUK", "name": "Duke Energy Corp.", "market": "US" }, + { "symbol": "GILD", "name": "Gilead Sciences Inc.", "market": "US" }, + { "symbol": "AMAT", "name": "Applied Materials Inc.", "market": "US" }, + { "symbol": "FISV", "name": "Fiserv Inc.", "market": "US" }, + { "symbol": "MO", "name": "Altria Group Inc.", "market": "US" }, + { "symbol": "VRTX", "name": "Vertex Pharmaceuticals Inc.", "market": "US" }, + { + "symbol": "REGN", + "name": "Regeneron Pharmaceuticals Inc.", + "market": "US" + }, + { "symbol": "PGR", "name": "Progressive Corp.", "market": "US" }, + { "symbol": "ELV", "name": "Elevance Health Inc.", "market": "US" }, + { "symbol": "EOG", "name": "EOG Resources Inc.", "market": "US" }, + { "symbol": "FDX", "name": "FedEx Corp.", "market": "US" }, + { + "symbol": "APD", + "name": "Air Products and Chemicals Inc.", + "market": "US" + }, + { "symbol": "AON", "name": "Aon plc", "market": "US" }, + { "symbol": "ITW", "name": "Illinois Tool Works Inc.", "market": "US" }, + { "symbol": "BSX", "name": "Boston Scientific Corp.", "market": "US" }, + { "symbol": "GM", "name": "General Motors Co.", "market": "US" }, + { "symbol": "HCA", "name": "HCA Healthcare Inc.", "market": "US" }, + { "symbol": "GD", "name": "General Dynamics Corp.", "market": "US" }, + { "symbol": "ZTS", "name": "Zoetis Inc.", "market": "US" }, + { "symbol": "SYY", "name": "Sysco Corp.", "market": "US" }, + { + "symbol": "AIG", + "name": "American International Group Inc.", + "market": "US" + }, + { "symbol": "MCO", "name": "Moody's Corp.", "market": "US" }, + { "symbol": "MS", "name": "Morgan Stanley", "market": "US" }, + { "symbol": "SLB", "name": "Schlumberger Ltd.", "market": "US" }, + { "symbol": "SO", "name": "Southern Co.", "market": "US" }, + { "symbol": "WM", "name": "Waste Management Inc.", "market": "US" }, + { "symbol": "D", "name": "Dominion Energy Inc.", "market": "US" }, + { "symbol": "PSA", "name": "Public Storage", "market": "US" }, + { "symbol": "CNC", "name": "Centene Corp.", "market": "US" }, + { "symbol": "TRV", "name": "Travelers Companies Inc.", "market": "US" }, + { "symbol": "AFL", "name": "Aflac Inc.", "market": "US" }, + { "symbol": "VLO", "name": "Valero Energy Corp.", "market": "US" }, + { "symbol": "WELL", "name": "Welltower Inc.", "market": "US" }, + { "symbol": "F", "name": "Ford Motor Co.", "market": "US" }, + { "symbol": "STZ", "name": "Constellation Brands Inc.", "market": "US" }, + { "symbol": "NOC", "name": "Northrop Grumman Corp.", "market": "US" }, + { "symbol": "KHC", "name": "Kraft Heinz Co.", "market": "US" }, + { "symbol": "EXC", "name": "Exelon Corp.", "market": "US" }, + { "symbol": "CARR", "name": "Carrier Global Corp.", "market": "US" }, + { "symbol": "HES", "name": "Hess Corp.", "market": "US" }, + { "symbol": "WMB", "name": "Williams Companies Inc.", "market": "US" }, + { "symbol": "VTR", "name": "Ventas Inc.", "market": "US" }, + { "symbol": "DOW", "name": "Dow Inc.", "market": "US" }, + { "symbol": "BKR", "name": "Baker Hughes Co.", "market": "US" }, + { "symbol": "OKE", "name": "ONEOK Inc.", "market": "US" }, + { "symbol": "NUE", "name": "Nucor Corp.", "market": "US" }, + { "symbol": "CPB", "name": "Campbell Soup Co.", "market": "US" }, + { "symbol": "CL", "name": "Colgate-Palmolive Co.", "market": "US" }, + { "symbol": "EMR", "name": "Emerson Electric Co.", "market": "US" }, + { "symbol": "ETN", "name": "Eaton Corp. plc", "market": "US" }, + { "symbol": "ROK", "name": "Rockwell Automation Inc.", "market": "US" }, + { + "symbol": "IFF", + "name": "International Flavors & Fragrances Inc.", + "market": "US" + }, + { "symbol": "XYL", "name": "Xylem Inc.", "market": "US" }, + { + "symbol": "WAB", + "name": "Westinghouse Air Brake Technologies Corp.", + "market": "US" + }, + { "symbol": "TDG", "name": "TransDigm Group Inc.", "market": "US" }, + { "symbol": "MAS", "name": "Masco Corp.", "market": "US" }, + { "symbol": "AWK", "name": "American Water Works Co. Inc.", "market": "US" }, + { "symbol": "PNR", "name": "Pentair plc", "market": "US" }, + { "symbol": "AOS", "name": "A. O. Smith Corp.", "market": "US" }, + { "symbol": "NDSN", "name": "Nordson Corp.", "market": "US" }, + { "symbol": "ALB", "name": "Albemarle Corp.", "market": "US" }, + { "symbol": "APTV", "name": "Aptiv PLC", "market": "US" }, + { "symbol": "BWA", "name": "BorgWarner Inc.", "market": "US" }, + { "symbol": "CUM", "name": "Cummins Inc.", "market": "US" }, + { "symbol": "DOV", "name": "Dover Corp.", "market": "US" }, + { "symbol": "FLS", "name": "Flowserve Corp.", "market": "US" }, + { "symbol": "GWW", "name": "W.W. Grainger Inc.", "market": "US" }, + { "symbol": "IR", "name": "Ingersoll Rand Inc.", "market": "US" }, + { "symbol": "IT", "name": "Gartner Inc.", "market": "US" }, + { "symbol": "J", "name": "Jacobs Solutions Inc.", "market": "US" }, + { + "symbol": "LECO", + "name": "Lincoln Electric Holdings Inc.", + "market": "US" + }, + { "symbol": "MIDD", "name": "Middleby Corp.", "market": "US" }, + { "symbol": "MLI", "name": "Mueller Industries Inc.", "market": "US" }, + { "symbol": "NVT", "name": "nVent Electric plc", "market": "US" }, + { "symbol": "OSK", "name": "Oshkosh Corp.", "market": "US" }, + { "symbol": "PWR", "name": "Quanta Services Inc.", "market": "US" }, + { "symbol": "RBC", "name": "Regal Rexnord Corp.", "market": "US" }, + { "symbol": "SNA", "name": "Snap-on Inc.", "market": "US" }, + { "symbol": "SWK", "name": "Stanley Black & Decker Inc.", "market": "US" }, + { "symbol": "TT", "name": "Trane Technologies plc", "market": "US" }, + { "symbol": "VMI", "name": "Valmont Industries Inc.", "market": "US" }, + { "symbol": "WMS", "name": "Advanced Drainage Systems Inc.", "market": "US" }, + { "symbol": "XYL", "name": "Xylem Inc.", "market": "US" }, + { "symbol": "0700.HK", "name": "Tencent Holdings Ltd.", "market": "HK" }, + { "symbol": "9988.HK", "name": "Alibaba Group Holding Ltd.", "market": "HK" }, + { "symbol": "3690.HK", "name": "Meituan", "market": "HK" }, + { "symbol": "1299.HK", "name": "AIA Group Ltd.", "market": "HK" }, + { "symbol": "0005.HK", "name": "HSBC Holdings plc", "market": "HK" }, + { + "symbol": "2318.HK", + "name": "Ping An Insurance Group Co.", + "market": "HK" + }, + { + "symbol": "2382.HK", + "name": "Sunny Optical Technology Group Co.", + "market": "HK" + }, + { "symbol": "1810.HK", "name": "Xiaomi Corp.", "market": "HK" }, + { + "symbol": "0823.HK", + "name": "Link Real Estate Investment Trust", + "market": "HK" + }, + { "symbol": "0001.HK", "name": "CK Hutchison Holdings Ltd.", "market": "HK" }, + { + "symbol": "0027.HK", + "name": "Galaxy Entertainment Group Ltd.", + "market": "HK" + }, + { "symbol": "0011.HK", "name": "Hang Seng Bank Ltd.", "market": "HK" }, + { "symbol": "0002.HK", "name": "CLP Holdings Ltd.", "market": "HK" }, + { + "symbol": "0003.HK", + "name": "Hong Kong & China Gas Co. Ltd.", + "market": "HK" + }, + { "symbol": "0006.HK", "name": "Power Assets Holdings Ltd.", "market": "HK" }, + { + "symbol": "0016.HK", + "name": "Sun Hung Kai Properties Ltd.", + "market": "HK" + }, + { + "symbol": "0017.HK", + "name": "New World Development Co. Ltd.", + "market": "HK" + }, + { "symbol": "0023.HK", "name": "Bank of East Asia Ltd.", "market": "HK" }, + { "symbol": "0066.HK", "name": "MTR Corp. Ltd.", "market": "HK" }, + { "symbol": "0083.HK", "name": "Sino Land Co. Ltd.", "market": "HK" }, + { "symbol": "0101.HK", "name": "Hang Lung Properties Ltd.", "market": "HK" }, + { + "symbol": "0144.HK", + "name": "China Merchants Port Holdings Co. Ltd.", + "market": "HK" + }, + { + "symbol": "0151.HK", + "name": "Want Want China Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "0175.HK", + "name": "Geely Automobile Holdings Ltd.", + "market": "HK" + }, + { "symbol": "0207.HK", "name": "Joy City Property Ltd.", "market": "HK" }, + { "symbol": "0267.HK", "name": "CITIC Ltd.", "market": "HK" }, + { "symbol": "0288.HK", "name": "WH Group Ltd.", "market": "HK" }, + { + "symbol": "0322.HK", + "name": "China Oilfield Services Ltd.", + "market": "HK" + }, + { + "symbol": "0386.HK", + "name": "China Petroleum & Chemical Corp.", + "market": "HK" + }, + { + "symbol": "0393.HK", + "name": "China Merchants China Direct Investments Ltd.", + "market": "HK" + }, + { + "symbol": "0416.HK", + "name": "Kwoon Chung Bus Holdings Ltd.", + "market": "HK" + }, + { "symbol": "0451.HK", "name": "Xinyi Glass Holdings Ltd.", "market": "HK" }, + { + "symbol": "0522.HK", + "name": "ASM Pacific Technology Ltd.", + "market": "HK" + }, + { + "symbol": "0575.HK", + "name": "Pacific Textiles Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "0606.HK", + "name": "China Agri-Industries Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "0669.HK", + "name": "Techtronic Industries Co. Ltd.", + "market": "HK" + }, + { + "symbol": "0688.HK", + "name": "China Overseas Land & Investment Ltd.", + "market": "HK" + }, + { + "symbol": "0708.HK", + "name": "China Everbright International Ltd.", + "market": "HK" + }, + { + "symbol": "0762.HK", + "name": "China Unicom (Hong Kong) Ltd.", + "market": "HK" + }, + { + "symbol": "0808.HK", + "name": "China Oilfield Services Ltd.", + "market": "HK" + }, + { + "symbol": "0836.HK", + "name": "China Resources Power Holdings Co. Ltd.", + "market": "HK" + }, + { "symbol": "0857.HK", "name": "PetroChina Co. Ltd.", "market": "HK" }, + { "symbol": "0883.HK", "name": "CNOOC Ltd.", "market": "HK" }, + { + "symbol": "0939.HK", + "name": "China Construction Bank Corp.", + "market": "HK" + }, + { "symbol": "0941.HK", "name": "China Mobile Ltd.", "market": "HK" }, + { "symbol": "0968.HK", "name": "Xinyi Solar Holdings Ltd.", "market": "HK" }, + { "symbol": "0992.HK", "name": "Lenovo Group Ltd.", "market": "HK" }, + { + "symbol": "1038.HK", + "name": "CK Infrastructure Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "1044.HK", + "name": "Hengan International Group Co. Ltd.", + "market": "HK" + }, + { + "symbol": "1093.HK", + "name": "CSPC Pharmaceutical Group Ltd.", + "market": "HK" + }, + { "symbol": "1109.HK", "name": "China Resources Land Ltd.", "market": "HK" }, + { "symbol": "1113.HK", "name": "CK Asset Holdings Ltd.", "market": "HK" }, + { + "symbol": "1137.HK", + "name": "Hong Kong Technology Venture Co. Ltd.", + "market": "HK" + }, + { + "symbol": "1177.HK", + "name": "Sino Biopharmaceutical Ltd.", + "market": "HK" + }, + { "symbol": "1208.HK", "name": "MMG Ltd.", "market": "HK" }, + { "symbol": "1211.HK", "name": "BYD Co. Ltd.", "market": "HK" }, + { + "symbol": "1288.HK", + "name": "Agricultural Bank of China Ltd.", + "market": "HK" + }, + { + "symbol": "1336.HK", + "name": "New China Life Insurance Co. Ltd.", + "market": "HK" + }, + { + "symbol": "1359.HK", + "name": "China Cinda Asset Management Co. Ltd.", + "market": "HK" + }, + { + "symbol": "1398.HK", + "name": "Industrial and Commercial Bank of China Ltd.", + "market": "HK" + }, + { + "symbol": "1515.HK", + "name": "China Resources Medical Holdings Co. Ltd.", + "market": "HK" + }, + { + "symbol": "1585.HK", + "name": "Yihai International Holding Ltd.", + "market": "HK" + }, + { "symbol": "1658.HK", "name": "Post Holdings Ltd.", "market": "HK" }, + { "symbol": "1772.HK", "name": "Ganfeng Lithium Co. Ltd.", "market": "HK" }, + { "symbol": "1816.HK", "name": "CGN Power Co. Ltd.", "market": "HK" }, + { + "symbol": "1876.HK", + "name": "Budweiser Brewing Company APAC Ltd.", + "market": "HK" + }, + { "symbol": "1928.HK", "name": "Sands China Ltd.", "market": "HK" }, + { + "symbol": "1997.HK", + "name": "Wharf Real Estate Investment Co. Ltd.", + "market": "HK" + }, + { + "symbol": "2007.HK", + "name": "Country Garden Holdings Co. Ltd.", + "market": "HK" + }, + { + "symbol": "2018.HK", + "name": "AAC Technologies Holdings Inc.", + "market": "HK" + }, + { "symbol": "2020.HK", "name": "ANTA Sports Products Ltd.", "market": "HK" }, + { + "symbol": "2196.HK", + "name": "Fuyao Glass Industry Group Co. Ltd.", + "market": "HK" + }, + { "symbol": "2233.HK", "name": "West China Cement Ltd.", "market": "HK" }, + { + "symbol": "2313.HK", + "name": "Shenzhou International Group Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "2328.HK", + "name": "PICC Property and Casualty Co. Ltd.", + "market": "HK" + }, + { "symbol": "2331.HK", "name": "Li Ning Co. Ltd.", "market": "HK" }, + { + "symbol": "2388.HK", + "name": "BOC Hong Kong Holdings Ltd.", + "market": "HK" + }, + { + "symbol": "2412.HK", + "name": "China Merchants Bank Co. Ltd.", + "market": "HK" + }, + { "symbol": "2428.HK", "name": "YTO Express Group Co. Ltd.", "market": "HK" }, + { + "symbol": "2600.HK", + "name": "China Aluminum International Engineering Corp. Ltd.", + "market": "HK" + }, + { + "symbol": "2628.HK", + "name": "China Life Insurance Co. Ltd.", + "market": "HK" + }, + { "symbol": "2688.HK", "name": "ENN Energy Holdings Ltd.", "market": "HK" }, + { "symbol": "2800.HK", "name": "Tracker Fund of Hong Kong", "market": "HK" }, + { "symbol": "2822.HK", "name": "CSOP FTSE China A50 ETF", "market": "HK" }, + { + "symbol": "2883.HK", + "name": "China Oilfield Services Ltd.", + "market": "HK" + }, + { + "symbol": "2899.HK", + "name": "Zijin Mining Group Co. Ltd.", + "market": "HK" + }, + { + "symbol": "3328.HK", + "name": "Bank of Communications Co. Ltd.", + "market": "HK" + }, + { "symbol": "3988.HK", "name": "Bank of China Ltd.", "market": "HK" }, + { + "symbol": "BABA", + "name": "Alibaba Group Holding Ltd. ADR", + "market": "US" + }, + { "symbol": "JD", "name": "JD.com Inc. ADR", "market": "US" }, + { "symbol": "PDD", "name": "PDD Holdings Inc. ADR", "market": "US" }, + { "symbol": "NTES", "name": "NetEase Inc. ADR", "market": "US" }, + { "symbol": "TAL", "name": "TAL Education Group ADR", "market": "US" }, + { "symbol": "YUMC", "name": "Yum China Holdings Inc.", "market": "US" }, + { "symbol": "ZTO", "name": "ZTO Express (Cayman) Inc. ADR", "market": "US" }, + { "symbol": "BGNE", "name": "BeiGene Ltd. ADR", "market": "US" }, + { "symbol": "GDS", "name": "GDS Holdings Ltd. ADR", "market": "US" }, + { "symbol": "HUYA", "name": "HUYA Inc. ADR", "market": "US" }, + { "symbol": "WB", "name": "Weibo Corp. ADR", "market": "US" }, + { "symbol": "IQ", "name": "iQIYI Inc. ADR", "market": "US" }, + { "symbol": "MOMO", "name": "Hello Group Inc. ADR", "market": "US" }, + { "symbol": "SINA", "name": "Sina Corp.", "market": "US" }, + { "symbol": "BIDU", "name": "Baidu Inc. ADR", "market": "US" }, + { "symbol": "XPEV", "name": "XPeng Inc. ADR", "market": "US" }, + { "symbol": "LI", "name": "Li Auto Inc. ADR", "market": "US" }, + { "symbol": "NIO", "name": "NIO Inc. ADR", "market": "US" }, + { "symbol": "EH", "name": "EHang Holdings Ltd. ADR", "market": "US" }, + { + "symbol": "TME", + "name": "Tencent Music Entertainment Group ADR", + "market": "US" + }, + { "symbol": "DIDI", "name": "DiDi Global Inc. ADR", "market": "US" }, + { "symbol": "QFIN", "name": "360 DigiTech Inc. ADR", "market": "US" }, + { + "symbol": "KC", + "name": "Kingsoft Cloud Holdings Ltd. ADR", + "market": "US" + }, + { + "symbol": "JKS", + "name": "JinkoSolar Holding Co. Ltd. ADR", + "market": "US" + }, + { "symbol": "SOL", "name": "Emeren Group Ltd. ADR", "market": "US" }, + { "symbol": "DQ", "name": "Daqo New Energy Corp. ADR", "market": "US" }, + { "symbol": "CAN", "name": "Canaan Inc. ADR", "market": "US" }, + { + "symbol": "EDU", + "name": "New Oriental Education & Technology Group Inc. ADR", + "market": "US" + }, + { "symbol": "ATHM", "name": "Autohome Inc. ADR", "market": "US" }, + { "symbol": "BZUN", "name": "Baozun Inc. ADR", "market": "US" }, + { "symbol": "LK", "name": "Luckin Coffee Inc. ADR", "market": "US" }, + { "symbol": "YJ", "name": "Yunji Inc. ADR", "market": "US" }, + { "symbol": "VIOT", "name": "Viomi Technology Co. Ltd. ADR", "market": "US" }, + { "symbol": "WBAI", "name": "500.com Ltd. ADR", "market": "US" }, + { "symbol": "SFUN", "name": "Fang Holdings Ltd. ADR", "market": "US" }, + { "symbol": "CTRP", "name": "Trip.com Group Ltd. ADR", "market": "US" }, + { "symbol": "HTHT", "name": "H World Group Ltd. ADR", "market": "US" }, + { "symbol": "VIPS", "name": "Vipshop Holdings Ltd. ADR", "market": "US" }, + { "symbol": "YY", "name": "JOYY Inc. ADR", "market": "US" }, + { + "symbol": "ZNH", + "name": "China Southern Airlines Co. Ltd. ADR", + "market": "US" + }, + { + "symbol": "CEA", + "name": "China Eastern Airlines Corp. Ltd. ADR", + "market": "US" + }, + { + "symbol": "SNP", + "name": "China Petroleum & Chemical Corp. ADR", + "market": "US" + }, + { "symbol": "PTR", "name": "PetroChina Co. Ltd. ADR", "market": "US" }, + { + "symbol": "ACH", + "name": "Aluminum Corp. of China Ltd. ADR", + "market": "US" + }, + { + "symbol": "SHI", + "name": "Sinopec Shanghai Petrochemical Co. Ltd. ADR", + "market": "US" + }, + { + "symbol": "HNP", + "name": "Huaneng Power International Inc. ADR", + "market": "US" + }, + { "symbol": "CHA", "name": "China Telecom Corp. Ltd. ADR", "market": "US" }, + { "symbol": "CHL", "name": "China Mobile Ltd. ADR", "market": "US" }, + { "symbol": "CMCM", "name": "Cheetah Mobile Inc. ADR", "market": "US" }, + { "symbol": "CJJD", "name": "China Jo-Jo Drugstores Inc.", "market": "US" }, + { + "symbol": "CNTF", + "name": "China TechFaith Wireless Communication Technology Ltd.", + "market": "US" + }, + { + "symbol": "CNET", + "name": "ZW Data Action Technologies Inc.", + "market": "US" + }, + { "symbol": "CTK", "name": "CooTek (Cayman) Inc. ADR", "market": "US" }, + { "symbol": "DOGZ", "name": "Dogness (International) Corp.", "market": "US" }, + { "symbol": "FANH", "name": "Fanhua Inc. ADR", "market": "US" }, + { + "symbol": "GSMG", + "name": "Glory Star New Media Group Holdings Ltd.", + "market": "US" + }, + { "symbol": "JFIN", "name": "Jiayin Group Inc. ADR", "market": "US" }, + { "symbol": "KZIA", "name": "Kazia Therapeutics Ltd. ADR", "market": "US" }, + { "symbol": "LIZI", "name": "Lizhi Inc. ADR", "market": "US" }, + { "symbol": "MDJH", "name": "MDJM Ltd.", "market": "US" }, + { "symbol": "MTC", "name": "MMTec Inc.", "market": "US" }, + { "symbol": "MY", "name": "MYR Group Inc.", "market": "US" }, + { "symbol": "NCTY", "name": "The9 Ltd. ADR", "market": "US" }, + { "symbol": "PUYI", "name": "Puyi Inc. ADR", "market": "US" }, + { + "symbol": "RAAS", + "name": "Cloopen Group Holding Ltd. ADR", + "market": "US" + }, + { "symbol": "RENN", "name": "Renren Inc. ADR", "market": "US" }, + { "symbol": "SECO", "name": "Secoo Holding Ltd. ADR", "market": "US" }, + { "symbol": "SISI", "name": "Shineco Inc.", "market": "US" }, + { "symbol": "SOS", "name": "SOS Ltd. ADR", "market": "US" }, + { "symbol": "TC", "name": "TuanChe Ltd. ADR", "market": "US" }, + { "symbol": "TEDU", "name": "Tarena International Inc. ADR", "market": "US" }, + { "symbol": "TIGR", "name": "UP Fintech Holding Ltd. ADR", "market": "US" }, + { "symbol": "TOUR", "name": "Tuniu Corp. ADR", "market": "US" }, + { "symbol": "WAFU", "name": "Wah Fu Education Group Ltd.", "market": "US" }, + { "symbol": "XNET", "name": "Xunlei Ltd. ADR", "market": "US" }, + { "symbol": "YRD", "name": "Yiren Digital Ltd. ADR", "market": "US" }, + { "symbol": "ZEPP", "name": "Zepp Health Corp. ADR", "market": "US" }, + { + "symbol": "ZKIN", + "name": "ZK International Group Co. Ltd.", + "market": "US" + }, + { "symbol": "ZLAB", "name": "Zai Lab Ltd. ADR", "market": "US" }, + { "symbol": "ZM", "name": "Zoom Video Communications Inc.", "market": "US" }, + { "symbol": "SNAP", "name": "Snap Inc.", "market": "US" }, + { "symbol": "SQ", "name": "Block Inc.", "market": "US" }, + { "symbol": "ROKU", "name": "Roku Inc.", "market": "US" }, + { "symbol": "DOCU", "name": "DocuSign Inc.", "market": "US" }, + { "symbol": "SHOP", "name": "Shopify Inc.", "market": "US" }, + { "symbol": "TWLO", "name": "Twilio Inc.", "market": "US" }, + { "symbol": "CRWD", "name": "CrowdStrike Holdings Inc.", "market": "US" }, + { "symbol": "OKTA", "name": "Okta Inc.", "market": "US" }, + { "symbol": "ZS", "name": "Zscaler Inc.", "market": "US" }, + { "symbol": "DDOG", "name": "Datadog Inc.", "market": "US" }, + { "symbol": "MDB", "name": "MongoDB Inc.", "market": "US" }, + { "symbol": "TEAM", "name": "Atlassian Corp.", "market": "US" }, + { "symbol": "FSLY", "name": "Fastly Inc.", "market": "US" }, + { "symbol": "NET", "name": "Cloudflare Inc.", "market": "US" }, + { "symbol": "PLAN", "name": "Anaplan Inc.", "market": "US" }, + { "symbol": "ESTC", "name": "Elastic N.V.", "market": "US" }, + { "symbol": "SMAR", "name": "Smartsheet Inc.", "market": "US" }, + { "symbol": "WORK", "name": "Slack Technologies Inc.", "market": "US" }, + { "symbol": "DOCS", "name": "Doximity Inc.", "market": "US" }, + { "symbol": "BILL", "name": "Bill Holdings Inc.", "market": "US" }, + { "symbol": "U", "name": "Unity Software Inc.", "market": "US" }, + { "symbol": "RBLX", "name": "Roblox Corp.", "market": "US" }, + { "symbol": "COIN", "name": "Coinbase Global Inc.", "market": "US" }, + { "symbol": "HOOD", "name": "Robinhood Markets Inc.", "market": "US" }, + { "symbol": "ABNB", "name": "Airbnb Inc.", "market": "US" }, + { "symbol": "LYFT", "name": "Lyft Inc.", "market": "US" }, + { "symbol": "UBER", "name": "Uber Technologies Inc.", "market": "US" }, + { "symbol": "DD", "name": "DuPont de Nemours Inc.", "market": "US" }, + { "symbol": "VEEV", "name": "Veeva Systems Inc.", "market": "US" }, + { "symbol": "FTNT", "name": "Fortinet Inc.", "market": "US" }, + { "symbol": "PINS", "name": "Pinterest Inc.", "market": "US" }, + { "symbol": "ETSY", "name": "Etsy Inc.", "market": "US" }, + { "symbol": "ALGN", "name": "Align Technology Inc.", "market": "US" }, + { "symbol": "TDOC", "name": "Teladoc Health Inc.", "market": "US" }, + { "symbol": "DOCS", "name": "Doximity Inc.", "market": "US" }, + { "symbol": "MTCH", "name": "Match Group Inc.", "market": "US" }, + { "symbol": "SPLK", "name": "Splunk Inc.", "market": "US" }, + { "symbol": "WDAY", "name": "Workday Inc.", "market": "US" }, + { "symbol": "HUBS", "name": "HubSpot Inc.", "market": "US" }, + { "symbol": "TTD", "name": "The Trade Desk Inc.", "market": "US" }, + { "symbol": "PAYC", "name": "Paycom Software Inc.", "market": "US" }, + { "symbol": "NOW", "name": "ServiceNow Inc.", "market": "US" }, + { "symbol": "SNOW", "name": "Snowflake Inc.", "market": "US" }, + { "symbol": "ZS", "name": "Zscaler Inc.", "market": "US" }, + { "symbol": "DDOG", "name": "Datadog Inc.", "market": "US" }, + { "symbol": "MDB", "name": "MongoDB Inc.", "market": "US" }, + { "symbol": "TEAM", "name": "Atlassian Corp.", "market": "US" }, + { "symbol": "FSLY", "name": "Fastly Inc.", "market": "US" }, + { "symbol": "NET", "name": "Cloudflare Inc.", "market": "US" }, + { "symbol": "PLAN", "name": "Anaplan Inc.", "market": "US" }, + { "symbol": "ESTC", "name": "Elastic N.V.", "market": "US" }, + { "symbol": "SMAR", "name": "Smartsheet Inc.", "market": "US" }, + { "symbol": "WORK", "name": "Slack Technologies Inc.", "market": "US" }, + { "symbol": "DOCS", "name": "Doximity Inc.", "market": "US" }, + { "symbol": "BILL", "name": "Bill Holdings Inc.", "market": "US" }, + { "symbol": "U", "name": "Unity Software Inc.", "market": "US" }, + { "symbol": "RBLX", "name": "Roblox Corp.", "market": "US" }, + { "symbol": "COIN", "name": "Coinbase Global Inc.", "market": "US" }, + { "symbol": "HOOD", "name": "Robinhood Markets Inc.", "market": "US" }, + { "symbol": "ABNB", "name": "Airbnb Inc.", "market": "US" }, + { "symbol": "LYFT", "name": "Lyft Inc.", "market": "US" }, + { "symbol": "UBER", "name": "Uber Technologies Inc.", "market": "US" }, + { "symbol": "DD", "name": "DuPont de Nemours Inc.", "market": "US" }, + { "symbol": "VEEV", "name": "Veeva Systems Inc.", "market": "US" }, + { "symbol": "FTNT", "name": "Fortinet Inc.", "market": "US" }, + { "symbol": "PINS", "name": "Pinterest Inc.", "market": "US" }, + { "symbol": "ETSY", "name": "Etsy Inc.", "market": "US" }, + { "symbol": "ALGN", "name": "Align Technology Inc.", "market": "US" }, + { "symbol": "TDOC", "name": "Teladoc Health Inc.", "market": "US" }, + { "symbol": "MTCH", "name": "Match Group Inc.", "market": "US" }, + { "symbol": "SPLK", "name": "Splunk Inc.", "market": "US" }, + { "symbol": "WDAY", "name": "Workday Inc.", "market": "US" }, + { "symbol": "HUBS", "name": "HubSpot Inc.", "market": "US" }, + { "symbol": "TTD", "name": "The Trade Desk Inc.", "market": "US" }, + { "symbol": "PAYC", "name": "Paycom Software Inc.", "market": "US" }, + { "symbol": "NOW", "name": "ServiceNow Inc.", "market": "US" }, + { "symbol": "SNOW", "name": "Snowflake Inc.", "market": "US" }, + { "symbol": "DOCU", "name": "DocuSign Inc.", "market": "US" }, + { "symbol": "SHOP", "name": "Shopify Inc.", "market": "US" }, + { "symbol": "TWLO", "name": "Twilio Inc.", "market": "US" }, + { "symbol": "CRWD", "name": "CrowdStrike Holdings Inc.", "market": "US" }, + { "symbol": "OKTA", "name": "Okta Inc.", "market": "US" }, + { "symbol": "ZS", "name": "Zscaler Inc.", "market": "US" }, + { "symbol": "DDOG", "name": "Datadog Inc.", "market": "US" }, + { "symbol": "MDB", "name": "MongoDB Inc.", "market": "US" }, + { "symbol": "TEAM", "name": "Atlassian Corp.", "market": "US" }, + { "symbol": "FSLY", "name": "Fastly Inc.", "market": "US" }, + { "symbol": "NET", "name": "Cloudflare Inc.", "market": "US" }, + { "symbol": "PLAN", "name": "Anaplan Inc.", "market": "US" }, + { "symbol": "ESTC", "name": "Elastic N.V.", "market": "US" }, + { "symbol": "SMAR", "name": "Smartsheet Inc.", "market": "US" }, + { "symbol": "WORK", "name": "Slack Technologies Inc.", "market": "US" }, + { "symbol": "DOCS", "name": "Doximity Inc.", "market": "US" }, + { "symbol": "BILL", "name": "Bill Holdings Inc.", "market": "US" }, + { "symbol": "U", "name": "Unity Software Inc.", "market": "US" }, + { "symbol": "RBLX", "name": "Roblox Corp.", "market": "US" }, + { "symbol": "COIN", "name": "Coinbase Global Inc.", "market": "US" }, + { "symbol": "HOOD", "name": "Robinhood Markets Inc.", "market": "US" }, + { "symbol": "ABNB", "name": "Airbnb Inc.", "market": "US" }, + { "symbol": "LYFT", "name": "Lyft Inc.", "market": "US" }, + { "symbol": "UBER", "name": "Uber Technologies Inc.", "market": "US" } +] diff --git a/crates/story/src/input_story.rs b/crates/story/src/input_story.rs index 18d3491e..62179fed 100644 --- a/crates/story/src/input_story.rs +++ b/crates/story/src/input_story.rs @@ -270,20 +270,12 @@ impl Render for InputStory { .child( section("Appearance false").max_w_md().child( div() - .border_1() + .border_b_2() .px_6() - .py_5() - .rounded_lg() - .bg(if cx.theme().is_dark() { - yellow_950() - } else { - yellow_50() - }) - .text_color(if cx.theme().is_dark() { - yellow_100() - } else { - yellow_900() - }) + .py_3() + .border_color(cx.theme().border) + .bg(cx.theme().secondary) + .text_color(cx.theme().secondary_foreground) .w_full() .child(TextInput::new(&self.input1).appearance(false)), ), diff --git a/crates/story/src/label_story.rs b/crates/story/src/label_story.rs index d2d06c8e..119a6d89 100644 --- a/crates/story/src/label_story.rs +++ b/crates/story/src/label_story.rs @@ -63,6 +63,12 @@ impl Render for LabelStory { .items_start() .child(Label::new("This is a label")), ) + .child( + section("Label with secondary text") + .max_w_md() + .items_start() + .child(Label::new("Company Address").secondary("(optional)")), + ) .child( section("Alignment").max_w_md().child( v_flex() diff --git a/crates/story/src/otp_input_story.rs b/crates/story/src/otp_input_story.rs index 29acc744..f4459382 100644 --- a/crates/story/src/otp_input_story.rs +++ b/crates/story/src/otp_input_story.rs @@ -138,16 +138,12 @@ impl Render for OtpInputStory { .size_full() .gap_5() .child( - h_flex() - .items_center() - .justify_between() - .child("OTP Input") - .child( - Checkbox::new("otp-mask") - .label("Masked") - .checked(self.otp_masked) - .on_click(cx.listener(Self::toggle_opt_masked)), - ), + h_flex().items_center().child( + Checkbox::new("otp-mask") + .label("Masked") + .checked(self.otp_masked) + .on_click(cx.listener(Self::toggle_opt_masked)), + ), ) .child( section("Normal") diff --git a/crates/story/src/table_story.rs b/crates/story/src/table_story.rs index 6092e7a4..1a9d13dc 100644 --- a/crates/story/src/table_story.rs +++ b/crates/story/src/table_story.rs @@ -1,9 +1,10 @@ use std::{ ops::Range, + sync::LazyLock, time::{self, Duration}, }; -use fake::{Fake, Faker}; +use fake::Fake; use gpui::{ div, prelude::FluentBuilder as _, px, Action, AnyElement, App, AppContext, ClickEvent, Context, Edges, Entity, Focusable, InteractiveElement, IntoElement, ParentElement, Pixels, Render, @@ -12,16 +13,15 @@ use gpui::{ use gpui_component::{ button::Button, checkbox::Checkbox, - green, h_flex, + h_flex, indicator::Indicator, input::{InputEvent, InputState, TextInput}, label::Label, popup_menu::{PopupMenu, PopupMenuExt}, - red, table::{self, ColFixed, ColSort, Table, TableDelegate, TableEvent}, v_flex, ActiveTheme as _, Selectable, Sizable as _, Size, StyleSized as _, }; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; #[derive(Action, Clone, PartialEq, Eq, Deserialize)] #[action(namespace = table_story, no_json)] @@ -31,11 +31,32 @@ struct ChangeSize(Size); #[action(namespace = table_story, no_json)] struct OpenDetail(usize); +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +struct Counter { + symbol: SharedString, + market: SharedString, + name: SharedString, +} + +static ALL_COUNTERS: LazyLock> = + LazyLock::new(|| serde_json::from_str(include_str!("./fixtures/counters.json")).unwrap()); + +impl Counter { + fn random() -> Self { + let len = ALL_COUNTERS.len(); + let ix = rand::random::() % len; + ALL_COUNTERS[ix].clone() + } + + fn symbol_code(&self) -> SharedString { + format!("{}.{}", self.symbol, self.market).into() + } +} + #[derive(Clone, Debug, Default)] struct Stock { id: usize, - symbol: SharedString, - name: SharedString, + counter: Counter, price: f64, change: f64, change_percent: f64, @@ -104,8 +125,7 @@ fn random_stocks(size: usize) -> Vec { (0..size) .map(|id| Stock { id, - symbol: Faker.fake::().into(), - name: Faker.fake::().into(), + counter: Counter::random(), change: (-100.0..100.0).fake(), change_percent: (-1.0..1.0).fake(), volume: (0.0..1000.0).fake(), @@ -195,6 +215,7 @@ impl StockTableDelegate { stocks: random_stocks(size), columns: vec![ Column::new("id", "ID", None), + Column::new("market", "Market", None), Column::new("symbol", "Symbol", Some(ColSort::Default)), Column::new("name", "Name", None), Column::new("price", "Price", Some(ColSort::Default)), @@ -261,11 +282,6 @@ impl StockTableDelegate { } fn render_value_cell(&self, val: f64, cx: &mut Context>) -> AnyElement { - let (fg_scale, bg_scale, opacity) = match cx.theme().mode.is_dark() { - true => (200, 950, 0.3), - false => (600, 50, 0.6), - }; - let this = div() .h_full() .table_cell_size(self.size) @@ -275,11 +291,11 @@ impl StockTableDelegate { let right_num = ((val - val.floor()) * 1000.).floor() as i32; let this = if right_num % 3 == 0 { - this.text_color(red(fg_scale)) - .bg(red(bg_scale).opacity(opacity)) + this.text_color(cx.theme().red) + .bg(cx.theme().red_light.alpha(0.05)) } else if right_num % 3 == 1 { - this.text_color(green(fg_scale)) - .bg(green(bg_scale).opacity(opacity)) + this.text_color(cx.theme().green) + .bg(cx.theme().green_light.alpha(0.05)) } else { this }; @@ -306,13 +322,13 @@ impl TableDelegate for StockTableDelegate { } fn col_width(&self, col_ix: usize, _: &App) -> Pixels { - if col_ix < 10 { - 120.0.into() - } else if col_ix < 20 { - 80.0.into() - } else { - 130.0.into() - } + px(match col_ix { + 0 => 60., + 1 => 60., + 2 => 100., + 3 => 180., + _ => 100., + }) } fn col_padding(&self, col_ix: usize, _: &App) -> Option> { @@ -412,8 +428,18 @@ impl TableDelegate for StockTableDelegate { match col.id.as_ref() { "id" => stock.id.to_string().into_any_element(), - "name" => stock.name.clone().into_any_element(), - "symbol" => stock.symbol.clone().into_any_element(), + "market" => div() + .map(|this| { + if stock.counter.market == "US" { + this.text_color(cx.theme().blue) + } else { + this.text_color(cx.theme().magenta) + } + }) + .child(stock.counter.market.clone()) + .into_any_element(), + "symbol" => stock.counter.symbol_code().into_any_element(), + "name" => stock.counter.name.clone().into_any_element(), "price" => self.render_value_cell(stock.price, cx), "change" => self.render_value_cell(stock.change, cx), "change_percent" => self.render_value_cell(stock.change_percent, cx), @@ -422,45 +448,77 @@ impl TableDelegate for StockTableDelegate { "market_cap" => self.render_value_cell(stock.market_cap, cx), "ttm" => self.render_value_cell(stock.ttm, cx), "five_mins_ranking" => self.render_value_cell(stock.five_mins_ranking, cx), - "th60_days_ranking" => stock.th60_days_ranking.to_string().into_any_element(), + "th60_days_ranking" => stock + .th60_days_ranking + .floor() + .to_string() + .into_any_element(), "year_change_percent" => (stock.year_change_percent * 100.0) + .floor() .to_string() .into_any_element(), "bid" => self.render_value_cell(stock.bid, cx), "bid_volume" => self.render_value_cell(stock.bid_volume, cx), "ask" => self.render_value_cell(stock.ask, cx), "ask_volume" => self.render_value_cell(stock.ask_volume, cx), - "open" => stock.open.to_string().into_any_element(), - "prev_close" => stock.prev_close.to_string().into_any_element(), + "open" => stock.open.floor().to_string().into_any_element(), + "prev_close" => stock.prev_close.floor().to_string().into_any_element(), "high" => self.render_value_cell(stock.high, cx), "low" => self.render_value_cell(stock.low, cx), - "turnover_rate" => (stock.turnover_rate * 100.0).to_string().into_any_element(), - "rise_rate" => (stock.rise_rate * 100.0).to_string().into_any_element(), - "amplitude" => (stock.amplitude * 100.0).to_string().into_any_element(), - "pe_status" => stock.pe_status.to_string().into_any_element(), - "pb_status" => stock.pb_status.to_string().into_any_element(), + "turnover_rate" => (stock.turnover_rate * 100.0) + .floor() + .to_string() + .into_any_element(), + "rise_rate" => (stock.rise_rate * 100.0) + .floor() + .to_string() + .into_any_element(), + "amplitude" => (stock.amplitude * 100.0) + .floor() + .to_string() + .into_any_element(), + "pe_status" => stock.pe_status.floor().to_string().into_any_element(), + "pb_status" => stock.pb_status.floor().to_string().into_any_element(), "volume_ratio" => self.render_value_cell(stock.volume_ratio, cx), "bid_ask_ratio" => self.render_value_cell(stock.bid_ask_ratio, cx), - "latest_pre_close" => stock.latest_pre_close.to_string().into_any_element(), - "latest_post_close" => stock.latest_post_close.to_string().into_any_element(), - "pre_market_cap" => stock.pre_market_cap.to_string().into_any_element(), + "latest_pre_close" => stock + .latest_pre_close + .floor() + .to_string() + .into_any_element(), + "latest_post_close" => stock + .latest_post_close + .floor() + .to_string() + .into_any_element(), + "pre_market_cap" => stock.pre_market_cap.floor().to_string().into_any_element(), "pre_market_percent" => (stock.pre_market_percent * 100.0) + .floor() .to_string() .into_any_element(), - "pre_market_change" => stock.pre_market_change.to_string().into_any_element(), - "post_market_cap" => stock.post_market_cap.to_string().into_any_element(), + "pre_market_change" => stock + .pre_market_change + .floor() + .to_string() + .into_any_element(), + "post_market_cap" => stock.post_market_cap.floor().to_string().into_any_element(), "post_market_percent" => (stock.post_market_percent * 100.0) + .floor() .to_string() .into_any_element(), - "post_market_change" => stock.post_market_change.to_string().into_any_element(), - "float_cap" => stock.float_cap.to_string().into_any_element(), + "post_market_change" => stock + .post_market_change + .floor() + .to_string() + .into_any_element(), + "float_cap" => stock.float_cap.floor().to_string().into_any_element(), "shares" => stock.shares.to_string().into_any_element(), "shares_float" => stock.shares_float.to_string().into_any_element(), - "day_5_ranking" => stock.day_5_ranking.to_string().into_any_element(), - "day_10_ranking" => stock.day_10_ranking.to_string().into_any_element(), - "day_30_ranking" => stock.day_30_ranking.to_string().into_any_element(), - "day_120_ranking" => stock.day_120_ranking.to_string().into_any_element(), - "day_250_ranking" => stock.day_250_ranking.to_string().into_any_element(), + "day_5_ranking" => stock.day_5_ranking.floor().to_string().into_any_element(), + "day_10_ranking" => stock.day_10_ranking.floor().to_string().into_any_element(), + "day_30_ranking" => stock.day_30_ranking.floor().to_string().into_any_element(), + "day_120_ranking" => stock.day_120_ranking.floor().to_string().into_any_element(), + "day_250_ranking" => stock.day_250_ranking.floor().to_string().into_any_element(), _ => "--".to_string().into_any_element(), } } @@ -510,7 +568,7 @@ impl TableDelegate for StockTableDelegate { _ => a.id.cmp(&b.id), }), "symbol" => self.stocks.sort_by(|a, b| match sort { - ColSort::Descending => b.symbol.cmp(&a.symbol), + ColSort::Descending => b.counter.symbol.cmp(&a.counter.symbol), _ => a.id.cmp(&b.id), }), "change" | "change_percent" => self.stocks.sort_by(|a, b| match sort { @@ -931,23 +989,38 @@ impl Render for TableStory { .child( h_flex().items_center().gap_2().child( h_flex() + .w_full() .items_center() .justify_between() - .gap_1() - .child(Label::new("Number of Stocks:")) + .gap_2() .child( h_flex() - .min_w_32() - .child(TextInput::new(&self.num_stocks_input)) - .into_any_element(), + .gap_2() + .flex_1() + .child(Label::new("Number of Stocks:")) + .child( + h_flex() + .min_w_32() + .child(TextInput::new(&self.num_stocks_input).small()) + .into_any_element(), + ) + .when(delegate.loading, |this| { + this.child( + h_flex() + .gap_1() + .child(Indicator::new()) + .child("Loading..."), + ) + }), ) - .when(delegate.loading, |this| { - this.child(h_flex().gap_1().child(Indicator::new()).child("Loading...")) - }) - .child(format!("Total Rows: {}", rows_count)) - .child(format!("Visible Rows: {:?}", delegate.visible_rows)) - .child(format!("Visible Cols: {:?}", delegate.visible_cols)) - .when(delegate.eof, |this| this.child("All data loaded.")), + .child( + h_flex() + .gap_2() + .child(format!("Total Rows: {}", rows_count)) + .child(format!("Visible Rows: {:?}", delegate.visible_rows)) + .child(format!("Visible Cols: {:?}", delegate.visible_cols)) + .when(delegate.eof, |this| this.child("All data loaded.")), + ), ), ) .child(self.table.clone()) diff --git a/crates/ui/src/label.rs b/crates/ui/src/label.rs index fe5c01db..3cfbe4c3 100644 --- a/crates/ui/src/label.rs +++ b/crates/ui/src/label.rs @@ -1,6 +1,6 @@ use gpui::{ - div, rems, App, IntoElement, ParentElement, RenderOnce, SharedString, StyleRefinement, Styled, - Window, + div, rems, App, HighlightStyle, IntoElement, ParentElement, RenderOnce, SharedString, + StyleRefinement, Styled, StyledText, Window, }; use crate::{ActiveTheme, StyledExt}; @@ -11,22 +11,28 @@ const MASKED: &'static str = "•"; pub struct Label { style: StyleRefinement, label: SharedString, - chars_count: usize, + secondary: Option, masked: bool, } impl Label { pub fn new(label: impl Into) -> Self { let label: SharedString = label.into(); - let chars_count = label.chars().count(); Self { style: Default::default(), label, - chars_count, + secondary: None, masked: false, } } + /// Set the secondary text for the label, + /// the secondary text will be displayed after the label text with `muted` color. + pub fn secondary(mut self, secondary: impl Into) -> Self { + self.secondary = Some(secondary.into()); + self + } + pub fn masked(mut self, masked: bool) -> Self { self.masked = masked; self @@ -41,16 +47,30 @@ impl Styled for Label { impl RenderOnce for Label { fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { - let text = if self.masked { - SharedString::from(MASKED.repeat(self.chars_count)) - } else { - self.label + let mut text = match &self.secondary { + Some(secondary) => format!("{} {}", self.label, secondary).into(), + None => self.label.clone(), }; + let chars_count = text.chars().count(); + if self.masked { + text = SharedString::from(MASKED.repeat(chars_count)) + }; + + let mut highlights = vec![(0..self.label.len(), HighlightStyle::default())]; + if self.secondary.is_some() { + highlights.push(( + self.label.len()..text.len(), + HighlightStyle { + color: Some(cx.theme().muted_foreground), + ..Default::default() + }, + )); + } div() .line_height(rems(1.25)) .text_color(cx.theme().foreground) .refine_style(&self.style) - .child(text) + .child(StyledText::new(&text).with_highlights(highlights)) } } diff --git a/crates/ui/src/theme/schema.rs b/crates/ui/src/theme/schema.rs index 64e89877..c52ee52c 100644 --- a/crates/ui/src/theme/schema.rs +++ b/crates/ui/src/theme/schema.rs @@ -456,7 +456,7 @@ impl Theme { apply_color!(danger_active, fallback = self.danger.opacity(0.95)); apply_color!(danger_foreground); apply_color!(danger_hover, fallback = self.danger); - apply_color!(description_list_label, fallback = self.secondary); + apply_color!(description_list_label, fallback = self.border.opacity(0.2)); apply_color!( description_list_label_foreground, fallback = self.secondary_foreground diff --git a/themes/molokai.json b/themes/molokai.json index e6b072b2..86e44563 100644 --- a/themes/molokai.json +++ b/themes/molokai.json @@ -21,7 +21,7 @@ "input.border": "#E4DEDA", "list.active.background": "#E1477411", "list.active.border": "#E14774AA", - "list.even.background": "#E1477499", + "list.even.background": "#E4DEDA33", "muted.background": "#f5f5f5", "muted.foreground": "#767676", "panel.background": "#FEFAF9", @@ -239,7 +239,7 @@ "input.border": "#3b3b3b", "list.active.background": "#f9267211", "list.active.border": "#f9267288", - "list.even.background": "#f9267299", + "list.even.background": "#292c2e", "muted.background": "#232526", "muted.foreground": "#5e5c51", "panel.background": "#1b1d1e",