From 9ab8367c215873515b687b885af2a0c6ae414c9b Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 1 May 2024 20:26:17 +0800 Subject: [PATCH 001/143] refactor: button appearance --- demo/src/app.rs | 14 +- demo/src/components/site_header.rs | 10 +- demo/src/pages/home.rs | 2 +- demo_markdown/docs/button/mod.md | 34 ++-- thaw/src/button/button.css | 99 +++++++++-- thaw/src/button/mod.rs | 51 +++--- thaw/src/calendar/mod.rs | 6 +- thaw/src/config_provider/config-provider.css | 8 + thaw/src/config_provider/mod.rs | 165 +++++++++++++++++++ thaw/src/date_picker/panel/date_panel.rs | 16 +- thaw/src/date_picker/panel/month_panel.rs | 8 +- thaw/src/date_picker/panel/year_panel.rs | 6 +- thaw/src/global_style/mod.rs | 3 - thaw/src/input_number/mod.rs | 6 +- thaw/src/lib.rs | 2 + thaw/src/theme/color.rs | 0 thaw/src/theme/common.rs | 128 +++++++++++++- thaw/src/time_picker/mod.rs | 4 +- 18 files changed, 460 insertions(+), 102 deletions(-) create mode 100644 thaw/src/config_provider/config-provider.css create mode 100644 thaw/src/config_provider/mod.rs create mode 100644 thaw/src/theme/color.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index a243770..735822a 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -115,11 +115,13 @@ fn TheProvider(children: Children) -> impl IntoView { let theme = create_rw_signal(theme); view! { - - - - {children()} - - + + + + + {children()} + + + } } diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index 5777aef..78593e7 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -152,7 +152,7 @@ pub fn SiteHeader() -> impl IntoView { - - - - + + + + } ``` @@ -107,17 +107,17 @@ view! { ```rust demo view! { - - - - } @@ -152,14 +152,14 @@ view! { view! { - - - + + + - - - + + + } @@ -171,7 +171,7 @@ view! { | --- | --- | --- | --- | | class | `OptionalProp>` | `Default::default()` | Additional classes for the button element. | | style | `Option>` | `Default::default()` | Button's style. | -| variant | `MaybeSignal` | `ButtonVariant::Primary` | Button's variant. | +| variant | `MaybeSignal` | `ButtonAppearance::Primary` | Button's variant. | | color | `MaybeSignal` | `ButtonColor::Primary` | Button's color. | | block | `MaybeSignal` | `false` | Whether the button is displayed as block. | | round | `MaybeSignal` | `false` | Whether the button shows rounded corners. | diff --git a/thaw/src/button/button.css b/thaw/src/button/button.css index ad249c1..9f6fab3 100644 --- a/thaw/src/button/button.css +++ b/thaw/src/button/button.css @@ -1,24 +1,93 @@ .thaw-button { - height: var(--thaw-height); - padding: var(--thaw-padding); - font-size: var(--thaw-font-size); - background-color: var(--thaw-background-color); - color: var(--thaw-font-color); - border: 1px solid var(--thaw-border-color); - border-radius: 5px; - position: relative; display: inline-flex; align-items: center; justify-content: center; - user-select: none; + min-width: 96px; + box-sizing: border-box; + + padding: 5px var(--spacingHorizontalM); + + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + font-weight: var(--fontWeightSemibold); + line-height: var(--lineHeightBase300); + + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); + + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + border-radius: var(--borderRadiusMedium); + + transition-duration: var(--durationFaster); + transition-property: background, border, color; + transition-timing-function: var(--curveEasyEase); } -.thaw-button:hover:not(.thaw-button--disabled, .thaw-button--outlined) { - border-color: var(--thaw-border-color-hover); - background-color: var(--thaw-background-color-hover); +.thaw-button:hover { + background-color: var(--colorNeutralBackground1Hover); + color: var(--colorNeutralForeground1Hover); + border-color: var(--colorNeutralStroke1Hover); cursor: pointer; +} - transition: all 0.3s; +.thaw-button:hover:active { + background-color: var(--colorNeutralBackground1Pressed); + color: var(--colorNeutralForeground1Pressed); + border-color: var(--colorNeutralStroke1Pressed); +} + +.thaw-button--primary { + background-color: var(--colorBrandBackground); + color: var(--colorNeutralForegroundOnBrand); + border-color: transparent; +} + +.thaw-button--primary:hover { + background-color: var(--colorBrandBackgroundHover); + color: var(--colorNeutralForegroundOnBrand); + border-color: transparent; +} + +.thaw-button--primary:hover:active { + background-color: var(--colorBrandBackgroundPressed); + color: var(--colorNeutralForegroundOnBrand); + border-color: transparent; +} + +.thaw-button--subtle { + background-color: var(--colorSubtleBackground); + color: var(--colorNeutralForeground2); + border-color: transparent; +} + +.thaw-button--subtle:hover { + background-color: var(--colorSubtleBackgroundHover); + color: var(--colorNeutralForeground2Hover); + border-color: transparent; +} + +.thaw-button--subtle:hover:active { + background-color: var(--colorSubtleBackgroundPressed); + color: var(--colorNeutralForeground2Pressed); + border-color: transparent; +} + +.thaw-button--transparent { + background-color: var(--colorTransparentBackground); + color: var(--colorNeutralForeground2); + border-color: transparent; +} + +.thaw-button--transparent:hover { + background-color: var(--colorTransparentBackgroundHover); + color: var(--colorNeutralForeground2BrandHover); + border-color: transparent; +} + +.thaw-button--transparent:hover:active { + background-color: var(--colorTransparentBackgroundPressed); + color: var(--colorNeutralForeground2BrandPressed); + border-color: transparent; } .thaw-button--block { @@ -36,11 +105,11 @@ cursor: not-allowed; } -.thaw-button:active:not(.thaw-button--disabled) { +/* .thaw-button:active:not(.thaw-button--disabled) { transition: all 0.3s; border-color: var(--thaw-border-color-hover); background-color: var(--thaw-background-color-active); -} +} */ .thaw-button--outlined { background-color: transparent; diff --git a/thaw/src/button/mod.rs b/thaw/src/button/mod.rs index ff4cbb5..ef3e674 100644 --- a/thaw/src/button/mod.rs +++ b/thaw/src/button/mod.rs @@ -10,12 +10,23 @@ use thaw_components::{OptionComp, Wave, WaveRef}; use thaw_utils::{class_list, mount_style, ComponentRef, OptionalMaybeSignal, OptionalProp}; #[derive(Default, PartialEq, Clone, Copy)] -pub enum ButtonVariant { +pub enum ButtonAppearance { #[default] + Secondary, Primary, - Outlined, - Text, - Link, + Subtle, + Transparent, +} + +impl ButtonAppearance { + fn as_str(&self) -> &str { + match self { + ButtonAppearance::Secondary => "secondary", + ButtonAppearance::Primary => "primary", + ButtonAppearance::Subtle => "subtle", + ButtonAppearance::Transparent => "transparent", + } + } } #[derive(Default, Clone)] @@ -97,7 +108,7 @@ impl ButtonSize { pub fn Button( #[prop(optional, into)] style: Option>, #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] variant: MaybeSignal, + #[prop(optional, into)] variant: MaybeSignal, #[prop(optional, into)] color: MaybeSignal, #[prop(optional, into)] size: MaybeSignal, #[prop(optional, into)] block: MaybeSignal, @@ -132,7 +143,8 @@ pub fn Button( )); match variant.get() { - ButtonVariant::Primary => { + ButtonAppearance::Secondary => {} + ButtonAppearance::Primary => { let bg_color_hover = color.get().theme_color_hover(theme); let bg_color_active = color.get().theme_color_active(theme); css_vars.push_str(&format!("--thaw-background-color: {bg_color};")); @@ -154,20 +166,7 @@ pub fn Button( theme.button.color_border_disabled )); } - ButtonVariant::Outlined => { - css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};")); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.button.border_color_outlined - )); - css_vars.push_str(&format!("--thaw-border-color-hover: {bg_color};")); - css_vars.push_str(&format!("--thaw-ripple-color: {bg_color};")); - css_vars.push_str(&format!( - "--thaw-border-color-disabled: {};", - theme.button.color_border_disabled - )); - } - ButtonVariant::Text => { + ButtonAppearance::Subtle => { css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};")); css_vars.push_str(&format!( "--thaw-background-color-hover: {};", @@ -179,7 +178,7 @@ pub fn Button( )); css_vars.push_str("--thaw-ripple-color: #0000;"); } - ButtonVariant::Link => { + ButtonAppearance::Transparent => { css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};")); css_vars.push_str("--thaw-ripple-color: #0000;"); } @@ -222,13 +221,11 @@ pub fn Button( view! { diff --git a/thaw/src/date_picker/panel/month_panel.rs b/thaw/src/date_picker/panel/month_panel.rs index d54ca7e..4dfe415 100644 --- a/thaw/src/date_picker/panel/month_panel.rs +++ b/thaw/src/date_picker/panel/month_panel.rs @@ -1,5 +1,5 @@ use super::PanelVariant; -use crate::{Button, ButtonSize, ButtonVariant}; +use crate::{Button, ButtonSize, ButtonAppearance}; use chrono::{Datelike, Month, Months, NaiveDate}; use leptos::*; @@ -23,14 +23,14 @@ pub fn MonthPanel(
- diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 396ce71..1854676 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -12,6 +12,7 @@ mod checkbox; mod code; mod collapse; mod color_picker; +mod config_provider; mod date_picker; mod divider; mod drawer; @@ -59,6 +60,7 @@ pub use checkbox::*; pub use code::*; pub use collapse::*; pub use color_picker::*; +pub use config_provider::*; pub use date_picker::*; pub use divider::*; pub use drawer::*; diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs new file mode 100644 index 0000000..e69de29 diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index a10a92a..7cde7de 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -2,7 +2,7 @@ use super::ThemeMethod; #[derive(Clone)] pub struct CommonTheme { - pub font_family: String, + pub font_family_base: String, pub font_color: String, pub background_color: String, pub border_color: String, @@ -21,6 +21,48 @@ pub struct CommonTheme { pub color_error_hover: String, pub color_error_active: String, + pub color_neutral_background_1: String, + pub color_neutral_background_1_hover: String, + pub color_neutral_background_1_pressed: String, + pub color_neutral_foreground_1: String, + pub color_neutral_foreground_1_hover: String, + pub color_neutral_foreground_1_pressed: String, + pub color_neutral_foreground_2: String, + pub color_neutral_foreground_2_hover: String, + pub color_neutral_foreground_2_pressed: String, + pub color_neutral_foreground_2_brand_hover: String, + pub color_neutral_foreground_2_brand_pressed: String, + pub color_neutral_foreground_on_brand: String, + pub color_neutral_stroke_1: String, + pub color_neutral_stroke_1_hover: String, + pub color_neutral_stroke_1_pressed: String, + pub color_brand_background: String, + pub color_brand_background_hover: String, + pub color_brand_background_pressed: String, + pub color_subtle_background: String, + pub color_subtle_background_hover: String, + pub color_subtle_background_pressed: String, + pub color_transparent_background: String, + pub color_transparent_background_hover: String, + pub color_transparent_background_pressed: String, + + pub font_size_base_300: String, + + pub line_height_base300: String, + + pub font_weight_regular: String, + pub font_weight_semibold: String, + pub font_weight_bold: String, + + pub stroke_width_thin: String, + + pub border_radius_medium: String, + + pub spacing_horizontal_m: String, + + pub duration_faster: String, + pub curve_easy_ease: String, + pub font_size: String, pub font_size_tiny: String, pub font_size_small: String, @@ -41,14 +83,13 @@ pub struct CommonTheme { pub border_radius: String, pub border_radius_small: String, - pub border_radius_medium: String, pub border_radius_large: String, } impl CommonTheme { fn common() -> Self { Self { - font_family: r#"Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", Segoe UI Symbol, "Noto Color Emoji""#.into(), + font_family_base: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif".into(), font_color: "".into(), background_color: "".into(), border_color: "".into(), @@ -66,6 +107,48 @@ impl CommonTheme { color_error_hover: "".into(), color_error_active: "".into(), + color_neutral_background_1: "".into(), + color_neutral_background_1_hover: "".into(), + color_neutral_background_1_pressed: "".into(), + color_neutral_foreground_1: "".into(), + color_neutral_foreground_1_hover: "".into(), + color_neutral_foreground_1_pressed: "".into(), + color_neutral_foreground_2: "".into(), + color_neutral_foreground_2_hover: "".into(), + color_neutral_foreground_2_pressed: "".into(), + color_neutral_foreground_2_brand_hover: "".into(), + color_neutral_foreground_2_brand_pressed: "".into(), + color_neutral_foreground_on_brand: "#fff".into(), + color_neutral_stroke_1: "".into(), + color_neutral_stroke_1_hover: "".into(), + color_neutral_stroke_1_pressed: "".into(), + color_brand_background: "".into(), + color_brand_background_hover: "".into(), + color_brand_background_pressed: "".into(), + color_subtle_background: "transparent".into(), + color_subtle_background_hover: "".into(), + color_subtle_background_pressed: "".into(), + color_transparent_background: "transparent".into(), + color_transparent_background_hover: "transparent".into(), + color_transparent_background_pressed: "transparent".into(), + + font_size_base_300: "14px".into(), + + line_height_base300: "20px".into(), + + font_weight_regular: "400".into(), + font_weight_semibold: "600".into(), + font_weight_bold: "700".into(), + + stroke_width_thin: "1px".into(), + + border_radius_medium: "4px".into(), + + spacing_horizontal_m: "12px".into(), + + duration_faster: "100ms".into(), + curve_easy_ease: "cubic-bezier(0.33,0,0.67,1)".into(), + font_size: "14px".into(), font_size_tiny: "12px".into(), font_size_small: "14px".into(), @@ -86,7 +169,6 @@ impl CommonTheme { border_radius: "3px".into(), border_radius_small: "2px".into(), - border_radius_medium: "4px".into(), border_radius_large: "8px".into(), } } @@ -111,6 +193,25 @@ impl ThemeMethod for CommonTheme { color_error_hover: "#de576d".into(), color_error_active: "#ab1f3f".into(), border_color: "#e5e8eb".into(), + color_neutral_background_1: "#fff".into(), + color_neutral_background_1_hover: "#f5f5f5".into(), + color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_foreground_1: "#242424".into(), + color_neutral_foreground_1_hover: "#242424".into(), + color_neutral_foreground_1_pressed: "#242424".into(), + color_neutral_foreground_2: "#424242".into(), + color_neutral_foreground_2_hover: "#242424".into(), + color_neutral_foreground_2_pressed: "#242424".into(), + color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), + color_neutral_foreground_2_brand_pressed: "#115ea3".into(), + color_neutral_stroke_1: "#d1d1d1".into(), + color_neutral_stroke_1_hover: "#c7c7c7".into(), + color_neutral_stroke_1_pressed: "#b3b3b3".into(), + color_brand_background: "#0f6cbd".into(), + color_brand_background_hover: "#115ea3".into(), + color_brand_background_pressed: "#0c3b5e".into(), + color_subtle_background_hover: "#f5f5f5".into(), + color_subtle_background_pressed: "#e0e0e0".into(), ..CommonTheme::common() } } @@ -134,6 +235,25 @@ impl ThemeMethod for CommonTheme { color_error_hover: "#de576d".into(), color_error_active: "#e57272".into(), border_color: "#1f2537".into(), + color_neutral_background_1: "#292929".into(), + color_neutral_background_1_hover: "#3d3d3d".into(), + color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_foreground_1: "#fff".into(), + color_neutral_foreground_1_hover: "#fff".into(), + color_neutral_foreground_1_pressed: "#fff".into(), + color_neutral_foreground_2: "#d6d6d6".into(), + color_neutral_foreground_2_hover: "#fff".into(), + color_neutral_foreground_2_pressed: "#fff".into(), + color_neutral_foreground_2_brand_hover: "#479ef5".into(), + color_neutral_foreground_2_brand_pressed: "#2886de".into(), + color_neutral_stroke_1: "#666666".into(), + color_neutral_stroke_1_hover: "#757575".into(), + color_neutral_stroke_1_pressed: "#6b6b6b".into(), + color_brand_background: "#115ea3".into(), + color_brand_background_hover: "#0f6cbd".into(), + color_brand_background_pressed: "#0c3b5e".into(), + color_subtle_background_hover: "#383838".into(), + color_subtle_background_pressed: "#2e2e2e".into(), ..CommonTheme::common() } } diff --git a/thaw/src/time_picker/mod.rs b/thaw/src/time_picker/mod.rs index 31d1319..027a7bf 100644 --- a/thaw/src/time_picker/mod.rs +++ b/thaw/src/time_picker/mod.rs @@ -3,7 +3,7 @@ mod theme; pub use theme::TimePickerTheme; use crate::{ - use_theme, Button, ButtonSize, ButtonVariant, Icon, Input, InputSuffix, Scrollbar, + use_theme, Button, ButtonSize, ButtonAppearance, Icon, Input, InputSuffix, Scrollbar, ScrollbarRef, SignalWatch, Theme, }; use chrono::{Local, NaiveTime, Timelike}; @@ -286,7 +286,7 @@ fn Panel(
diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 5162a46..408f0c7 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -2,9 +2,12 @@ use thaw_macro::WriteCSSVars; #[derive(Clone, WriteCSSVars)] pub struct ColorTheme { + pub color_neutral_background_disabled: String, pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, pub color_neutral_background_1_pressed: String, + + pub color_neutral_foreground_disabled: String, pub color_neutral_foreground_1: String, pub color_neutral_foreground_1_hover: String, pub color_neutral_foreground_1_pressed: String, @@ -14,6 +17,8 @@ pub struct ColorTheme { pub color_neutral_foreground_2_brand_hover: String, pub color_neutral_foreground_2_brand_pressed: String, pub color_neutral_foreground_on_brand: String, + + pub color_neutral_stroke_disabled: String, pub color_neutral_stroke_1: String, pub color_neutral_stroke_1_hover: String, pub color_neutral_stroke_1_pressed: String, @@ -31,9 +36,11 @@ pub struct ColorTheme { impl ColorTheme { pub fn light() -> Self { Self { + color_neutral_background_disabled: "#f0f0f0".into(), color_neutral_background_1: "#fff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_foreground_disabled: "#bdbdbd".into(), color_neutral_foreground_1: "#242424".into(), color_neutral_foreground_1_hover: "#242424".into(), color_neutral_foreground_1_pressed: "#242424".into(), @@ -43,6 +50,8 @@ impl ColorTheme { color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), color_neutral_foreground_2_brand_pressed: "#115ea3".into(), color_neutral_foreground_on_brand: "#fff".into(), + + color_neutral_stroke_disabled: "#e0e0e0".into(), color_neutral_stroke_1: "#d1d1d1".into(), color_neutral_stroke_1_hover: "#c7c7c7".into(), color_neutral_stroke_1_pressed: "#b3b3b3".into(), @@ -60,9 +69,11 @@ impl ColorTheme { pub fn dark() -> Self { Self { + color_neutral_background_disabled: "#141414".into(), color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_foreground_disabled: "#5c5c5c".into(), color_neutral_foreground_1: "#fff".into(), color_neutral_foreground_1_hover: "#fff".into(), color_neutral_foreground_1_pressed: "#fff".into(), @@ -72,6 +83,8 @@ impl ColorTheme { color_neutral_foreground_2_brand_hover: "#479ef5".into(), color_neutral_foreground_2_brand_pressed: "#2886de".into(), color_neutral_foreground_on_brand: "#fff".into(), + + color_neutral_stroke_disabled: "#424242".into(), color_neutral_stroke_1: "#666666".into(), color_neutral_stroke_1_hover: "#757575".into(), color_neutral_stroke_1_pressed: "#6b6b6b".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 6aa459d..51127dd 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -20,9 +20,13 @@ pub struct CommonTheme { pub color_error_hover: String, pub color_error_active: String, + pub font_size_base_200: String, pub font_size_base_300: String, + pub font_size_base_400: String, - pub line_height_base300: String, + pub line_height_base_200: String, + pub line_height_base_300: String, + pub line_height_base_400: String, pub font_weight_regular: String, pub font_weight_semibold: String, @@ -35,7 +39,9 @@ pub struct CommonTheme { pub border_radius_circular: String, pub spacing_horizontal_s_nudge: String, + pub spacing_horizontal_s: String, pub spacing_horizontal_m: String, + pub spacing_horizontal_l: String, pub duration_faster: String, pub curve_easy_ease: String, @@ -69,9 +75,13 @@ impl CommonTheme { color_error_hover: "".into(), color_error_active: "".into(), + font_size_base_200: "12px".into(), font_size_base_300: "14px".into(), + font_size_base_400: "16px".into(), - line_height_base300: "20px".into(), + line_height_base_200: "16px".into(), + line_height_base_300: "20px".into(), + line_height_base_400: "22px".into(), font_weight_regular: "400".into(), font_weight_semibold: "600".into(), @@ -84,7 +94,9 @@ impl CommonTheme { border_radius_circular: "10000px".into(), spacing_horizontal_s_nudge: "6px".into(), + spacing_horizontal_s: "8px".into(), spacing_horizontal_m: "12px".into(), + spacing_horizontal_l: "16px".into(), duration_faster: "100ms".into(), curve_easy_ease: "cubic-bezier(0.33,0,0.67,1)".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 1bf8d54..e270590 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -1,16 +1,16 @@ -mod common; mod color; +mod common; use self::common::CommonTheme; -pub use color::ColorTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, AvatarTheme, BackTopTheme, BreadcrumbTheme, - ButtonTheme, CalendarTheme, CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, - MenuTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, - SkeletionTheme, SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, - TypographyTheme, UploadTheme, + CalendarTheme, CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, + MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, + SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme, + UploadTheme, }; +pub use color::ColorTheme; use leptos::*; pub trait ThemeMethod { @@ -23,7 +23,6 @@ pub struct Theme { pub name: String, pub common: CommonTheme, pub color: ColorTheme, - pub button: ButtonTheme, pub input: InputTheme, pub menu: MenuTheme, pub table: TableTheme, @@ -60,7 +59,6 @@ impl Theme { name: "light".into(), common: CommonTheme::light(), color: ColorTheme::light(), - button: ButtonTheme::light(), input: InputTheme::light(), menu: MenuTheme::light(), table: TableTheme::light(), @@ -96,7 +94,6 @@ impl Theme { name: "dark".into(), common: CommonTheme::dark(), color: ColorTheme::dark(), - button: ButtonTheme::dark(), input: InputTheme::dark(), menu: MenuTheme::dark(), table: TableTheme::dark(), diff --git a/thaw/src/time_picker/mod.rs b/thaw/src/time_picker/mod.rs index 027a7bf..51009ff 100644 --- a/thaw/src/time_picker/mod.rs +++ b/thaw/src/time_picker/mod.rs @@ -286,10 +286,10 @@ fn Panel( diff --git a/thaw_utils/src/class_list.rs b/thaw_utils/src/class_list.rs index 567beac..773d3f8 100644 --- a/thaw_utils/src/class_list.rs +++ b/thaw_utils/src/class_list.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "ssr"))] use leptos::create_render_effect; -use leptos::{Attribute, IntoAttribute, Oco, RwSignal, SignalUpdate, SignalWith}; +use leptos::{Attribute, IntoAttribute, Memo, Oco, RwSignal, SignalGet, SignalUpdate, SignalWith}; use std::{collections::HashSet, rc::Rc}; pub struct ClassList(RwSignal>>); @@ -163,6 +163,12 @@ where } } +impl IntoClass for (&'static str, Memo) { + fn into_class(self) -> Class { + Class::Fn(self.0.into(), Box::new(move || self.1.get())) + } +} + impl IntoClass for (String, T) where T: Fn() -> bool + 'static, From cad7d0469130071ced1cc3300483eb7eedeb27a5 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 8 May 2024 10:10:48 +0800 Subject: [PATCH 005/143] refactor: remove GlobalStyle --- demo/src/app.rs | 1 - demo_markdown/docs/theme/mod.md | 15 ------ thaw/src/config_provider/mod.rs | 81 ++++++++++++++------------------- thaw/src/global_style/mod.rs | 24 ---------- thaw/src/input/mod.rs | 4 +- thaw/src/lib.rs | 2 - 6 files changed, 35 insertions(+), 92 deletions(-) delete mode 100644 thaw/src/global_style/mod.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 735822a..35c4974 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -117,7 +117,6 @@ fn TheProvider(children: Children) -> impl IntoView { view! { - {children()} diff --git a/demo_markdown/docs/theme/mod.md b/demo_markdown/docs/theme/mod.md index 20b0a7e..c6239c0 100644 --- a/demo_markdown/docs/theme/mod.md +++ b/demo_markdown/docs/theme/mod.md @@ -17,21 +17,6 @@ view! { } ``` -### GlobalStyle - -You can use GlobalStyle to sync common global style to the body element. - -```rust -let theme = create_rw_signal(Theme::light()); - -view! { - - - "..." - -} -``` - ### Customize Theme ```rust demo diff --git a/thaw/src/config_provider/mod.rs b/thaw/src/config_provider/mod.rs index e2e66cb..2f1086d 100644 --- a/thaw/src/config_provider/mod.rs +++ b/thaw/src/config_provider/mod.rs @@ -4,7 +4,12 @@ use thaw_utils::mount_style; #[component] pub fn ConfigProvider( - #[prop(optional, into)] theme: Option>, + /// Sets the theme used in a scope. + #[prop(optional, into)] + theme: Option>, + /// Sets the direction of text & generated styles. + #[prop(optional, into)] + dir: RwSignal>, children: Children, ) -> impl IntoView { mount_style("config-provider", include_str!("./config-provider.css")); @@ -13,62 +18,24 @@ pub fn ConfigProvider( let css_vars = Memo::new(move |_| { let mut css_vars = String::new(); theme.with(|theme| { - // css_vars.push_str(&format!( - // "--fontFamilyBase: {};", - // theme.common.font_family_base - // )); - // css_vars.push_str(&format!( - // "--fontSizeBase300: {};", - // theme.common.font_size_base_300 - // )); - // css_vars.push_str(&format!( - // "--lineHeightBase300: {};", - // theme.common.line_height_base300, - // )); - // css_vars.push_str(&format!( - // "--fontWeightRegular: {};", - // theme.common.font_weight_regular - // )); - // css_vars.push_str(&format!( - // "--fontWeightSemibold: {};", - // theme.common.font_weight_semibold - // )); - // css_vars.push_str(&format!( - // "--fontWeightBold: {};", - // theme.common.font_weight_bold - // )); - // css_vars.push_str(&format!( - // "--strokeWidthThin: {};", - // theme.common.stroke_width_thin, - // )); - // css_vars.push_str(&format!( - // "--borderRadiusMedium: {};", - // theme.common.border_radius_medium - // )); - // css_vars.push_str(&format!( - // "--spacingHorizontalM: {};", - // theme.common.spacing_horizontal_m - // )); - - // css_vars.push_str(&format!( - // "--durationFaster: {};", - // theme.common.duration_faster - // )); - // css_vars.push_str(&format!( - // "--curveEasyEase: {};", - // theme.common.curve_easy_ease - // )); theme.common.write_css_vars(&mut css_vars); theme.color.write_css_vars(&mut css_vars); }); css_vars }); - let config_injection = ConfigInjection { theme }; + let config_injection = ConfigInjection { + theme, + dir: dir.clone(), + }; view! { -
+
{children()}
@@ -78,4 +45,22 @@ pub fn ConfigProvider( #[derive(Clone)] pub struct ConfigInjection { theme: RwSignal, + dir: RwSignal>, +} + +#[derive(Clone)] +pub enum ConfigDirection { + Ltr, + Rtl, + Auto, +} + +impl ConfigDirection { + pub fn as_str(&self) -> &'static str { + match self { + ConfigDirection::Ltr => "ltr", + ConfigDirection::Rtl => "rtl", + ConfigDirection::Auto => "auto", + } + } } diff --git a/thaw/src/global_style/mod.rs b/thaw/src/global_style/mod.rs deleted file mode 100644 index fad8395..0000000 --- a/thaw/src/global_style/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::{use_theme, Theme}; -use leptos::*; - -#[component] -pub fn GlobalStyle() -> impl IntoView { - let theme = use_theme(Theme::light); - create_effect(move |_| { - theme.with(|theme| { - if let Some(body) = document().body() { - // _ = body - // .style() - // .set_property("background-color", &theme.common.background_color); - // _ = body.style().set_property("color", &theme.common.font_color); - // _ = body - // .style() - // .set_property("font-size", &theme.common.font_size); - _ = body - .style() - .set_property("color-scheme", &theme.common.color_scheme); - _ = body.style().set_property("margin", "0"); - } - }); - }); -} diff --git a/thaw/src/input/mod.rs b/thaw/src/input/mod.rs index 0403f39..b961e13 100644 --- a/thaw/src/input/mod.rs +++ b/thaw/src/input/mod.rs @@ -164,7 +164,7 @@ pub fn Input( } view! { -
+ } } diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 1854676..c083318 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -16,7 +16,6 @@ mod config_provider; mod date_picker; mod divider; mod drawer; -mod global_style; mod grid; mod icon; mod image; @@ -64,7 +63,6 @@ pub use config_provider::*; pub use date_picker::*; pub use divider::*; pub use drawer::*; -pub use global_style::*; pub use grid::*; pub use icon::*; pub use image::*; From ed425b90f0256f361866d8495141be83c6ccb98e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 9 May 2024 23:28:08 +0800 Subject: [PATCH 006/143] feat: input style --- thaw/src/input/input.css | 85 +++++++++++++++++++++++++++++++--------- thaw/src/theme/color.rs | 12 ++++++ thaw/src/theme/common.rs | 4 ++ 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/thaw/src/input/input.css b/thaw/src/input/input.css index 64e8539..d45f1c7 100644 --- a/thaw/src/input/input.css +++ b/thaw/src/input/input.css @@ -1,17 +1,77 @@ .thaw-input { display: inline-flex; - width: 100%; + align-items: center; + flex-wrap: nowrap; + position: relative; box-sizing: border-box; - padding: 0 10px; - background-color: var(--thaw-background-color); - font-size: 14px; - color: var(--thaw-font-color); - border: 1px solid var(--thaw-border-color); - border-radius: var(--thaw-border-radius); + min-height: 32px; + + background-color: var(--colorNeutralBackground1); + + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + font-weight: var(--fontWeightRegular); + line-height: var(--lineHeightBase300); + + border: 1px solid var(--colorNeutralStroke1); + border-bottom-color: var(--colorNeutralStrokeAccessible); + border-radius: var(--borderRadiusMedium); + cursor: text; transition: all 0.3s; } +.thaw-input:hover { + border-color: var(--colorNeutralStroke1Hover); + border-bottom-color: var(--colorNeutralStrokeAccessibleHover); +} + +.thaw-input:active .thaw-input:focus-within { + border-color: var(--colorNeutralStroke1Pressed); + border-bottom-color: var(--colorNeutralStrokeAccessiblePressed); +} + +.thaw-input::after { + box-sizing: border-box; + content: ""; + position: absolute; + left: -1px; + bottom: -1px; + right: -1px; + height: max(2px, var(--borderRadiusMedium)); + border-bottom-left-radius: var(--borderRadiusMedium); + border-bottom-right-radius: var(--borderRadiusMedium); + border-bottom: 2px solid var(--colorCompoundBrandStroke); + clip-path: inset(calc(100% - 2px) 0px 0px); + transform: scaleX(0); + transition-property: transform; + transition-duration: var(--durationUltraFast); + transition-delay: var(--curveAccelerateMid); +} + +.thaw-input:focus-within::after { + transform: scaleX(1); + transition-property: transform; + transition-duration: var(--durationNormal); + transition-delay: var(--curveDecelerateMid); +} + +.thaw-input__input-el { + align-self: stretch; + box-sizing: border-box; + flex-grow: 1; + min-width: 0px; + border-style: none; + padding: 0 var(--spacingHorizontalM); + color: var(--colorNeutralForeground1); + background-color: transparent; + outline-style: none; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: inherit; +} + .thaw-input--focus, .thaw-input:hover:not(.thaw-input--disabled, .thaw-input--invalid) { border-color: var(--thaw-border-color-hover); @@ -36,17 +96,6 @@ box-shadow: 0 0 0 2px var(--thaw-box-shadow-color-invalid); } -.thaw-input__input-el { - width: 100%; - height: 30px; - background-color: transparent !important; - color: var(--thaw-font-color); - line-height: 30px; - font-size: inherit; - border: none; - outline: none; -} - .thaw-input__input-el::placeholder { color: var(--thaw-placeholder-color); } diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 408f0c7..3de796f 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -22,6 +22,10 @@ pub struct ColorTheme { pub color_neutral_stroke_1: String, pub color_neutral_stroke_1_hover: String, pub color_neutral_stroke_1_pressed: String, + pub color_neutral_stroke_accessible: String, + + pub color_compound_brand_stroke: String, + pub color_brand_background: String, pub color_brand_background_hover: String, pub color_brand_background_pressed: String, @@ -55,6 +59,10 @@ impl ColorTheme { color_neutral_stroke_1: "#d1d1d1".into(), color_neutral_stroke_1_hover: "#c7c7c7".into(), color_neutral_stroke_1_pressed: "#b3b3b3".into(), + color_neutral_stroke_accessible: "#616161".into(), + + color_compound_brand_stroke: "#0f6cbd".into(), + color_brand_background: "#0f6cbd".into(), color_brand_background_hover: "#115ea3".into(), color_brand_background_pressed: "#0c3b5e".into(), @@ -88,6 +96,10 @@ impl ColorTheme { color_neutral_stroke_1: "#666666".into(), color_neutral_stroke_1_hover: "#757575".into(), color_neutral_stroke_1_pressed: "#6b6b6b".into(), + color_neutral_stroke_accessible: "#adadad".into(), + + color_compound_brand_stroke: "#479ef5".into(), + color_brand_background: "#115ea3".into(), color_brand_background_hover: "#0f6cbd".into(), color_brand_background_pressed: "#0c3b5e".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 51127dd..9762af6 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -43,7 +43,9 @@ pub struct CommonTheme { pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, + pub duration_ultra_fast: String, pub duration_faster: String, + pub curve_accelerate_mid: String, pub curve_easy_ease: String, pub height_tiny: String, @@ -98,7 +100,9 @@ impl CommonTheme { spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), + duration_ultra_fast: "50ms".into(), duration_faster: "100ms".into(), + curve_accelerate_mid: "cubic-bezier(1,0,1,1)".into(), curve_easy_ease: "cubic-bezier(0.33,0,0.67,1)".into(), height_tiny: "22px".into(), From 824ca9c4b1fb1a57e6634fb50d12a9cb5a8e6d6e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 10 May 2024 15:47:01 +0800 Subject: [PATCH 007/143] refactor: input --- demo_markdown/docs/input/mod.md | 59 +++++++++++++--------- thaw/src/input/input.css | 89 +++++++++++++++++++-------------- thaw/src/input/mod.rs | 55 +++----------------- thaw/src/theme/color.rs | 9 ++++ thaw/src/theme/common.rs | 8 +++ thaw_utils/src/class_list.rs | 10 ++++ 6 files changed, 120 insertions(+), 110 deletions(-) diff --git a/demo_markdown/docs/input/mod.md b/demo_markdown/docs/input/mod.md index 285ecbf..2115557 100644 --- a/demo_markdown/docs/input/mod.md +++ b/demo_markdown/docs/input/mod.md @@ -1,7 +1,7 @@ # Input ```rust demo -let value = create_rw_signal(String::from("o")); +let value = RwSignal::new(String::from("o")); view! { @@ -12,10 +12,35 @@ view! { } ``` +## Prefix & Suffix + +```rust demo +let value = RwSignal::new(String::from("o")); + +view! { + + + + + + + + + + + + + "$" + ".00" + + +} +``` + ### Disabled ```rust demo -let value = create_rw_signal(String::from("o")); +let value = RwSignal::new(String::from("o")); view! { @@ -25,6 +50,14 @@ view! { } ``` +### Placeholder + +```rust demo +view! { + +} +``` + ### Invalid ```rust demo @@ -78,29 +111,7 @@ view! { } ``` -## Prefix & Suffix -```rust demo -let value = create_rw_signal(String::from("o")); - -view! { - - - - - - - - "$" - - - - - - - -} -``` ### Input Props diff --git a/thaw/src/input/input.css b/thaw/src/input/input.css index d45f1c7..ec9adca 100644 --- a/thaw/src/input/input.css +++ b/thaw/src/input/input.css @@ -16,9 +16,6 @@ border: 1px solid var(--colorNeutralStroke1); border-bottom-color: var(--colorNeutralStrokeAccessible); border-radius: var(--borderRadiusMedium); - - cursor: text; - transition: all 0.3s; } .thaw-input:hover { @@ -26,7 +23,12 @@ border-bottom-color: var(--colorNeutralStrokeAccessibleHover); } -.thaw-input:active .thaw-input:focus-within { +.thaw-input:focus-within { + outline: transparent solid 2px; +} + +.thaw-input:active, +.thaw-input:focus-within { border-color: var(--colorNeutralStroke1Pressed); border-bottom-color: var(--colorNeutralStrokeAccessiblePressed); } @@ -56,7 +58,11 @@ transition-delay: var(--curveDecelerateMid); } -.thaw-input__input-el { +.r1qp7m7v:focus-within:active::after { + border-bottom-color: var(--colorCompoundBrandStrokePressed); +} + +.thaw-input__input { align-self: stretch; box-sizing: border-box; flex-grow: 1; @@ -72,44 +78,51 @@ line-height: inherit; } -.thaw-input--focus, -.thaw-input:hover:not(.thaw-input--disabled, .thaw-input--invalid) { - border-color: var(--thaw-border-color-hover); +.thaw-input__input::placeholder { + color: var(--colorNeutralForeground4); + opacity: 1; } -.thaw-input--disabled, -.thaw-input--disabled .thaw-input__input-el { +.thaw-input--prefix { + padding-left: var(--spacingHorizontalMNudge); +} + +.thaw-input--prefix > .thaw-input__input { + padding-left: var(--spacingHorizontalXXS); +} + +.thaw-input--suffix { + padding-right: var(--spacingHorizontalMNudge); +} + +.thaw-input--suffix > .thaw-input__input { + padding-right: var(--spacingHorizontalXXS); +} + +.thaw-input__prefix, +.thaw-input__suffix { + display: inline-flex; + align-items: center; + justify-content: center; +} + +.thaw-input.thaw-input--disabled { + border-color: var(--colorNeutralStrokeDisabled); + border-bottom-color: var(--colorNeutralStrokeDisabled); + background-color: var(--colorTransparentBackground); cursor: not-allowed; - background-color: var(--thaw-background-color-disabled); - color: var(--thaw-font-color-disabled); +} + +.thaw-input--disabled > .thaw-input__input { + background-color: var(--colorTransparentBackground); + color: var(--colorNeutralForegroundDisabled); + cursor: not-allowed; +} + +.thaw-input--disabled > .thaw-input__input::placeholder { + color: var(--colorNeutralForegroundDisabled); } .thaw-input--invalid { border-color: var(--thaw-border-color-error); } - -.thaw-input--focus:not(.thaw-input--invalid) { - box-shadow: 0 0 0 2px var(--thaw-box-shadow-color); -} - -.thaw-input--focus.thaw-input--invalid { - box-shadow: 0 0 0 2px var(--thaw-box-shadow-color-invalid); -} - -.thaw-input__input-el::placeholder { - color: var(--thaw-placeholder-color); -} - -.thaw-input__prefix { - display: inline-flex; - align-items: center; - justify-content: center; - margin-right: 4px; -} - -.thaw-input__suffix { - display: inline-flex; - align-items: center; - justify-content: center; - margin-left: 4px; -} diff --git a/thaw/src/input/mod.rs b/thaw/src/input/mod.rs index b961e13..8d6e624 100644 --- a/thaw/src/input/mod.rs +++ b/thaw/src/input/mod.rs @@ -4,7 +4,6 @@ mod theme; pub use text_area::{TextArea, TextAreaRef}; pub use theme::InputTheme; -use crate::theme::{use_theme, Theme}; use leptos::*; use thaw_utils::{class_list, mount_style, ComponentRef, Model, OptionalProp}; @@ -54,10 +53,9 @@ pub fn Input( #[prop(optional, into)] class: OptionalProp>, #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, ) -> impl IntoView { - let theme = use_theme(Theme::light); mount_style("input", include_str!("./input.css")); - let value_trigger = create_trigger(); + let value_trigger = Trigger::new(); let on_input = move |ev| { let input_value = event_target_value(&ev); if let Some(allow_value) = allow_value.as_ref() { @@ -68,7 +66,7 @@ pub fn Input( } value.set(input_value); }; - let is_focus = create_rw_signal(false); + let is_focus = RwSignal::new(false); let on_internal_focus = move |ev| { is_focus.set(true); if let Some(on_focus) = on_focus.as_ref() { @@ -82,47 +80,7 @@ pub fn Input( } }; - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let border_color_hover = theme.common.color_primary.clone(); - css_vars.push_str(&format!("--thaw-border-color-hover: {border_color_hover};")); - css_vars.push_str(&format!("--thaw-box-shadow-color: {border_color_hover}33;")); - let border_radius = theme.common.border_radius.clone(); - css_vars.push_str(&format!("--thaw-border-radius: {border_radius};")); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.input.background_color - )); - css_vars.push_str(&format!("--thaw-font-color: {};", theme.input.font_color)); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.input.border_color - )); - css_vars.push_str(&format!( - "--thaw-border-color-error: {};", - theme.common.color_error - )); - css_vars.push_str(&format!( - "--thaw-placeholder-color: {};", - theme.input.placeholder_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-disabled: {};", - theme.input.background_color_disabled - )); - css_vars.push_str(&format!( - "--thaw-font-color-disabled: {};", - theme.input.font_color_disabled - )); - css_vars.push_str(&format!( - "--thaw-box-shadow-color-invalid: {}33;", - theme.common.color_error - )); - }); - css_vars - }); - let input_ref = create_node_ref::(); + let input_ref = NodeRef::::new(); input_ref.on_load(move |_| { comp_ref.load(InputRef { input_ref }); }); @@ -166,12 +124,13 @@ pub fn Input( view! { {if let Some(prefix) = input_prefix.and_then(|prefix| prefix.if_.then_some(prefix)) { @@ -192,7 +151,7 @@ pub fn Input( on:input=on_input on:focus=on_internal_focus on:blur=on_internal_blur - class="thaw-input__input-el" + class="thaw-input__input" disabled=move || disabled.get() placeholder=placeholder.map(|p| move || p.get()) ref=input_ref diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 3de796f..c7ba47c 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -16,6 +16,7 @@ pub struct ColorTheme { pub color_neutral_foreground_2_pressed: String, pub color_neutral_foreground_2_brand_hover: String, pub color_neutral_foreground_2_brand_pressed: String, + pub color_neutral_foreground_4: String, pub color_neutral_foreground_on_brand: String, pub color_neutral_stroke_disabled: String, @@ -23,6 +24,8 @@ pub struct ColorTheme { pub color_neutral_stroke_1_hover: String, pub color_neutral_stroke_1_pressed: String, pub color_neutral_stroke_accessible: String, + pub color_neutral_stroke_accessible_hover: String, + pub color_neutral_stroke_accessible_pressed: String, pub color_compound_brand_stroke: String, @@ -53,6 +56,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#242424".into(), color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), color_neutral_foreground_2_brand_pressed: "#115ea3".into(), + color_neutral_foreground_4: "#707070".into(), color_neutral_foreground_on_brand: "#fff".into(), color_neutral_stroke_disabled: "#e0e0e0".into(), @@ -60,6 +64,8 @@ impl ColorTheme { color_neutral_stroke_1_hover: "#c7c7c7".into(), color_neutral_stroke_1_pressed: "#b3b3b3".into(), color_neutral_stroke_accessible: "#616161".into(), + color_neutral_stroke_accessible_hover: "#575757".into(), + color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), color_compound_brand_stroke: "#0f6cbd".into(), @@ -90,6 +96,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#fff".into(), color_neutral_foreground_2_brand_hover: "#479ef5".into(), color_neutral_foreground_2_brand_pressed: "#2886de".into(), + color_neutral_foreground_4: "#999999".into(), color_neutral_foreground_on_brand: "#fff".into(), color_neutral_stroke_disabled: "#424242".into(), @@ -97,6 +104,8 @@ impl ColorTheme { color_neutral_stroke_1_hover: "#757575".into(), color_neutral_stroke_1_pressed: "#6b6b6b".into(), color_neutral_stroke_accessible: "#adadad".into(), + color_neutral_stroke_accessible_hover: "#bdbdbd".into(), + color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), color_compound_brand_stroke: "#479ef5".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 9762af6..828ead4 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -38,14 +38,18 @@ pub struct CommonTheme { pub border_radius_medium: String, pub border_radius_circular: String, + pub spacing_horizontal_x_x_s: String, pub spacing_horizontal_s_nudge: String, pub spacing_horizontal_s: String, + pub spacing_horizontal_m_nudge: String, pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, pub duration_ultra_fast: String, pub duration_faster: String, + pub duration_normal: String, pub curve_accelerate_mid: String, + pub curve_decelerate_mid: String, pub curve_easy_ease: String, pub height_tiny: String, @@ -95,14 +99,18 @@ impl CommonTheme { border_radius_medium: "4px".into(), border_radius_circular: "10000px".into(), + spacing_horizontal_x_x_s: "2px".into(), spacing_horizontal_s_nudge: "6px".into(), spacing_horizontal_s: "8px".into(), + spacing_horizontal_m_nudge: "10px".into(), spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), duration_ultra_fast: "50ms".into(), duration_faster: "100ms".into(), + duration_normal: "200ms".into(), curve_accelerate_mid: "cubic-bezier(1,0,1,1)".into(), + curve_decelerate_mid: "cubic-bezier(0,0,0,1)".into(), curve_easy_ease: "cubic-bezier(0.33,0,0.67,1)".into(), height_tiny: "22px".into(), diff --git a/thaw_utils/src/class_list.rs b/thaw_utils/src/class_list.rs index 773d3f8..bdc5502 100644 --- a/thaw_utils/src/class_list.rs +++ b/thaw_utils/src/class_list.rs @@ -163,6 +163,16 @@ where } } +impl IntoClass for (&'static str, bool) { + fn into_class(self) -> Class { + if self.1 { + Class::String(self.0.into()) + } else { + Class::None + } + } +} + impl IntoClass for (&'static str, Memo) { fn into_class(self) -> Class { Class::Fn(self.0.into(), Box::new(move || self.1.get())) From d00e970a6a05fd755ce440ca246358be986f4c3f Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 10 May 2024 21:51:35 +0800 Subject: [PATCH 008/143] refactor: avatar --- demo_markdown/docs/avatar/mod.md | 49 ++++++++++++- thaw/src/avatar/avatar.css | 54 ++++++++++++-- thaw/src/avatar/mod.rs | 118 +++++++++++++++++++++++-------- thaw/src/avatar/theme.rs | 20 ------ thaw/src/theme/color.rs | 8 +++ thaw/src/theme/common.rs | 16 ++++- thaw/src/theme/mod.rs | 5 +- 7 files changed, 208 insertions(+), 62 deletions(-) delete mode 100644 thaw/src/avatar/theme.rs diff --git a/demo_markdown/docs/avatar/mod.md b/demo_markdown/docs/avatar/mod.md index 117633c..4ad2e7e 100644 --- a/demo_markdown/docs/avatar/mod.md +++ b/demo_markdown/docs/avatar/mod.md @@ -1,11 +1,54 @@ # Avatar +```rust demo +view! { + +} +``` + +### Name + +```rust demo +view! { + +} +``` + +### Image + +```rust demo +view! { + +} +``` + +### Shape + +```rust demo +view! { + +} +``` + +### Size + ```rust demo view! { - - - + + + + + + + + + + + + + + } ``` diff --git a/thaw/src/avatar/avatar.css b/thaw/src/avatar/avatar.css index 68f131d..d10fb3d 100644 --- a/thaw/src/avatar/avatar.css +++ b/thaw/src/avatar/avatar.css @@ -1,13 +1,55 @@ .thaw-avatar { display: inline-block; - width: var(--thaw-size); - height: var(--thaw-size); - background-color: var(--thaw-background-color); - border-radius: var(--thaw-border-radius); + flex-shrink: 0; + position: relative; + vertical-align: middle; + border-radius: var(--borderRadiusCircular); + font-family: var(--fontFamilyBase); + font-weight: var(--fontWeightSemibold); + font-size: var(--fontSizeBase300); + width: 32px; + height: 32px; } -.thaw-avatar img { +.thaw-avatar--square { + border-radius: var(--borderRadiusMedium); +} + +.thaw-avatar__icon, +.thaw-avatar__initials { + position: absolute; + box-sizing: border-box; + top: 0px; + left: 0px; width: 100%; height: 100%; - border-radius: var(--thaw-border-radius); + line-height: 1; + border: var(--strokeWidthThin) solid var(--colorTransparentStroke); + display: flex; + align-items: center; + justify-content: center; + text-align: center; + user-select: none; + border-radius: inherit; + + background-color: var(--colorNeutralBackground6); + color: var(--colorNeutralForeground3); +} + +.thaw-avatar__icon { + font-size: 20px; +} + +.thaw-avatar__image { + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + border-radius: inherit; + object-fit: cover; + vertical-align: top; + + background-color: var(--colorNeutralBackground6); + color: var(--colorNeutralForeground3); } diff --git a/thaw/src/avatar/mod.rs b/thaw/src/avatar/mod.rs index 1ea5270..ccb33ca 100644 --- a/thaw/src/avatar/mod.rs +++ b/thaw/src/avatar/mod.rs @@ -1,45 +1,107 @@ -mod theme; - -pub use theme::AvatarTheme; - -use crate::{use_theme, Theme}; use leptos::*; use thaw_components::OptionComp; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_utils::{class_list, mount_style, OptionalProp, StoredMaybeSignal}; #[component] pub fn Avatar( - #[prop(optional, into)] src: Option>, - #[prop(optional, into)] round: MaybeSignal, - #[prop(default = MaybeSignal::Static(30), into)] size: MaybeSignal, + /// The Avatar's image. + #[prop(optional, into)] + src: Option>, + /// The name of the person or entity represented by this Avatar. + #[prop(optional, into)] + name: Option>, + /// Custom initials. + #[prop(optional, into)] + initials: Option>, + /// The avatar can have a circular or square shape. + #[prop(optional, into)] + shape: MaybeSignal, + /// Size of the avatar in pixels. + #[prop(optional, into)] size: Option>, #[prop(optional, into)] class: OptionalProp>, ) -> impl IntoView { - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - css_vars.push_str(&format!("--thaw-size: {}px;", size.get())); - css_vars.push_str(&format!( - "--thaw-border-radius: {};", - if round.get() { "50%" } else { "3px" } - )); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {}", - theme.avatar.background_color - )); - }); - css_vars - }); mount_style("avatar", include_str!("./avatar.css")); + let style = move || { + let size = size?.get(); + + let mut style = format!("width: {0}px; height: {0}px;", size); + + if let Some(font_size) = match size { + 0..=24 => Some(100), + 25..=28 => Some(200), + 29..=40 => None, + 41..=56 => Some(400), + 57..=96 => Some(500), + 97..=128 => Some(600), + _ => Some(600), + } { + style.push_str(&format!("font-size: var(--fontSizeBase{});", font_size)) + } + + Some(style) + }; + + let is_show_default_icon = src.is_none() && initials.is_none() && name.is_none(); + let name: Option> = name.map(|n| n.into()); + view! { + { + move || { + if let Some(initials) = initials.as_ref().map_or_else(|| name.as_ref().map(|n| initials_name(n.get())), |i| Some(i.get())) { + view! { + + {initials} + + }.into() + } else { + None + } + } + } - + + { + if is_show_default_icon { + view! { + + }.into() + } else { + None + } + } } } + +// TODO +fn initials_name(name: String) -> String { + name.split_at(2).0.to_string().to_ascii_uppercase() +} + +#[derive(Default, Clone)] +pub enum AvatarShape { + #[default] + Circular, + Square, +} + +impl AvatarShape { + pub fn as_str(&self) -> &'static str { + match self { + Self::Circular => "circular", + Self::Square => "square", + } + } +} diff --git a/thaw/src/avatar/theme.rs b/thaw/src/avatar/theme.rs deleted file mode 100644 index a335f79..0000000 --- a/thaw/src/avatar/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct AvatarTheme { - pub background_color: String, -} - -impl ThemeMethod for AvatarTheme { - fn light() -> Self { - Self { - background_color: "#f7f7f7".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#424245".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index c7ba47c..fa259d9 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -6,6 +6,7 @@ pub struct ColorTheme { pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, pub color_neutral_background_1_pressed: String, + pub color_neutral_background_6: String, pub color_neutral_foreground_disabled: String, pub color_neutral_foreground_1: String, @@ -16,6 +17,7 @@ pub struct ColorTheme { pub color_neutral_foreground_2_pressed: String, pub color_neutral_foreground_2_brand_hover: String, pub color_neutral_foreground_2_brand_pressed: String, + pub color_neutral_foreground_3: String, pub color_neutral_foreground_4: String, pub color_neutral_foreground_on_brand: String, @@ -47,6 +49,8 @@ impl ColorTheme { color_neutral_background_1: "#fff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_background_6: "#e6e6e6".into(), + color_neutral_foreground_disabled: "#bdbdbd".into(), color_neutral_foreground_1: "#242424".into(), color_neutral_foreground_1_hover: "#242424".into(), @@ -56,6 +60,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#242424".into(), color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), color_neutral_foreground_2_brand_pressed: "#115ea3".into(), + color_neutral_foreground_3: "#616161".into(), color_neutral_foreground_4: "#707070".into(), color_neutral_foreground_on_brand: "#fff".into(), @@ -87,6 +92,8 @@ impl ColorTheme { color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_background_6: "#333333".into(), + color_neutral_foreground_disabled: "#5c5c5c".into(), color_neutral_foreground_1: "#fff".into(), color_neutral_foreground_1_hover: "#fff".into(), @@ -96,6 +103,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#fff".into(), color_neutral_foreground_2_brand_hover: "#479ef5".into(), color_neutral_foreground_2_brand_pressed: "#2886de".into(), + color_neutral_foreground_3: "#adadad".into(), color_neutral_foreground_4: "#999999".into(), color_neutral_foreground_on_brand: "#fff".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 828ead4..a430588 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -20,9 +20,16 @@ pub struct CommonTheme { pub color_error_hover: String, pub color_error_active: String, + pub font_size_base_100: String, pub font_size_base_200: String, pub font_size_base_300: String, pub font_size_base_400: String, + pub font_size_base_500: String, + pub font_size_base_600: String, + pub font_size_base_700: String, + pub font_size_base_800: String, + pub font_size_base_900: String, + pub font_size_base_1000: String, pub line_height_base_200: String, pub line_height_base_300: String, @@ -37,7 +44,7 @@ pub struct CommonTheme { pub border_radius_none: String, pub border_radius_medium: String, pub border_radius_circular: String, - + pub spacing_horizontal_x_x_s: String, pub spacing_horizontal_s_nudge: String, pub spacing_horizontal_s: String, @@ -81,9 +88,16 @@ impl CommonTheme { color_error_hover: "".into(), color_error_active: "".into(), + font_size_base_100: "10px".into(), font_size_base_200: "12px".into(), font_size_base_300: "14px".into(), font_size_base_400: "16px".into(), + font_size_base_500: "20px".into(), + font_size_base_600: "24px".into(), + font_size_base_700: "28px".into(), + font_size_base_800: "32px".into(), + font_size_base_900: "40px".into(), + font_size_base_1000: "60px".into(), line_height_base_200: "16px".into(), line_height_base_300: "20px".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index e270590..ff9943f 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,7 +4,7 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, AutoCompleteTheme, AvatarTheme, BackTopTheme, BreadcrumbTheme, + AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme, @@ -29,7 +29,6 @@ pub struct Theme { pub alert: AlertTheme, pub skeletion: SkeletionTheme, pub tag: TagTheme, - pub avatar: AvatarTheme, pub message: MessageTheme, pub select: SelectTheme, pub slider: SliderTheme, @@ -65,7 +64,6 @@ impl Theme { alert: AlertTheme::light(), skeletion: SkeletionTheme::light(), tag: TagTheme::light(), - avatar: AvatarTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), slider: SliderTheme::light(), @@ -100,7 +98,6 @@ impl Theme { alert: AlertTheme::dark(), skeletion: SkeletionTheme::dark(), tag: TagTheme::dark(), - avatar: AvatarTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), slider: SliderTheme::dark(), From c6f83aa01dcae6d331c66a27be262ee8f63f86a1 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 10 May 2024 23:26:09 +0800 Subject: [PATCH 009/143] refactor: divider --- demo_markdown/docs/divider/mod.md | 26 ++++++++++-- thaw/src/divider/divider.css | 69 ++++++++++++++++++++++++++++--- thaw/src/divider/mod.rs | 19 +++++++-- thaw/src/theme/color.rs | 3 ++ 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/demo_markdown/docs/divider/mod.md b/demo_markdown/docs/divider/mod.md index 385e2d9..aeb3e9b 100644 --- a/demo_markdown/docs/divider/mod.md +++ b/demo_markdown/docs/divider/mod.md @@ -2,9 +2,29 @@ ```rust demo view! { - "top" - - "bottom" + +
+ +
+
+ "Text" +
+
+} +``` + +### Vertical + +```rust demo +view! { + +
+ +
+
+ "Text" +
+
} ``` diff --git a/thaw/src/divider/divider.css b/thaw/src/divider/divider.css index 949ecb9..2f33222 100644 --- a/thaw/src/divider/divider.css +++ b/thaw/src/divider/divider.css @@ -2,12 +2,71 @@ .thaw-divider { position: relative; display: flex; + flex-direction: row; + align-items: center; + flex-grow: 1; width: 100%; - margin: 1.5rem 0; + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase200); + font-weight: var(--fontWeightRegular); + color: var(--colorNeutralForeground2); + line-height: var(--lineHeightBase200); + box-sizing: border-box; + text-align: center; } -.thaw-divider__line { - background-color: #efeff5; - height: 1px; - width: 100%; +.thaw-divider--vertical { + flex-direction: column; + width: auto; + height: 100%; + min-height: 20px; } + +.thaw-divider::before { + content: ""; + display: flex; + flex-grow: 1; + min-width: 8px; + border-top-width: var(--strokeWidthThin); + border-top-style: solid; + border-color: var(--colorNeutralStroke2); + box-sizing: border-box; +} + +.thaw-divider--vertical::before { + min-width: auto; + min-height: 8px; + border-top-width: medium; + border-top-style: none; + border-right-width: var(--strokeWidthThin); + border-right-style: solid; +} + + +.thaw-divider::after { + content: ""; + display: flex; + flex-grow: 1; + min-width: 8px; + border-top-width: var(--strokeWidthThin); + border-top-style: solid; + border-color: var(--colorNeutralStroke2); + box-sizing: border-box; +} + +.thaw-divider--vertical::after { + min-width: auto; + min-height: 8px; + border-top-width: medium; + border-top-style: none; + border-right-width: var(--strokeWidthThin); + border-right-style: solid; +} + +.thaw-divider__wrapper { + margin: 0 12px; +} + +.thaw-divider--vertical > .thaw-divider__wrapper { + margin: 12px 0; +} \ No newline at end of file diff --git a/thaw/src/divider/mod.rs b/thaw/src/divider/mod.rs index a3793ca..830926a 100644 --- a/thaw/src/divider/mod.rs +++ b/thaw/src/divider/mod.rs @@ -1,13 +1,26 @@ use leptos::*; +use thaw_components::OptionComp; use thaw_utils::{class_list, mount_style, OptionalProp}; #[component] -pub fn Divider(#[prop(optional, into)] class: OptionalProp>) -> impl IntoView { +pub fn Divider( + #[prop(optional, into)] class: OptionalProp>, + #[prop(optional, into)] vertical: MaybeSignal, + #[prop(optional)] children: Option, +) -> impl IntoView { mount_style("divider", include_str!("./divider.css")); view! { -
-
+ } } diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index fa259d9..6c246c7 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -25,6 +25,7 @@ pub struct ColorTheme { pub color_neutral_stroke_1: String, pub color_neutral_stroke_1_hover: String, pub color_neutral_stroke_1_pressed: String, + pub color_neutral_stroke_2: String, pub color_neutral_stroke_accessible: String, pub color_neutral_stroke_accessible_hover: String, pub color_neutral_stroke_accessible_pressed: String, @@ -68,6 +69,7 @@ impl ColorTheme { color_neutral_stroke_1: "#d1d1d1".into(), color_neutral_stroke_1_hover: "#c7c7c7".into(), color_neutral_stroke_1_pressed: "#b3b3b3".into(), + color_neutral_stroke_2: "#e0e0e0".into(), color_neutral_stroke_accessible: "#616161".into(), color_neutral_stroke_accessible_hover: "#575757".into(), color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), @@ -111,6 +113,7 @@ impl ColorTheme { color_neutral_stroke_1: "#666666".into(), color_neutral_stroke_1_hover: "#757575".into(), color_neutral_stroke_1_pressed: "#6b6b6b".into(), + color_neutral_stroke_2: "#525252".into(), color_neutral_stroke_accessible: "#adadad".into(), color_neutral_stroke_accessible_hover: "#bdbdbd".into(), color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), From 7219c0cb9380063b88f3292b1ebac2b6b15d3d5c Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sat, 11 May 2024 10:21:12 +0800 Subject: [PATCH 010/143] feat: logo --- demo/src/assets/favicon.ico | Bin 23462 -> 5673 bytes logo.svg | 13 ++++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/demo/src/assets/favicon.ico b/demo/src/assets/favicon.ico index 100548a1e909d48f0c2a178b01cd2760b5c98732..81f1f1599dbb82e797143adfd2b85e91096ffd6f 100644 GIT binary patch literal 5673 zcmWkycRbYpAOGCI8FA*>PBv#tMmQ_0jBFVfLXomc$Q`mmMhag-8f33R(VaarDl;pb z8P3@{?&tS@z2A@b>-ieb$LsNWy#9It0O(x)e?R~dVCMpW^9v+enj2kU;AJ>hFPIn` z-1xuu{|^Q|{|>@2oBv1m1I=wfLq(7N0|3tNCI-4Tp;Mc$A4PE5PIY5J^iQGgZ=8yP zMQvzkSW)E{_!v-)MWiV>NH-m!sQQeCv)>60pL}U+m(KZ%6SaELjMc{S-7}Ss!cY;o zLKI~-$St`mEq7o*OSyRZaXt$*Rx@aDTeDbuMICp?PO!J+x%CLgW&ls6kq%S4NT}e8 z9r4-jVuytH4pG}RARTwj+G;u-523&SI6eVuu0?KWTA&hKi~_SzmXRc{O%7_H1Uw}dZ{g;MsI7Z5!|pK+?>$x6mVmRYJdeCGQ1%N zaN8`$ckZ%0JM3ZGuA_CssJbFBp7UP8T{&trAJxP&hg)n7E~s?BFJn-0o`6_&{2brpRyt64_=)F0f)FpBsG5n zzNkkNRva~=Ds7`hj|-wki|`+akq-4ta|;FTOM!{2Q*4WlN6=qgMDAD?Lu!t93(4po zXvA=!<3XMTZEAqTX>TL#qJcgZ$s8-c72YZ7%_PSal&e-9=w7?$eXT>fEG(4gn~+=5 zA9wFx_4bsh)kJ*KWU#B`Bby=4#h8_VkJ%?qV@sFYp15=537P(_zLcHxyCbiM!K`D_ z-Mv9Eb9CSD&rQz+7Kv8Row5Y0GaJv?z_5c0pR1>CxA+8`v5!#5Ag-ufbVe6y$J1WC2XD<|ZHT7#Ec5NGNlgsO8+Bcqy zy)o7f7xY@-7a&@+Kdt`5Qm)*Hu-(tVvvb9^L098D)XEa&7K-QdtLN*H+=Mc%_?`?ghu zclu?g(XOqP`#M~ed%nw#tL(qV0+jOWJ*Er#eojWM>@tnHKi=(sk#aK{jij;ojl?QH zUjT2-yKXJ|S1x(F4vOv`GW|Pg@o?Z7T1Y!~J8PL9SomCEo#TJjhjznygvIAl_s8cs z1ig9>1csEcsNqf>pc3(v$5mIVs7C&~UCqliSVU?aC7lYU_(aZOC0J^L!`*^ewQ_&V3e}k*%#;bT2w*H_X5^y-8+HAszgWCYZTfaiBEbwcMoCtx`sJ5r`S)rX9j~0 zpagT(%lLY_+kmaeFl|vS56wTD6hq9&kK&!qM%@)%jv|m!l^+J%{WSs|BJOKY`Ir){+Jx{Z5Xgq(X zIpfjJtyu}LRqrkZLq;$zu)JH2zm1iD(ADo_WXu{eESzrs2IZa88COL9#!-J&8;63~ zz>lh3SQHhg{}bwunXSSHX6Hntx;UEL6NpUu+1!f-Yujqw$H(NFrmZ07;Bz_tfN0`& zm-l)(Or%`VShp6NZc{zd7+G_Amj*Wgxl$WvLuF1=QC2oD3 z+Qtj9WJ>=)RI-v-a2(p!UE)83Ki#~B4JvS(7gS8LnL4~LZ7tpaJEB2Pl8w3`F*e|8 zIz*$^dXwH}4^`bruSuUE1Y`*G2-Og;IEsO-XKsrLygT@3vFH?kqe+**0_62s?AVW& zUEt9gZ=#IWINYOR9i`fJwqZSVgeD3rU-3gZQtfUNA*D16OZOv1-4Lw`Y%NLX-1v&B zA6=7bD?KvUCl8&zV}bS15Gp83dZVpgsp^ozx|3@{?Z!gzGMV!0lc?fgaLyXE-3+!BOn@{QP6C0Iy+xp zdq_*SR-KrGqP>>+9LEnd_Z58qyzcwZ!tq6`^wG7{Cx2bvmzRedqGe0Km z?0v6Ow89{8P4E^_?GWiMRmw>>Z}-UxcP29YbYB3XfP3lps$e2ztP{jtjHlEHSL0@y zX8z21kxX)lsr>xg)>oMPzVQGZ(FE~jjgzln|D#QnqL*YNN);AbNdGw(j7GtZd}(_v zBAzW30l|tg{~DgdxW#mKAU~dg({5!@G%jMYDIKoClDx2!|Ly>*vA6&-f{*qCCjT+8 z8iR{Er%Ep}(jEV|lK}m&qr|*)%HQRBr9GaKThTONdfZ!WbH)-Tw*ydPj2r71_b((5VDn>MtNX%yaO(7?z-^7UQy{Uk&>h3+!dKuw?f{ zPCMv@5Cb$U8epJfai{m~Zu z2e%Z)dWwcL40u16zDD=SZW+G(*of0d6?}Iob;2}9YUKmJ3D1c0@&!V1!0UEX6$B`R zY%~QV9_9?F*9ws&_|xn&WnBKg%}Kl~1RvHtGxoH$bsW-3 z5KMnfkWxze^*bc$nl75+%zCQjuaG1^SNSl$zd8C1G)c%e}3mx~4XG`v0*9Le!>Zb2nEN=+P zI9Wi0Gq5dx%PR269biwrz)$0g*a}^=#POrLV#=_k^OBK*v9(++81#B+X!$yM3}Dn^ zUzH9Lo{)p?Wl+72&j&nqo(r!OllvUa-y;+-y*M{&DJ}w+ATt72k9flTq`~St7x4h5 z96z$6Av|mX+Zf2N4PQN^1H_M>0J=g@-o_plIKqueg(!?tl_kF*3zx}06+{Hk%-5kP zss*7dbc=t0 z7#j!=C^$q405E0{7Eo}C)B=Fq2ay0wEfvPgjiWe*O-rC4ID;|IC#uP<8#TU(iDIwM zn__(PKzV(aZ7c97_iZPi`s3|j^F2wdpb$d#1}bC>SFB*D1%#;MlpCXOHfo8_b)Du9 zZ7-=sbjb-mi%=Gzx(8@>yjC2a&=@3gfA*%a1>Plm2)v+g?K_z#It8Hte$9I> z$M09g%6fDcf{clo)w7psFI|yw0OG>8PW5)Xm#f1b04j^Aw^Dq)X!tq!fwyfZW5Zl^ zP71)gKwXF5yi?k)+)O~RrmGdBtOFkh6Cludx!hNFGZ6zcqE%GitoeAvfaaODm^Ylv z`eC#vk(#+(A)Rhw3a~yzr~~+oie`Kh`Bz zv_@8ZNM$;aJXY8cqZy~Kn=%H(hhJb!6hpq_oMRCIt5je5yLrl$KB3okqw}qIP%#G+ zgPxen_{5NNpH)oWDp9Xqt5g_81wfIwV}2)f|6KFYQ%q>lYbs_pYw&2Ftd!9hPDfJ+-a- z-mldz9d2L}9znlhlrI2BQm#vf+dkPNFr>`6w)>!@6^8L{?%CendEmin`9j1vmJ%tE zpuhq0dxkhZwP5uS1v?<*$#m(WeQ0R4wCfU!`1QO1*!=I%be$4|^f+Oh{G#F6{EbfD zSYWv`iJ~i>qzVH?aG$5-%FS{^N#@NxLVK~SaY!7tBZ<=L#^V76bDuMoHLCOhP?AA& zPu232+9oR@Mlylr*w%&rqdJ&7S${`ZXTp*m_)i3<-Ltz3lA7ufGBMduv0Ae1{ZuFm zrXh^>q{LV0Wc&&#TI{f!lWb|$Mnexkh!X_Ihb+og;E7xk3-mLjqDCZB$Dh@K@mF`8 zZ?kTxj7OadbJ#s!65)UZnByYqKE*=}1hy#h)QhYe!fjWc88Tb*wOuFYs z1VQk%m6b)fgX>)FuYLOKb_gpD8fu+VK@(KLt+O=9S zEvoOY1Ynr^H<9zs(@*4$Xabv{#Ku}(8V9IQ+^$Dv_(2kJ91?Y0F1<1NqJ!VkflWKZ zKF?LIGDFcKQUIR4tR-v{Fhr<2sBLbm_xvzQE;GVpH{0R_V*#f0CMHTgkz8how5Gg& z=Y96{b1V>?&chij8zh_MCI)6Fh5$Oq3OLSAiM`WiL3D#?A4|CVp+9_f#aIejsA|`b z>XD*MgdN)=t6$sqMojri+QZOn+OKY=X+&uD`OO<0)EGo!;XZ@vR{5VyD=8fiN%zIu z_vwoR;aP|zhMr|US9!J38|NVv%UYKFY&y6Y0BSNPjP3_;v~jT|OSD2&}ZB63St z6vJCmHyuWlj!$)g^8VZ-2Aw|_2RVhl!#`(S-jmtWQY(`L5dRST`JzrS(qzWML`tME zAYNTt(!}xV&?xI=i7f~2%f#wGVNo;UAq&XuRKP}(0r!hIANpd>7%FI>$j9C%WCY{y z;OqpgMp4d(LKnln&Pj)ysbbeV>7gbqV)h}QMM#R$2s$K9!K5sftNTH5J6>RjI+a3@ z%*3Qlp|Gm|sudeFDH~@C_Yspx1dy{68<3UsCh8N}$oSzaR{EKa%v z6qEl2c&BMXXGt5G7L#XBCK=I2bcts-1%U7TW<=*mtXxW93}I&d8#mz4g1QUt(uyEy&fqD!OOkKv*FK;A`#*(^vc^A(l`!rS+YbhdyE zDoA#CW_()$Fo!#c{foc{6|ic7OZ@nj4lANZTJ{W-zq<5qZ+E6&Z>r9m`#mUQ+lyZ` z*7K=)nD=){(Z89w*vLes&UJu&x~lXzJjll*5>6bq>o?z8@IT4IW&geCS;j=)lq8d+ zTb*k?(f70J_(_Q0CFYeWcSWY0A{jG#2`XFOQ|^igg>f^ZLzRPNgUCKHXQb29f0M5g z1+h{IUt=~BqSneN*P1sY%okhyD(0e8oRDM~4WB! z6K`9EfhEwJku!nHfDBSA_NxPvo}PO2zJAf>J*InqRhpl<={bUTU5aKZz!fO^(`va) zaX_AM#ThDFLGNnyC=X>G!Kh>jnR2@L1@jG~!qLZ~gS$M!J9YCqQ|Et{a%(Z)hIUqd z)J3d&?vr4u@wFx!`&kPQ^MLkpsjIhaCj>fH=?t^N;s=0jjO+zS4KfcIw#PqU@Q9zK zeKT~A5MHG4rqDkkH`~euDL($n;kI*viMtK_A?$Xz;HxB78%7=Q*HNd(Ds8f%jC}2z zZ%a;3O_Po6SLg+<*E5u)&V~x;WCz&?AeAZiN#IJhm=`Nm73eAfe+NJ=V;eQMk zZ|e$bC?`(pdC6uZxYsSMgYMTP8Im~dTdh*ztqL}CLy74WsUzO6FYTE5a?kpvIxa3A){UzOgYp49m&H(?;---o+Z>-x&W&?it?Wc_bGsCQF?pNG8 zzvVQW*CjkFlB$q%N{sUnc6w&+&M*pjGHk(A7WYRtxoeSI2Kv}!pv+?*u~UAOalTgY zOgLCIpN`{u+LOh||2xt9G6!Vx?t+W-I_qnMlgW$;%D?GU$np#*6?NBtbiU;UObpEp JD)lhY{{w*igB<_> literal 23462 zcmeI4TZ|Po7{@C_F;VdH;G^s9!558}7@u@sR7j8*jRuj#Yrq$bny6=wXm;^IH! zr_+8NAx^`;#ft_0UL^XK3vq!E;&SYW60c)tJhxw$3UTR`YEL4j=#N}2I%HkkA-hB! z`vCUOv44wwKlVe|W#h;4L$FMzU!gu4>*!Vxt;mc z#5&}&R6Zfjs$7W*1%S^S`INXBx@^LJv@{zx+at(-5c^G(TcKJ}vz9Bx>A2tbqTIVH z=3}$VA0c-o%Mn$vh?ymJR2L7SoO`E;QI=gz{Dk`cfMjz$jW+qTxC(rRrv;Ga{c9m$s7^I4uFAgV8wAc0PJMgK6UA!^doT7mKfn18B!? zZ3i##xgYz9sGP`Z$D0#)G6BZNsfX!&*k-J(k{9x?VITJ@`1n9GKeNl7@x+5!2p{&S>`I$D#_hrR;f_`BP zUTDW}gWRw_!5_O!8mKrMuMk!)PLx9V{;ZhxMA`P9&sXFV{=D1uo}CqcG4b+cmB)$s z@7fZ|O2Q@%$Y;dGMeHkiuPfSr>bp|P6MwVR_N|qd4=W!|l-qYjI4fm`+l%y9VNWjy z+HtmgZ{3p5Yx_F1Uvt!Td9283_*FZ5{xbHDl!HsMYjuaEy8 zGqbYA>(p$Yn7>asLegM7$7NfM_IxzDT$a(NK5G4ak1^UOJHLId@j@_q(8;N{L&`5V ztNsh0%c0L3AN%sT5SuQ z-gdJ356&JhwHc3^;;rN8D4ygFSG%L=pAwB1f?AP^o+B8t{Rp^nHSVjIEpXk5Q zuCwBC6!q|I%?pf{IXP*DpY^3nKRH~5K9o{bz8ufdy19>-u~!??zvXpJ(tmz!GNW`% z?DjrZJDx5h!`s(4->=-9$g@AiYOfb7=IQ(X8rna!_S?~)&)21y#^<@w`re+O|Mz6Y zafqO@XkNpS?Q3M9_0Fqv#^>vz(wO=Mt+|HTQ&TqQt?J@V@3N%J9J@Z2WmP37rT6XN zw7L+h*!ES1RrQ=WR?`Je^kZq-T4*?yeHCTZ4o-^6063MOJC4Dt2&?vSqAk&1?mMep zao(KszT4iA@{4}=&N0q^jm=jI5%p_>(6hqY4sW7P3f5r^K)%156fk`J{?E> zsHfW>U=KL`Ze&Hji&p;vSGi`xZ`9ZBZ?Yep%bpM- zmopo#pg)tD6*--!$ThJ6?Uruu?Z;$1A+kN? z*+cB{d)=2x`!nU~j`d^{th&Tr9H^G&eo5evZTn3EUh(bE3D zt<0*@N6V=qf9jL(Po9|{Oxmovc*n`=i^|tlV-OMJ|E8YhL{I?IEQsQKfkcgyt&OU z)E2L6W|8Nk4=;~(C-h?jt8LMEd5r_W55wxuun~U9k^KSkS$X*(vtEMJwb;$$@cD9@ zw&u%;>j7M2GBM^K{mbp`->%y*u<9#iTOpjNhl>?|Zx=7D-_{I#kBxQTI}7omzc1Sn z*VgLSlgCQ);&rZ#aw*^6j+$xfVh8p1Wt2`=e4W=8mp0X}^ZNSTrvARnxX!CfT$0v5 zG>q%%OB2?1vHxP*TJ1^e;$v4jZQi&L$`UajLqq3fNoj=Lxm*LBd7 z>*($Jrhnsm7T-(hKc4Rw9d1`?SZ z3b*UKA6&nU_3l;jY0W$Nj$F)lA?x>Kob%>k_o*h>U%aeUmv)>d{Z-Y!{|{vdE4L{< z+qj`#De2Ed|1bC0QiweEd0sBs&y2|u<+vJqdA|q~zp`<(rMkF2roLtKO2#MDc+SsJ zY^*G!F0l`cRZZ8ng$leGP0>}p5}?uJm=5X_@Y+ouwy>^5!B gX**Y$D*Km10$ZbAFe6=Gc(JZW>H3A5(WrO-1Fx - + + + fill="#fff" transform="translate(8 8) scale(13)"> \ No newline at end of file From 6d42248e76ac69452b8592543ae398fda3668bfe Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sat, 11 May 2024 15:53:37 +0800 Subject: [PATCH 011/143] feat: nav --- demo/src/components/site_header.rs | 14 +++---- demo/src/pages/components.rs | 21 +++++----- thaw/src/layout/layout.css | 1 + thaw/src/lib.rs | 3 ++ thaw/src/nav/mod.rs | 5 +++ thaw/src/nav/nav-drawer.css | 61 ++++++++++++++++++++++++++++++ thaw/src/nav/nav_drawer.rs | 27 +++++++++++++ thaw/src/nav/nav_item.rs | 24 ++++++++++++ thaw/src/text/mod.rs | 6 +++ thaw/src/theme/color.rs | 12 ++++++ thaw/src/theme/common.rs | 4 ++ 11 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 thaw/src/nav/mod.rs create mode 100644 thaw/src/nav/nav-drawer.css create mode 100644 thaw/src/nav/nav_drawer.rs create mode 100644 thaw/src/nav/nav_item.rs create mode 100644 thaw/src/text/mod.rs diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index 1aba86e..efaa7e0 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -161,13 +161,13 @@ pub fn SiteHeader() -> impl IntoView { - { - use crate::pages::{gen_guide_menu_data, gen_menu_data}; - vec![ - gen_guide_menu_data().into_view(), - gen_menu_data().into_view(), - ] - } + // { + // use crate::pages::{gen_guide_menu_data, gen_menu_data}; + // vec![ + // gen_guide_menu_data().into_view(), + // gen_menu_data().into_view(), + // ] + // }
diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 1cf7946..3fd5523 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -59,11 +59,11 @@ pub fn ComponentsPage() -> impl IntoView { - + {gen_menu_data().into_view()} - + @@ -81,15 +81,13 @@ pub(crate) struct MenuGroupOption { impl IntoView for MenuGroupOption { fn into_view(self) -> View { let Self { label, children } = self; + let children_len = children.len(); view! { - - - {children.into_iter().map(|v| v.into_view()).collect_view()} - - - } + + {format!("{label} ({children_len})")} + + {children.into_iter().map(|v| v.into_view()).collect_view()} + }.into_view() } } @@ -101,7 +99,8 @@ pub(crate) struct MenuItemOption { impl IntoView for MenuItemOption { fn into_view(self) -> View { let Self { label, value } = self; - view! { } + // key=value label + view! { {label} } } } diff --git a/thaw/src/layout/layout.css b/thaw/src/layout/layout.css index b03a32a..e81e579 100644 --- a/thaw/src/layout/layout.css +++ b/thaw/src/layout/layout.css @@ -3,6 +3,7 @@ } .thaw-layout--absolute-positioned { + background-color: inherit; position: absolute; top: 0; right: 0; diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index c083318..f09383f 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -27,6 +27,7 @@ mod menu; mod message; pub mod mobile; mod modal; +mod nav; mod popover; mod progress; mod radio; @@ -40,6 +41,7 @@ mod switch; mod table; mod tabs; mod tag; +mod text; mod theme; mod time_picker; mod typography; @@ -73,6 +75,7 @@ pub use loading_bar::*; pub use menu::*; pub use message::*; pub use modal::*; +pub use nav::*; pub use popover::*; pub use progress::*; pub use radio::*; diff --git a/thaw/src/nav/mod.rs b/thaw/src/nav/mod.rs new file mode 100644 index 0000000..33174e4 --- /dev/null +++ b/thaw/src/nav/mod.rs @@ -0,0 +1,5 @@ +mod nav_drawer; +mod nav_item; + +pub use nav_drawer::*; +pub use nav_item::*; \ No newline at end of file diff --git a/thaw/src/nav/nav-drawer.css b/thaw/src/nav/nav-drawer.css new file mode 100644 index 0000000..1ff976f --- /dev/null +++ b/thaw/src/nav/nav-drawer.css @@ -0,0 +1,61 @@ +.thaw-nav-drawer { + overflow: hidden; + width: 260px; + max-width: 100vw; + height: auto; + /* max-height: 100vh; */ + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); + position: relative; +} + +.thaw-nav-drawer__body { + padding: 0 var(--spacingVerticalMNudge); + flex: 1 1 0%; + align-self: stretch; + position: relative; + z-index: 1; + /* overflow: auto; */ +} + +.thaw-nav-item { + display: flex; + text-transform: none; + position: relative; + justify-content: start; + gap: var(--spacingVerticalL); + padding: var(--spacingVerticalMNudge); + /* background-color: var(--colorNeutralBackground4); */ + border-radius: var(--borderRadiusMedium); + color: var(--colorNeutralForeground2); + text-decoration-line: none; + border: none; + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + font-weight: var(--fontWeightRegular); + line-height: var(--lineHeightBase300); + cursor: pointer; +} + +.thaw-nav-item:hover { + background-color: var(--colorNeutralBackground4Hover); +} + +.thaw-nav-item:active { + background-color: var(--colorNeutralBackground4Pressed); +} + +.thaw-nav-item--selected::after { + content: ""; + position: absolute; + width: 4px; + height: 20px; + background-color: var(--colorNeutralForeground2BrandSelected); + border-radius: var(--borderRadiusCircular); + margin-inline-start: -18px; +} \ No newline at end of file diff --git a/thaw/src/nav/nav_drawer.rs b/thaw/src/nav/nav_drawer.rs new file mode 100644 index 0000000..91b96b9 --- /dev/null +++ b/thaw/src/nav/nav_drawer.rs @@ -0,0 +1,27 @@ +use leptos::*; +use thaw_utils::{mount_style, Model}; + +#[component] +pub fn NavDrawer( + #[prop(optional, into)] selected_value: Model, + children: Children, +) -> impl IntoView { + mount_style("nav-drawer", include_str!("./nav-drawer.css")); + + view! { + +
+
+ {children()} +
+
+
+ } +} + +#[derive(Clone)] +pub(crate) struct NavDrawerInjection(pub Model); + +pub(crate) fn use_nav_drawer() -> NavDrawerInjection { + expect_context() +} diff --git a/thaw/src/nav/nav_item.rs b/thaw/src/nav/nav_item.rs new file mode 100644 index 0000000..4d221d7 --- /dev/null +++ b/thaw/src/nav/nav_item.rs @@ -0,0 +1,24 @@ +use leptos::*; +use crate::use_nav_drawer; +use thaw_utils::{class_list, StoredMaybeSignal}; + +#[component] +pub fn NavItem(#[prop(into)] value: MaybeSignal, children: Children) -> impl IntoView { + let nav_drawer = use_nav_drawer(); + let value: StoredMaybeSignal<_> = value.into(); + let on_click = move |_| { + let value = value.get(); + if nav_drawer.0.with(|key| key != &value) { + nav_drawer.0.set(value); + } + }; + view! { + + {children()} + + } +} diff --git a/thaw/src/text/mod.rs b/thaw/src/text/mod.rs new file mode 100644 index 0000000..744f638 --- /dev/null +++ b/thaw/src/text/mod.rs @@ -0,0 +1,6 @@ +use leptos::*; + + +pub fn Caption1Strong() { + +} \ No newline at end of file diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 6c246c7..bf2cb6d 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -6,6 +6,9 @@ pub struct ColorTheme { pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, pub color_neutral_background_1_pressed: String, + pub color_neutral_background_4: String, + pub color_neutral_background_4_hover: String, + pub color_neutral_background_4_pressed: String, pub color_neutral_background_6: String, pub color_neutral_foreground_disabled: String, @@ -17,6 +20,7 @@ pub struct ColorTheme { pub color_neutral_foreground_2_pressed: String, pub color_neutral_foreground_2_brand_hover: String, pub color_neutral_foreground_2_brand_pressed: String, + pub color_neutral_foreground_2_brand_selected: String, pub color_neutral_foreground_3: String, pub color_neutral_foreground_4: String, pub color_neutral_foreground_on_brand: String, @@ -50,6 +54,9 @@ impl ColorTheme { color_neutral_background_1: "#fff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_background_4: "#f0f0f0".into(), + color_neutral_background_4_hover: "#fafafa".into(), + color_neutral_background_4_pressed: "#f5f5f5".into(), color_neutral_background_6: "#e6e6e6".into(), color_neutral_foreground_disabled: "#bdbdbd".into(), @@ -61,6 +68,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#242424".into(), color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), color_neutral_foreground_2_brand_pressed: "#115ea3".into(), + color_neutral_foreground_2_brand_selected: "#0f6cbd".into(), color_neutral_foreground_3: "#616161".into(), color_neutral_foreground_4: "#707070".into(), color_neutral_foreground_on_brand: "#fff".into(), @@ -94,6 +102,9 @@ impl ColorTheme { color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_background_4: "#0a0a0a".into(), + color_neutral_background_4_hover: "#1f1f1f".into(), + color_neutral_background_4_pressed: "#000000".into(), color_neutral_background_6: "#333333".into(), color_neutral_foreground_disabled: "#5c5c5c".into(), @@ -105,6 +116,7 @@ impl ColorTheme { color_neutral_foreground_2_pressed: "#fff".into(), color_neutral_foreground_2_brand_hover: "#479ef5".into(), color_neutral_foreground_2_brand_pressed: "#2886de".into(), + color_neutral_foreground_2_brand_selected: "#479ef5".into(), color_neutral_foreground_3: "#adadad".into(), color_neutral_foreground_4: "#999999".into(), color_neutral_foreground_on_brand: "#fff".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index a430588..b09ec93 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -51,6 +51,8 @@ pub struct CommonTheme { pub spacing_horizontal_m_nudge: String, pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, + pub spacing_vertical_m_nudge: String, + pub spacing_vertical_l: String, pub duration_ultra_fast: String, pub duration_faster: String, @@ -119,6 +121,8 @@ impl CommonTheme { spacing_horizontal_m_nudge: "10px".into(), spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), + spacing_vertical_m_nudge: "10px".into(), + spacing_vertical_l: "16px".into(), duration_ultra_fast: "50ms".into(), duration_faster: "100ms".into(), From d45f7b908eac7be1d812e94152467c9b2cfbf0da Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sat, 11 May 2024 17:47:33 +0800 Subject: [PATCH 012/143] feat: nav slot --- demo/src/pages/components.rs | 15 ++++++++++++--- thaw/src/nav/nav-drawer.css | 9 +++++++++ thaw/src/nav/nav_drawer.rs | 24 +++++++++++++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 3fd5523..b9571f1 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -58,13 +58,22 @@ pub fn ComponentsPage() -> impl IntoView { - +
{gen_menu_data().into_view()} - + +
diff --git a/thaw/src/nav/nav-drawer.css b/thaw/src/nav/nav-drawer.css index 1ff976f..f43564d 100644 --- a/thaw/src/nav/nav-drawer.css +++ b/thaw/src/nav/nav-drawer.css @@ -23,6 +23,15 @@ /* overflow: auto; */ } +.thaw-nav-drawer__footer { + width: 100%; + max-width: 100%; + padding: 0 var(--spacingVerticalMNudge); + box-sizing: border-box; + position: relative; + z-index: 2; +} + .thaw-nav-item { display: flex; text-transform: none; diff --git a/thaw/src/nav/nav_drawer.rs b/thaw/src/nav/nav_drawer.rs index 91b96b9..e82b06c 100644 --- a/thaw/src/nav/nav_drawer.rs +++ b/thaw/src/nav/nav_drawer.rs @@ -1,24 +1,46 @@ use leptos::*; +use thaw_components::OptionComp; use thaw_utils::{mount_style, Model}; +use crate::Scrollbar; #[component] pub fn NavDrawer( #[prop(optional, into)] selected_value: Model, children: Children, + #[prop(optional)] nav_drawer_header: Option, + #[prop(optional)] nav_drawer_footer: Option, ) -> impl IntoView { mount_style("nav-drawer", include_str!("./nav-drawer.css")); view! {
+ +
{(header.children)()}
+
- {children()} + + {children()} +
+ +
{(footer.children)()}
+
} } +#[slot] +pub struct NavDrawerHeader { + children: Children, +} + +#[slot] +pub struct NavDrawerFooter { + children: Children, +} + #[derive(Clone)] pub(crate) struct NavDrawerInjection(pub Model); From 246c509b297a7f6fb36a1a213de398fc2875527f Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 13 May 2024 17:32:45 +0800 Subject: [PATCH 013/143] refactor: card --- demo/src/components/site_header.rs | 9 ++--- demo/src/pages/components.rs | 11 +----- demo/src/pages/home.rs | 11 ++++-- demo_markdown/docs/card/mod.md | 12 ++++++- thaw/src/card/card-header.css | 25 +++++++++++++ thaw/src/card/card.css | 21 ++++++++--- thaw/src/card/card_header.rs | 39 ++++++++++++++++++++ thaw/src/card/mod.rs | 58 ++++++++++++++++-------------- thaw/src/modal/mod.rs | 2 +- thaw/src/nav/nav-drawer.css | 16 ++++++--- thaw/src/theme/color.rs | 6 ++++ 11 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 thaw/src/card/card-header.css create mode 100644 thaw/src/card/card_header.rs diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index efaa7e0..17d6a7e 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -23,9 +23,7 @@ pub fn SiteHeader() -> impl IntoView { theme.set(Theme::dark()); } }); - let style = create_memo(move |_| { - theme.with(|theme| format!("border-bottom: 1px solid {}", theme.common.border_color)) - }); + let search_value = create_rw_signal(String::new()); let search_all_options = store_value(gen_search_all_options()); let search_options = create_memo(move |_| { @@ -88,6 +86,9 @@ pub fn SiteHeader() -> impl IntoView { align-items: center; justify-content: space-between; padding: 0 20px; + z-index: 1000; + position: relative; + border-bottom: 1px solid var(--colorNeutralStroke2); } .demo-name { cursor: pointer; @@ -124,7 +125,7 @@ pub fn SiteHeader() -> impl IntoView { } " - + impl IntoView { {gen_menu_data().into_view()} - -
diff --git a/demo/src/pages/home.rs b/demo/src/pages/home.rs index 9aa4f9b..3c67f3f 100644 --- a/demo/src/pages/home.rs +++ b/demo/src/pages/home.rs @@ -18,10 +18,15 @@ pub fn Home() -> impl IntoView {

"Thaw UI"

"An easy to use leptos component library"

- + navigate("/components/button", Default::default()); + } + > + "Read the docs" + + + "content" diff --git a/thaw/src/card/card-header.css b/thaw/src/card/card-header.css new file mode 100644 index 0000000..69d477d --- /dev/null +++ b/thaw/src/card/card-header.css @@ -0,0 +1,25 @@ +.thaw-card-header { + display: grid; + grid-auto-columns: min-content 1fr min-content; + align-items: center; + --thaw-card-header--gap: 12px; +} + +.thaw-card-header__header { + grid-row-start: 1; + grid-column-start: 2; + display: flex; +} + +.thaw-card-header__description { + grid-row-start: 2; + grid-column-start: 2; + display: flex; +} + +.thaw-card-header__action { + grid-column-start: 3; + grid-row-start: span 2; + display: flex; + margin-left: var(--thaw-card-header--gap); +} \ No newline at end of file diff --git a/thaw/src/card/card.css b/thaw/src/card/card.css index c461ef2..75bc809 100644 --- a/thaw/src/card/card.css +++ b/thaw/src/card/card.css @@ -1,11 +1,24 @@ .thaw-card { + position: relative; display: flex; flex-direction: column; - border: 1px solid var(--thaw-border-color); - border-radius: 3px; overflow: hidden; - background-color: var(--thaw-background-color); /* moving here so that applying padding to card element works correctly */ + box-sizing: border-box; + max-width: 100%; + width: 720px; + margin: auto; + padding: var(--thaw-card--size); + row-gap: var(--thaw-card--size); + column-gap: var(--thaw-card--size); + + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); + box-shadow: var(--shadow4); + border-radius: var(--borderRadiusMedium); + + --thaw-card--size: 12px; } + .thaw-card__header { font-weight: 600; display: flex; @@ -29,4 +42,4 @@ .thaw-card__header + .thaw-card__content, .thaw-card__footer { padding: 0 28px 20px; -} +} \ No newline at end of file diff --git a/thaw/src/card/card_header.rs b/thaw/src/card/card_header.rs new file mode 100644 index 0000000..f78b8b7 --- /dev/null +++ b/thaw/src/card/card_header.rs @@ -0,0 +1,39 @@ +use leptos::*; +use thaw_components::OptionComp; +use thaw_utils::mount_style; + +#[component] +pub fn CardHeader( + #[prop(optional)] card_header_description: Option, + #[prop(optional)] card_header_action: Option, + children: Children, +) -> impl IntoView { + mount_style("card-header", include_str!("./card-header.css")); + view! { +
+
+ {children()} +
+ +
+ {(description.children)()} +
+
+ +
+ {(action.children)()} +
+
+
+ } +} + +#[slot] +pub struct CardHeaderDescription { + children: Children, +} + +#[slot] +pub struct CardHeaderAction { + children: Children, +} diff --git a/thaw/src/card/mod.rs b/thaw/src/card/mod.rs index 5468546..97d1e94 100644 --- a/thaw/src/card/mod.rs +++ b/thaw/src/card/mod.rs @@ -1,12 +1,15 @@ +mod card_header; + +pub use card_header::*; + use crate::{use_theme, Theme}; use leptos::*; use thaw_components::*; use thaw_utils::{class_list, mount_style, OptionalProp}; - -#[slot] -pub struct CardHeader { - children: Children, -} +// #[slot] +// pub struct CardHeader { +// children: Children, +// } #[slot] pub struct CardHeaderExtra { @@ -23,7 +26,7 @@ pub struct CardFooter { #[component] pub fn Card( #[prop(optional, into)] title: OptionalProp>, - #[prop(optional)] card_header: Option, + // #[prop(optional)] card_header: Option, #[prop(optional)] card_header_extra: Option, #[prop(optional, into)] class: OptionalProp>, children: Children, @@ -51,31 +54,32 @@ pub fn Card(
- {if card_header.is_some() || title.is_some() { - view! { -
-
+ // {if card_header.is_some() || title.is_some() { + // view! { + //
+ //
- {if let Some(header) = card_header { - (header.children)().into_view() - } else if let Some(title) = title.into_option() { - (move || title.get()).into_view() - } else { - unreachable!() - }} + // {if let Some(header) = card_header { + // (header.children)().into_view() + // } else if let Some(title) = title.into_option() { + // (move || title.get()).into_view() + // } else { + // unreachable!() + // }} -
- -
{(header_extra.children)()}
-
-
- } - .into() - } else { - None - }} + //
+ // + //
{(header_extra.children)()}
+ //
+ //
+ // } + // .into() + // } else { + // None + // }}
{children()}
diff --git a/thaw/src/modal/mod.rs b/thaw/src/modal/mod.rs index 396ad7d..d25535d 100644 --- a/thaw/src/modal/mod.rs +++ b/thaw/src/modal/mod.rs @@ -113,7 +113,7 @@ pub fn Modal( style=move || display.get() > - + {move || title.get()} diff --git a/thaw/src/nav/nav-drawer.css b/thaw/src/nav/nav-drawer.css index f43564d..fe931b8 100644 --- a/thaw/src/nav/nav-drawer.css +++ b/thaw/src/nav/nav-drawer.css @@ -2,7 +2,7 @@ overflow: hidden; width: 260px; max-width: 100vw; - height: auto; + height: 100%; /* max-height: 100vh; */ box-sizing: border-box; display: flex; @@ -15,12 +15,18 @@ } .thaw-nav-drawer__body { - padding: 0 var(--spacingVerticalMNudge); - flex: 1 1 0%; + flex: 1; align-self: stretch; position: relative; z-index: 1; - /* overflow: auto; */ + overflow: auto; +} + +.thaw-nav-drawer__body + > .thaw-scrollbar + > .thaw-scrollbar__container + > .thaw-scrollbar__content { + padding: 0 var(--spacingVerticalMNudge); } .thaw-nav-drawer__footer { @@ -67,4 +73,4 @@ background-color: var(--colorNeutralForeground2BrandSelected); border-radius: var(--borderRadiusCircular); margin-inline-start: -18px; -} \ No newline at end of file +} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index bf2cb6d..ea3450b 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -45,6 +45,8 @@ pub struct ColorTheme { pub color_transparent_background: String, pub color_transparent_background_hover: String, pub color_transparent_background_pressed: String, + + pub shadow4: String, } impl ColorTheme { @@ -93,6 +95,8 @@ impl ColorTheme { color_transparent_background: "transparent".into(), color_transparent_background_hover: "transparent".into(), color_transparent_background_pressed: "transparent".into(), + + shadow4: "0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14)".into(), } } @@ -141,6 +145,8 @@ impl ColorTheme { color_transparent_background: "transparent".into(), color_transparent_background_hover: "transparent".into(), color_transparent_background_pressed: "transparent".into(), + + shadow4: "0 0 2px rgba(0,0,0,0.24), 0 2px 4px rgba(0,0,0,0.28)".into(), } } } \ No newline at end of file From 372941b01d64978fc8e5988c3487895327bf8038 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 14 May 2024 14:56:48 +0800 Subject: [PATCH 014/143] refactor: card --- demo_markdown/docs/card/mod.md | 46 +++++++++++-------------- thaw/src/card/card-footer.css | 6 ++++ thaw/src/card/card.css | 7 ++-- thaw/src/card/card_footer.rs | 12 +++++++ thaw/src/card/card_preview.rs | 10 ++++++ thaw/src/card/mod.rs | 62 +++------------------------------- 6 files changed, 56 insertions(+), 87 deletions(-) create mode 100644 thaw/src/card/card-footer.css create mode 100644 thaw/src/card/card_footer.rs create mode 100644 thaw/src/card/card_preview.rs diff --git a/demo_markdown/docs/card/mod.md b/demo_markdown/docs/card/mod.md index 1a1070a..585da00 100644 --- a/demo_markdown/docs/card/mod.md +++ b/demo_markdown/docs/card/mod.md @@ -2,32 +2,26 @@ ```rust demo view! { - - "content" - - "header-extra" - "content" - - - - "Header" - - "Description" - - - - - - "content" - - - "header-extra" - "content" - "footer" - - + + + "Header" + + "Description" + + + + + + + + + + + + + } ``` diff --git a/thaw/src/card/card-footer.css b/thaw/src/card/card-footer.css new file mode 100644 index 0000000..2b36ce3 --- /dev/null +++ b/thaw/src/card/card-footer.css @@ -0,0 +1,6 @@ +.thaw-card-footer { + display: flex; + flex-direction: row; + column-gap: 12px; + row-gap: 12px; +} diff --git a/thaw/src/card/card.css b/thaw/src/card/card.css index 75bc809..6462160 100644 --- a/thaw/src/card/card.css +++ b/thaw/src/card/card.css @@ -19,11 +19,10 @@ --thaw-card--size: 12px; } -.thaw-card__header { - font-weight: 600; - display: flex; - align-items: center; +.thaw-card > .thaw-card-preview { + margin: 0 calc(var(--thaw-card--size)* -1); } + .thaw-card__header-extra { display: flex; align-items: center; diff --git a/thaw/src/card/card_footer.rs b/thaw/src/card/card_footer.rs new file mode 100644 index 0000000..1271f23 --- /dev/null +++ b/thaw/src/card/card_footer.rs @@ -0,0 +1,12 @@ +use leptos::*; +use thaw_utils::mount_style; + +#[component] +pub fn CardFooter(children: Children) -> impl IntoView { + mount_style("card-footer", include_str!("./card-footer.css")); + view! { + + } +} diff --git a/thaw/src/card/card_preview.rs b/thaw/src/card/card_preview.rs new file mode 100644 index 0000000..006be8b --- /dev/null +++ b/thaw/src/card/card_preview.rs @@ -0,0 +1,10 @@ +use leptos::*; + +#[component] +pub fn CardPreview(children: Children) -> impl IntoView { + view! { +
+ {children()} +
+ } +} diff --git a/thaw/src/card/mod.rs b/thaw/src/card/mod.rs index 97d1e94..05529b5 100644 --- a/thaw/src/card/mod.rs +++ b/thaw/src/card/mod.rs @@ -1,15 +1,13 @@ +mod card_footer; mod card_header; +mod card_preview; +pub use card_footer::*; pub use card_header::*; +pub use card_preview::*; -use crate::{use_theme, Theme}; use leptos::*; -use thaw_components::*; use thaw_utils::{class_list, mount_style, OptionalProp}; -// #[slot] -// pub struct CardHeader { -// children: Children, -// } #[slot] pub struct CardHeaderExtra { @@ -26,69 +24,19 @@ pub struct CardFooter { #[component] pub fn Card( #[prop(optional, into)] title: OptionalProp>, - // #[prop(optional)] card_header: Option, #[prop(optional)] card_header_extra: Option, #[prop(optional, into)] class: OptionalProp>, children: Children, #[prop(optional)] card_footer: Option, ) -> impl IntoView { mount_style("card", include_str!("./card.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - // TODO - css_vars.push_str(&format!( - "--thaw-background-color: ;", - // theme.common.background_color - )); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.common.border_color - )); - }); - css_vars - }); view! {
- - // {if card_header.is_some() || title.is_some() { - // view! { - //
- //
- - // {if let Some(header) = card_header { - // (header.children)().into_view() - // } else if let Some(title) = title.into_option() { - // (move || title.get()).into_view() - // } else { - // unreachable!() - // }} - - //
- // - //
{(header_extra.children)()}
- //
- //
- // } - // .into() - // } else { - // None - // }} - -
{children()}
- - - - - - - + {children()}
} } From eeff259208f6256e102eb7e121432efaa069d1e1 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 14 May 2024 17:39:13 +0800 Subject: [PATCH 015/143] feat: text --- demo_markdown/docs/card/mod.md | 4 +- thaw/src/lib.rs | 3 +- thaw/src/text/mod.rs | 89 ++++++++++++++++++++++++++++++++-- thaw/src/text/text.css | 30 ++++++++++++ thaw/src/theme/mod.rs | 12 ++--- thaw/src/typography/mod.rs | 5 -- thaw/src/typography/text.css | 9 ---- thaw/src/typography/text.rs | 38 --------------- thaw/src/typography/theme.rs | 20 -------- thaw_utils/src/class_list.rs | 49 ++++++++++++++++++- 10 files changed, 171 insertions(+), 88 deletions(-) create mode 100644 thaw/src/text/text.css delete mode 100644 thaw/src/typography/mod.rs delete mode 100644 thaw/src/typography/text.css delete mode 100644 thaw/src/typography/text.rs delete mode 100644 thaw/src/typography/theme.rs diff --git a/demo_markdown/docs/card/mod.md b/demo_markdown/docs/card/mod.md index 585da00..0f8d937 100644 --- a/demo_markdown/docs/card/mod.md +++ b/demo_markdown/docs/card/mod.md @@ -4,9 +4,9 @@ view! { - "Header" + "Header" - "Description" + "Description" +
+ +
+ {children()} +
+
+
+ } +} + +#[slot] +pub struct AccordionHeader { + children: Children, +} + +#[slot] +pub struct AccordionPanel { + children: Children, +} diff --git a/thaw/src/accordion/mod.rs b/thaw/src/accordion/mod.rs new file mode 100644 index 0000000..da0e7e9 --- /dev/null +++ b/thaw/src/accordion/mod.rs @@ -0,0 +1,43 @@ +mod accordion_item; + +pub use accordion_item::*; + +use leptos::*; +use std::collections::HashSet; +use thaw_utils::Model; + +#[component] +pub fn Accordion( + /// Controls the state of the panel. + #[prop(optional, into)] open_items: Model>, + /// Indicates if Accordion support multiple Panels opened at the same time. + #[prop(optional)] multiple: bool, + /// Indicates if Accordion support multiple Panels closed at the same time. + #[prop(optional)] collapsible: bool, + children: Children, +) -> impl IntoView { + view! { + +
+ {children()} +
+
+ } +} + +#[derive(Clone)] +pub(crate) struct AccordionInjection { + pub open_items: Model>, + pub multiple: bool, + pub collapsible: bool, +} + +impl AccordionInjection { + pub fn use_() -> AccordionInjection { + expect_context() + } +} diff --git a/thaw/src/collapse/collapse.css b/thaw/src/collapse/collapse.css deleted file mode 100644 index 7dca169..0000000 --- a/thaw/src/collapse/collapse.css +++ /dev/null @@ -1,55 +0,0 @@ -.thaw-collapse .thaw-collapse-item:not(:first-child) { - margin-top: 16px; - border-top: 1px solid var(--thaw-border-color); -} - -.thaw-collapse-item__header { - display: flex; - align-items: center; - cursor: pointer; -} - -.thaw-collapse - .thaw-collapse-item:not(:first-child) - .thaw-collapse-item__header { - padding-top: 16px; -} - -.thaw-collapse-item-arrow { - margin-right: 4px; - transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-collapse-item--active .thaw-collapse-item-arrow { - transform: rotate(90deg); -} - -.thaw-collapse-item__content { - padding-top: 16px; -} - -.thaw-collapse-item-enter-from, -.thaw-collapse-item-enter-to { - opacity: 1; -} - -.thaw-collapse-item-leave-to, -.thaw-collapse-item-enter-from { - opacity: 0; - padding-top: 0; - max-height: 0; -} - -.thaw-collapse-item-leave-active { - overflow: hidden; - transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s, - opacity 0.15s cubic-bezier(0, 0, 0.2, 1) 0s, - padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s; -} - -.thaw-collapse-item-enter-active { - overflow: hidden; - transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.15s cubic-bezier(0.4, 0, 1, 1), - padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1); -} diff --git a/thaw/src/collapse/collapse_item.rs b/thaw/src/collapse/collapse_item.rs deleted file mode 100644 index 18f8ca8..0000000 --- a/thaw/src/collapse/collapse_item.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::use_collapse; -use crate::Icon; -use leptos::*; -use thaw_components::CSSTransition; -use thaw_utils::{class_list, OptionalProp, StoredMaybeSignal}; - -#[component] -pub fn CollapseItem( - #[prop(optional, into)] class: OptionalProp>, - #[prop(into)] title: MaybeSignal, - #[prop(into)] key: MaybeSignal, - children: Children, -) -> impl IntoView { - let collapse = use_collapse(); - let key: StoredMaybeSignal<_> = key.into(); - let content_ref = create_node_ref::(); - - let is_show_content = create_memo(move |_| { - collapse - .value - .with(|keys| key.with(|key| keys.contains(key))) - }); - - let on_click = move |_| { - collapse.value.update(|keys| { - if collapse.accordion { - keys.clear(); - } - let key = key.get_untracked(); - if is_show_content.get_untracked() { - keys.remove(&key); - } else { - keys.insert(key); - } - }); - }; - - view! { -
-
- - {move || title.get()} -
- -
- {children()} -
-
-
- } -} diff --git a/thaw/src/collapse/mod.rs b/thaw/src/collapse/mod.rs deleted file mode 100644 index a99d1ff..0000000 --- a/thaw/src/collapse/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -mod collapse_item; -mod theme; - -pub use collapse_item::CollapseItem; -pub use theme::CollapseTheme; - -use crate::{use_theme, Theme}; -use leptos::*; -use std::collections::HashSet; -use thaw_utils::{class_list, mount_style, Model, OptionalProp}; - -#[component] -pub fn Collapse( - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] value: Model>, - #[prop(optional)] accordion: bool, - children: Children, -) -> impl IntoView { - mount_style("collapser", include_str!("./collapse.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - theme.with(|theme| format!("--thaw-border-color: {};", theme.collapse.border_color)) - }); - - view! { - -
- {children()} -
-
- } -} - -#[derive(Clone)] -pub(crate) struct CollapseInjection { - pub value: Model>, - pub accordion: bool, -} - -pub(crate) fn use_collapse() -> CollapseInjection { - expect_context() -} diff --git a/thaw/src/collapse/theme.rs b/thaw/src/collapse/theme.rs deleted file mode 100644 index 386bc22..0000000 --- a/thaw/src/collapse/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct CollapseTheme { - pub border_color: String, -} - -impl ThemeMethod for CollapseTheme { - fn light() -> Self { - Self { - border_color: "#efeff5".into(), - } - } - - fn dark() -> Self { - Self { - border_color: "#ffffff17".into(), - } - } -} diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index ef84b85..1ea8c51 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -1,3 +1,4 @@ +mod accordion; mod alert; mod anchor; mod auto_complete; @@ -10,7 +11,6 @@ mod calendar; mod card; mod checkbox; mod code; -mod collapse; mod color_picker; mod config_provider; mod date_picker; @@ -46,6 +46,7 @@ mod theme; mod time_picker; mod upload; +pub use accordion::*; pub use alert::*; pub use anchor::*; pub use auto_complete::*; @@ -58,7 +59,6 @@ pub use calendar::*; pub use card::*; pub use checkbox::*; pub use code::*; -pub use collapse::*; pub use color_picker::*; pub use config_provider::*; pub use date_picker::*; diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index f983366..51650c8 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -5,9 +5,9 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, - CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, - PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, - SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, + ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, + ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme, + SwitchTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -44,7 +44,6 @@ pub struct Theme { pub time_picker: TimePickerTheme, pub date_picker: DatePickerTheme, pub popover: PopoverTheme, - pub collapse: CollapseTheme, pub scrollbar: ScrollbarTheme, pub back_top: BackTopTheme, pub anchor: AnchorTheme, @@ -78,7 +77,6 @@ impl Theme { time_picker: TimePickerTheme::light(), date_picker: DatePickerTheme::light(), popover: PopoverTheme::light(), - collapse: CollapseTheme::light(), scrollbar: ScrollbarTheme::light(), back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), @@ -111,7 +109,6 @@ impl Theme { time_picker: TimePickerTheme::dark(), date_picker: DatePickerTheme::dark(), popover: PopoverTheme::dark(), - collapse: CollapseTheme::dark(), scrollbar: ScrollbarTheme::dark(), back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(), From f178d7c9ca5ea5ada19f6506f484a4424d771c10 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 16 May 2024 16:18:36 +0800 Subject: [PATCH 017/143] feat: clear code --- demo/src/pages/components.rs | 5 ++--- demo_markdown/docs/card/mod.md | 4 +++- thaw/src/card/card.css | 20 -------------------- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 7bff405..65ac9b8 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -83,9 +83,9 @@ impl IntoView for MenuGroupOption { let Self { label, children } = self; let children_len = children.len(); view! { - + {format!("{label} ({children_len})")} - + {children.into_iter().map(|v| v.into_view()).collect_view()} }.into_view() } @@ -99,7 +99,6 @@ pub(crate) struct MenuItemOption { impl IntoView for MenuItemOption { fn into_view(self) -> View { let Self { label, value } = self; - // key=value label view! { {label} } } } diff --git a/demo_markdown/docs/card/mod.md b/demo_markdown/docs/card/mod.md index 0f8d937..ba6962f 100644 --- a/demo_markdown/docs/card/mod.md +++ b/demo_markdown/docs/card/mod.md @@ -4,7 +4,9 @@ view! { - "Header" + + "Header""2022-02-22" + "Description" diff --git a/thaw/src/card/card.css b/thaw/src/card/card.css index 6462160..b3b23c5 100644 --- a/thaw/src/card/card.css +++ b/thaw/src/card/card.css @@ -22,23 +22,3 @@ .thaw-card > .thaw-card-preview { margin: 0 calc(var(--thaw-card--size)* -1); } - -.thaw-card__header-extra { - display: flex; - align-items: center; -} -.thaw-card__header-content { - flex: 1; -} -.thaw-card__header, -.thaw-card__content, -.thaw-card__footer { - padding: 12px 28px; -} -.thaw-card__header { - padding: 20px 28px; -} -.thaw-card__header + .thaw-card__content, -.thaw-card__footer { - padding: 0 28px 20px; -} \ No newline at end of file From a0db94378a74a7c553e2147daa24fb9750ee7f6b Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 17 May 2024 17:34:24 +0800 Subject: [PATCH 018/143] feat: checkbox --- thaw/src/checkbox/checkbox.css | 96 +++++++++++++++++++++++++++------- thaw/src/checkbox/mod.rs | 19 ++----- thaw/src/theme/common.rs | 4 ++ 3 files changed, 83 insertions(+), 36 deletions(-) diff --git a/thaw/src/checkbox/checkbox.css b/thaw/src/checkbox/checkbox.css index ee1e6fa..477d5b4 100644 --- a/thaw/src/checkbox/checkbox.css +++ b/thaw/src/checkbox/checkbox.css @@ -1,33 +1,89 @@ .thaw-checkbox { + position: relative; display: inline-flex; - align-items: center; + vertical-align: middle; + color: var(--colorNeutralForeground3); cursor: pointer; } +.thaw-checkbox--checked { + --thaw-checkbox__indicator--background-color: var( + --colorCompoundBrandBackground + ); + --thaw-checkbox__indicator--color: var(--colorNeutralForegroundInverted); + --thaw-checkbox__indicator--border-color: var( + --colorCompoundBrandBackground + ); +} + +.thaw-checkbox:hover { + color: var(--colorNeutralForeground2); + + --thaw-checkbox__indicator--border-color: var( + --colorNeutralStrokeAccessibleHover + ); +} + +.thaw-checkbox:active { + color: var(--colorNeutralForeground1); + + --thaw-checkbox__indicator--border-color: var( + --colorNeutralStrokeAccessiblePressed + ); +} + +.thaw-checkbox:focus, +.thaw-checkbox:focus-visible { + outline-style: none; +} + .thaw-checkbox__input { - width: 0; - height: 0; + position: absolute; + top: 0px; + left: 0px; + width: calc(16px + 2 * var(--spacingHorizontalS)); + height: 100%; + margin: 0px; opacity: 0; + box-sizing: border-box; + cursor: inherit; } -.thaw-checkbox__dot { - display: inline-flex; - justify-content: center; + +.thaw-checkbox__indicator { + align-self: flex-start; + flex-shrink: 0; + display: flex; align-items: center; - width: 14px; - height: 14px; - border: 1px solid #ddd; - border-radius: 2px; -} -.thaw-checkbox:hover .thaw-checkbox__dot, -.thaw-checkbox--checked .thaw-checkbox__dot { - border-color: var(--thaw-background-color-checked); -} -.thaw-checkbox--checked .thaw-checkbox__dot { - background-color: var(--thaw-background-color-checked); + justify-content: center; + margin: var(--spacingVerticalS) var(--spacingHorizontalS); + height: 16px; + width: 16px; + background-color: var(--thaw-checkbox__indicator--background-color); + font-size: 12px; + color: var(--thaw-checkbox__indicator--color); + border-color: var( + --thaw-checkbox__indicator--border-color, + var(--colorNeutralStrokeAccessible) + ); + border-style: solid; + border-width: var(--strokeWidthThin); + border-radius: var(--borderRadiusSmall); + fill: currentcolor; + box-sizing: border-box; + pointer-events: none; + overflow: hidden; } .thaw-checkbox__label { - display: inline-block; - padding: 0 6px; - user-select: none; + align-self: center; + margin-bottom: calc((16px - var(--lineHeightBase300)) / 2); + margin-top: calc((16px - var(--lineHeightBase300)) / 2); + padding-bottom: var(--spacingVerticalS); + padding-top: var(--spacingVerticalS); + padding-left: var(--spacingHorizontalXS); + padding-right: var(--spacingHorizontalS); + line-height: var(--lineHeightBase300); + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + color: inherit; } diff --git a/thaw/src/checkbox/mod.rs b/thaw/src/checkbox/mod.rs index 41058b8..e5c307f 100644 --- a/thaw/src/checkbox/mod.rs +++ b/thaw/src/checkbox/mod.rs @@ -4,7 +4,7 @@ mod checkbox_item; pub use checkbox_group::CheckboxGroup; pub use checkbox_item::CheckboxItem; -use crate::{icon::*, theme::use_theme, Theme}; +use crate::icon::*; use leptos::*; use thaw_components::*; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; @@ -15,20 +15,8 @@ pub fn Checkbox( #[prop(optional, into)] class: OptionalProp>, #[prop(optional)] children: Option, ) -> impl IntoView { - let theme = use_theme(Theme::light); mount_style("checkbox", include_str!("./checkbox.css")); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color-checked: {};", - theme.common.color_primary - )); - }); - css_vars - }); - view! {
-
+
@@ -48,7 +35,7 @@ pub fn Checkbox(
-
{children()}
+
} diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index b09ec93..ca6bf22 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -46,11 +46,13 @@ pub struct CommonTheme { pub border_radius_circular: String, pub spacing_horizontal_x_x_s: String, + pub spacing_horizontal_x_s: String, pub spacing_horizontal_s_nudge: String, pub spacing_horizontal_s: String, pub spacing_horizontal_m_nudge: String, pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, + pub spacing_vertical_s: String, pub spacing_vertical_m_nudge: String, pub spacing_vertical_l: String, @@ -116,11 +118,13 @@ impl CommonTheme { border_radius_circular: "10000px".into(), spacing_horizontal_x_x_s: "2px".into(), + spacing_horizontal_x_s: "4px".into(), spacing_horizontal_s_nudge: "6px".into(), spacing_horizontal_s: "8px".into(), spacing_horizontal_m_nudge: "10px".into(), spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), + spacing_vertical_s: "8px".into(), spacing_vertical_m_nudge: "10px".into(), spacing_vertical_l: "16px".into(), From ec351e7ba1bc66dd5a74f28dac714b03689c258f Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 20 May 2024 17:47:09 +0800 Subject: [PATCH 019/143] feat: checkbox theme --- thaw/src/checkbox/checkbox.css | 40 +++++++++++++++++++++++++--------- thaw/src/theme/color.rs | 12 ++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/thaw/src/checkbox/checkbox.css b/thaw/src/checkbox/checkbox.css index 477d5b4..3eb7bc5 100644 --- a/thaw/src/checkbox/checkbox.css +++ b/thaw/src/checkbox/checkbox.css @@ -6,16 +6,6 @@ cursor: pointer; } -.thaw-checkbox--checked { - --thaw-checkbox__indicator--background-color: var( - --colorCompoundBrandBackground - ); - --thaw-checkbox__indicator--color: var(--colorNeutralForegroundInverted); - --thaw-checkbox__indicator--border-color: var( - --colorCompoundBrandBackground - ); -} - .thaw-checkbox:hover { color: var(--colorNeutralForeground2); @@ -32,6 +22,36 @@ ); } +.thaw-checkbox--checked { + color: var(--colorNeutralForeground1); + + --thaw-checkbox__indicator--background-color: var( + --colorCompoundBrandBackground + ); + --thaw-checkbox__indicator--color: var(--colorNeutralForegroundInverted); + --thaw-checkbox__indicator--border-color: var( + --colorCompoundBrandBackground + ); +} + +.thaw-checkbox--checked:hover { + --thaw-checkbox__indicator--border-color: var( + --colorCompoundBrandBackgroundHover + ); + --thaw-checkbox__indicator--background-color: var( + --colorCompoundBrandBackgroundHover + ); +} + +.thaw-checkbox--checked:active { + --thaw-checkbox__indicator--border-color: var( + --colorCompoundBrandBackgroundPressed + ); + --thaw-checkbox__indicator--background-color: var( + --colorCompoundBrandBackgroundPressed + ); +} + .thaw-checkbox:focus, .thaw-checkbox:focus-visible { outline-style: none; diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index ea3450b..185b61e 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -24,6 +24,7 @@ pub struct ColorTheme { pub color_neutral_foreground_3: String, pub color_neutral_foreground_4: String, pub color_neutral_foreground_on_brand: String, + pub color_neutral_foreground_inverted: String, pub color_neutral_stroke_disabled: String, pub color_neutral_stroke_1: String, @@ -34,6 +35,9 @@ pub struct ColorTheme { pub color_neutral_stroke_accessible_hover: String, pub color_neutral_stroke_accessible_pressed: String, + pub color_compound_brand_background: String, + pub color_compound_brand_background_hover: String, + pub color_compound_brand_background_pressed: String, pub color_compound_brand_stroke: String, pub color_brand_background: String, @@ -74,6 +78,7 @@ impl ColorTheme { color_neutral_foreground_3: "#616161".into(), color_neutral_foreground_4: "#707070".into(), color_neutral_foreground_on_brand: "#fff".into(), + color_neutral_foreground_inverted: "#fff".into(), color_neutral_stroke_disabled: "#e0e0e0".into(), color_neutral_stroke_1: "#d1d1d1".into(), @@ -84,6 +89,9 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#575757".into(), color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), + color_compound_brand_background: "#0f6cbd".into(), + color_compound_brand_background_hover: "#115ea3".into(), + color_compound_brand_background_pressed: "#0f548c".into(), color_compound_brand_stroke: "#0f6cbd".into(), color_brand_background: "#0f6cbd".into(), @@ -124,6 +132,7 @@ impl ColorTheme { color_neutral_foreground_3: "#adadad".into(), color_neutral_foreground_4: "#999999".into(), color_neutral_foreground_on_brand: "#fff".into(), + color_neutral_foreground_inverted: "#242424".into(), color_neutral_stroke_disabled: "#424242".into(), color_neutral_stroke_1: "#666666".into(), @@ -134,6 +143,9 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#bdbdbd".into(), color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), + color_compound_brand_background: "#479ef5".into(), + color_compound_brand_background_hover: "#62abf5".into(), + color_compound_brand_background_pressed: "#2886de".into(), color_compound_brand_stroke: "#479ef5".into(), color_brand_background: "#115ea3".into(), From be91dcbf6ae6277382876acedf53130aa5e70239 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 21 May 2024 17:25:22 +0800 Subject: [PATCH 020/143] feat: checkbox checked --- demo_markdown/docs/checkbox/mod.md | 12 ++++----- thaw/src/checkbox/checkbox.css | 1 + thaw/src/checkbox/checkbox_group.rs | 14 +++++++--- thaw/src/checkbox/checkbox_item.rs | 24 ++++++++--------- thaw/src/checkbox/mod.rs | 42 ++++++++++++++++++++--------- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/demo_markdown/docs/checkbox/mod.md b/demo_markdown/docs/checkbox/mod.md index e1eb6fd..0e26a48 100644 --- a/demo_markdown/docs/checkbox/mod.md +++ b/demo_markdown/docs/checkbox/mod.md @@ -1,10 +1,10 @@ # Checkbox ```rust demo -let value = create_rw_signal(false); +let checked = RwSignal::new(false); view! { - "Click" + "Click" } ``` @@ -14,13 +14,13 @@ view! { ```rust demo use std::collections::HashSet; -let value = create_rw_signal(HashSet::new()); +let value = RwSignal::new(HashSet::new()); view! { - - - + + +
"value: " {move || format!("{:?}", value.get())}
} diff --git a/thaw/src/checkbox/checkbox.css b/thaw/src/checkbox/checkbox.css index 3eb7bc5..a7a3501 100644 --- a/thaw/src/checkbox/checkbox.css +++ b/thaw/src/checkbox/checkbox.css @@ -106,4 +106,5 @@ font-family: var(--fontFamilyBase); font-size: var(--fontSizeBase300); color: inherit; + cursor: inherit; } diff --git a/thaw/src/checkbox/checkbox_group.rs b/thaw/src/checkbox/checkbox_group.rs index 9082359..44bed97 100644 --- a/thaw/src/checkbox/checkbox_group.rs +++ b/thaw/src/checkbox/checkbox_group.rs @@ -7,12 +7,20 @@ pub fn CheckboxGroup( #[prop(optional, into)] value: Model>, children: Children, ) -> impl IntoView { - view! { } + view! { + +
+ {children()} +
+
+ } } #[derive(Clone)] pub(crate) struct CheckboxGroupInjection(pub Model>); -pub(crate) fn use_checkbox_group() -> CheckboxGroupInjection { - expect_context() +impl CheckboxGroupInjection { + pub fn use_() -> Self { + expect_context() + } } diff --git a/thaw/src/checkbox/checkbox_item.rs b/thaw/src/checkbox/checkbox_item.rs index 8c5179f..e5812fc 100644 --- a/thaw/src/checkbox/checkbox_item.rs +++ b/thaw/src/checkbox/checkbox_item.rs @@ -1,4 +1,4 @@ -use crate::checkbox::{checkbox_group::use_checkbox_group, Checkbox}; +use super::{checkbox_group::CheckboxGroupInjection, Checkbox}; use leptos::*; use thaw_utils::OptionalProp; @@ -6,39 +6,39 @@ use thaw_utils::OptionalProp; pub fn CheckboxItem( #[prop(optional, into)] label: Option, #[prop(optional, into)] class: OptionalProp>, - #[prop(into)] key: String, + #[prop(into)] value: String, ) -> impl IntoView { - let checkbox_group_value = use_checkbox_group().0; + let group_value = CheckboxGroupInjection::use_().0; let checked = RwSignal::new(false); - let item_key = StoredValue::new(key); + let item_value = StoredValue::new(value); let is_checked = Memo::new(move |_| { - checkbox_group_value.with(|value| item_key.with_value(|key| value.contains(key))) + group_value.with(|group_value| item_value.with_value(|value| group_value.contains(value))) }); Effect::new(move |_| { checked.track(); if is_checked.get_untracked() { - checkbox_group_value.update(move |value| { - item_key.with_value(|key| { - value.remove(key); + group_value.update(move |group_value| { + item_value.with_value(|value| { + group_value.remove(value); }); }); } else if checked.get_untracked() { - checkbox_group_value.update(move |value| { - value.insert(item_key.get_value()); + group_value.update(move |group_value| { + group_value.insert(item_value.get_value()); }); } }); if let Some(label) = label { view! { - + {label} } } else { - view! { } + view! { } } } diff --git a/thaw/src/checkbox/mod.rs b/thaw/src/checkbox/mod.rs index e5c307f..b3ece84 100644 --- a/thaw/src/checkbox/mod.rs +++ b/thaw/src/checkbox/mod.rs @@ -4,38 +4,56 @@ mod checkbox_item; pub use checkbox_group::CheckboxGroup; pub use checkbox_item::CheckboxItem; -use crate::icon::*; use leptos::*; use thaw_components::*; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; #[component] pub fn Checkbox( - #[prop(optional, into)] value: Model, + #[prop(optional, into)] checked: Model, #[prop(optional, into)] class: OptionalProp>, #[prop(optional)] children: Option, ) -> impl IntoView { mount_style("checkbox", include_str!("./checkbox.css")); + let id = uuid::Uuid::new_v4().to_string(); + let input_ref = NodeRef::::new(); + + let on_change = move |_| { + let input = input_ref.get_untracked().unwrap(); + checked.set(input.checked()) + }; + view! {
- +
- - - - - + { + move || if checked.get() { + view! { + + }.into() + } else { + None + } + }
- +
} From 7d99f9bd0971a139c89663712ca1b714fc1ad176 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 22 May 2024 17:28:20 +0800 Subject: [PATCH 021/143] feat: SpinButton --- demo/src/app.rs | 1 + demo/src/pages/components.rs | 4 + demo_markdown/docs/spin_button/mod.md | 13 +++ demo_markdown/src/lib.rs | 1 + thaw/src/calendar/mod.rs | 2 +- thaw/src/input/input.css | 2 +- thaw/src/lib.rs | 2 + thaw/src/spin_button/mod.rs | 110 +++++++++++++++++++++++ thaw/src/spin_button/spin-button.css | 123 ++++++++++++++++++++++++++ thaw/src/theme/color.rs | 3 + 10 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 demo_markdown/docs/spin_button/mod.md create mode 100644 thaw/src/spin_button/mod.rs create mode 100644 thaw/src/spin_button/spin-button.css diff --git a/demo/src/app.rs b/demo/src/app.rs index 053d00c..fd2a8d9 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -80,6 +80,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 65ac9b8..af96c43 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -140,6 +140,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "typography".into(), label: "Typography".into(), }, + MenuItemOption { + value: "spin-button".into(), + label: "Spin Button".into(), + }, ], }, MenuGroupOption { diff --git a/demo_markdown/docs/spin_button/mod.md b/demo_markdown/docs/spin_button/mod.md new file mode 100644 index 0000000..8204702 --- /dev/null +++ b/demo_markdown/docs/spin_button/mod.md @@ -0,0 +1,13 @@ +# SpinButton + +```rust demo +let value = RwSignal::new(0); +let value_f64 = RwSignal::new(0.0); + +view! { + + + + +} +``` \ No newline at end of file diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 63fb01d..c1a78ee 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -62,6 +62,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "SkeletonMdPage" => "../docs/skeleton/mod.md", "SliderMdPage" => "../docs/slider/mod.md", "SpaceMdPage" => "../docs/space/mod.md", + "SpinButtonMdPage" => "../docs/spin_button/mod.md", "SpinnerMdPage" => "../docs/spinner/mod.md", "SwitchMdPage" => "../docs/switch/mod.md", "TableMdPage" => "../docs/table/mod.md", diff --git a/thaw/src/calendar/mod.rs b/thaw/src/calendar/mod.rs index 24c265f..98efb6f 100644 --- a/thaw/src/calendar/mod.rs +++ b/thaw/src/calendar/mod.rs @@ -2,7 +2,7 @@ mod theme; pub use theme::CalendarTheme; -use crate::{use_theme, Button, ButtonGroup, ButtonAppearance, Theme}; +use crate::{use_theme, Button, ButtonGroup, Theme}; use chrono::{Datelike, Days, Local, Month, Months, NaiveDate}; use leptos::*; use std::ops::Deref; diff --git a/thaw/src/input/input.css b/thaw/src/input/input.css index ec9adca..aa9ae1d 100644 --- a/thaw/src/input/input.css +++ b/thaw/src/input/input.css @@ -58,7 +58,7 @@ transition-delay: var(--curveDecelerateMid); } -.r1qp7m7v:focus-within:active::after { +.thaw-input:focus-within:active::after { border-bottom-color: var(--colorCompoundBrandStrokePressed); } diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 1ea8c51..9b4455d 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -36,6 +36,7 @@ mod select; mod skeleton; mod slider; mod space; +mod spin_button; mod spinner; mod switch; mod table; @@ -83,6 +84,7 @@ pub use select::*; pub use skeleton::*; pub use slider::*; pub use space::*; +pub use spin_button::*; pub use spinner::*; pub use switch::*; pub use table::*; diff --git a/thaw/src/spin_button/mod.rs b/thaw/src/spin_button/mod.rs new file mode 100644 index 0000000..e6aa277 --- /dev/null +++ b/thaw/src/spin_button/mod.rs @@ -0,0 +1,110 @@ +use leptos::*; +use num_traits::Bounded; +use std::ops::{Add, Sub}; +use std::str::FromStr; +use thaw_utils::{mount_style, Model, StoredMaybeSignal}; + +#[component] +pub fn SpinButton( + #[prop(optional, into)] value: Model, + #[prop(into)] step_page: MaybeSignal, + #[prop(default = T::min_value().into(), into)] min: MaybeSignal, + #[prop(default = T::max_value().into(), into)] max: MaybeSignal, + #[prop(optional, into)] disabled: MaybeSignal, +) -> impl IntoView +where + T: Add + Sub + PartialOrd + Bounded, + T: Default + Clone + FromStr + ToString + 'static, +{ + mount_style("spin-button", include_str!("./spin-button.css")); + + let initialization_value = value.get_untracked().to_string(); + let step_page: StoredMaybeSignal<_> = step_page.into(); + let min: StoredMaybeSignal<_> = min.into(); + let max: StoredMaybeSignal<_> = max.into(); + let input_value = RwSignal::new(String::new()); + + Effect::new_isomorphic(move |prev| { + value.with(|value| { + if let Some(prev) = prev { + if value == &prev { + return prev; + } + } + input_value.set(value.to_string()); + value.clone() + }) + }); + + let update_value = move |new_value| { + let min = min.get_untracked(); + let max = max.get_untracked(); + if new_value < min { + value.set(min); + } else if new_value > max { + value.set(max); + } else if with!(|value| value != &new_value) { + value.set(new_value); + } + }; + + let increment_disabled = Memo::new(move |_| disabled.get() || value.get() <= min.get()); + let decrement_disabled = Memo::new(move |_| disabled.get() || value.get() >= max.get()); + + view! { + + () else { + input_value.update(|_| {}); + return; + }; + update_value(v); + } + /> + + + + } +} diff --git a/thaw/src/spin_button/spin-button.css b/thaw/src/spin_button/spin-button.css new file mode 100644 index 0000000..190ed33 --- /dev/null +++ b/thaw/src/spin_button/spin-button.css @@ -0,0 +1,123 @@ +.thaw-spin-button { + display: inline-grid; + grid-template-columns: 1fr 24px; + grid-template-rows: 1fr 1fr; + column-gap: var(--spacingHorizontalXS); + row-gap: 0px; + position: relative; + isolation: isolate; + background-color: var(--colorNeutralBackground1); + min-height: 32px; + padding: 0 0 0 var(--spacingHorizontalMNudge); + + border: 1px solid var(--colorNeutralStroke1); + border-bottom-color: var(--colorNeutralStrokeAccessible); + border-radius: var(--borderRadiusMedium); +} + +.thaw-spin-button:hover { + border-color: var(--colorNeutralStroke1Hover); + border-bottom-color: var(--colorNeutralStrokeAccessibleHover); +} + +.thaw-spin-button:focus-within { + outline: transparent solid 2px; +} + +.thaw-spin-button:active, +.thaw-spin-button:focus-within { + border-color: var(--colorNeutralStroke1Pressed); + border-bottom-color: var(--colorNeutralStrokeAccessiblePressed); +} + +.thaw-spin-button::after { + box-sizing: border-box; + content: ""; + position: absolute; + left: -1px; + bottom: -1px; + right: -1px; + height: max(2px, var(--borderRadiusMedium)); + border-bottom-left-radius: var(--borderRadiusMedium); + border-bottom-right-radius: var(--borderRadiusMedium); + border-bottom: 2px solid var(--colorCompoundBrandStroke); + clip-path: inset(calc(100% - 2px) 0px 0px); + transform: scaleX(0); + transition-property: transform; + transition-duration: var(--durationUltraFast); + transition-delay: var(--curveAccelerateMid); +} + +.thaw-spin-button:focus-within::after { + transform: scaleX(1); + transition-property: transform; + transition-duration: var(--durationNormal); + transition-delay: var(--curveDecelerateMid); +} + +.thaw-spin-button:focus-within:active::after { + border-bottom-color: var(--colorCompoundBrandStrokePressed); +} + +.thaw-spin-button__input { + grid-area: 1 / 1 / 3 / 2; + outline-style: none; + border: 0px; + padding: 0px; + color: var(--colorNeutralForeground1); + background-color: transparent; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: inherit; + width: 100%; +} + +.thaw-spin-button__increment-button, +.thaw-spin-button__decrement-button { + display: inline-flex; + width: 24px; + align-items: center; + justify-content: center; + border: 0px; + position: absolute; + outline-style: none; + height: 16px; + background-color: transparent; + color: var(--colorNeutralForeground3); + grid-column-start: 2; + border-radius: 0px; + padding: 0px 5px; +} + +.thaw-spin-button__increment-button:enabled:hover, +.thaw-spin-button__decrement-button:enabled:hover { + cursor: pointer; + color: var(--colorNeutralForeground3Hover); + background-color: var(--colorSubtleBackgroundHover); +} + +.thaw-spin-button__increment-button:enabled:active, +.thaw-spin-button__decrement-button:enabled:active { + color: var(--colorNeutralForeground3Pressed); + background-color: var(--colorSubtleBackgroundPressed); +} + +.thaw-spin-button__increment-button:active, +.thaw-spin-button__decrement-button:active { + outline-style: none; +} + +.thaw-spin-button__increment-button { + grid-row-start: 1; + padding-top: 4px; + padding-bottom: 1px; + border-top-right-radius: var(--borderRadiusMedium); +} + +.thaw-spin-button__decrement-button { + padding-bottom: 4px; + padding-top: 1px; + grid-row-start: 2; + border-bottom-right-radius: var(--borderRadiusMedium); +} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 185b61e..aa07a79 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -39,6 +39,7 @@ pub struct ColorTheme { pub color_compound_brand_background_hover: String, pub color_compound_brand_background_pressed: String, pub color_compound_brand_stroke: String, + pub color_compound_brand_stroke_pressed: String, pub color_brand_background: String, pub color_brand_background_hover: String, @@ -93,6 +94,7 @@ impl ColorTheme { color_compound_brand_background_hover: "#115ea3".into(), color_compound_brand_background_pressed: "#0f548c".into(), color_compound_brand_stroke: "#0f6cbd".into(), + color_compound_brand_stroke_pressed: "#0f548c".into(), color_brand_background: "#0f6cbd".into(), color_brand_background_hover: "#115ea3".into(), @@ -147,6 +149,7 @@ impl ColorTheme { color_compound_brand_background_hover: "#62abf5".into(), color_compound_brand_background_pressed: "#2886de".into(), color_compound_brand_stroke: "#479ef5".into(), + color_compound_brand_stroke_pressed: "#2886de".into(), color_brand_background: "#115ea3".into(), color_brand_background_hover: "#0f6cbd".into(), From 97263ec80ddf8a336e8a40d6de08109bf57923f9 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 22 May 2024 23:17:27 +0800 Subject: [PATCH 022/143] feat: SpinButton disabled --- demo_markdown/docs/spin_button/mod.md | 22 +++++++++++++++++++- thaw/src/spin_button/mod.rs | 7 +++++-- thaw/src/spin_button/spin-button.css | 30 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/demo_markdown/docs/spin_button/mod.md b/demo_markdown/docs/spin_button/mod.md index 8204702..1374443 100644 --- a/demo_markdown/docs/spin_button/mod.md +++ b/demo_markdown/docs/spin_button/mod.md @@ -7,7 +7,27 @@ let value_f64 = RwSignal::new(0.0); view! { - + } +``` + +### Min / Max + +```rust demo +let value = RwSignal::new(0); + +view! { + +} +``` + +### Disabled + +```rust demo +let value = RwSignal::new(0); + +view! { + +} ``` \ No newline at end of file diff --git a/thaw/src/spin_button/mod.rs b/thaw/src/spin_button/mod.rs index e6aa277..41d068d 100644 --- a/thaw/src/spin_button/mod.rs +++ b/thaw/src/spin_button/mod.rs @@ -48,12 +48,13 @@ where } }; - let increment_disabled = Memo::new(move |_| disabled.get() || value.get() <= min.get()); - let decrement_disabled = Memo::new(move |_| disabled.get() || value.get() >= max.get()); + let increment_disabled = Memo::new(move |_| disabled.get() || value.get() >= max.get()); + let decrement_disabled = Memo::new(move |_| disabled.get() || value.get() <= min.get()); view! { Date: Thu, 23 May 2024 14:48:06 +0800 Subject: [PATCH 023/143] reactor: radio --- demo_markdown/docs/radio/mod.md | 20 ++------ thaw/src/checkbox/mod.rs | 6 +-- thaw/src/radio/mod.rs | 68 ++++++++++++++++---------- thaw/src/radio/radio.css | 87 ++++++++++++++++++++++++--------- thaw/src/radio/radio_group.rs | 14 ++++-- thaw/src/radio/radio_item.rs | 39 --------------- thaw/src/theme/color.rs | 6 +++ 7 files changed, 128 insertions(+), 112 deletions(-) delete mode 100644 thaw/src/radio/radio_item.rs diff --git a/demo_markdown/docs/radio/mod.md b/demo_markdown/docs/radio/mod.md index 87d5b84..d3b6889 100644 --- a/demo_markdown/docs/radio/mod.md +++ b/demo_markdown/docs/radio/mod.md @@ -1,26 +1,12 @@ # Radio ```rust demo -let value = create_rw_signal(false); - -view! { - "Click" -} -``` - -### Group - -```rust demo -let value = create_rw_signal(None); +let value = RwSignal::new(None); view! { - - "Apple" - - - "Orange" - + +
"value: " {move || format!("{:?}", value.get())} diff --git a/thaw/src/checkbox/mod.rs b/thaw/src/checkbox/mod.rs index b3ece84..acabd1e 100644 --- a/thaw/src/checkbox/mod.rs +++ b/thaw/src/checkbox/mod.rs @@ -25,7 +25,7 @@ pub fn Checkbox( }; view! { -
-
+ + } } diff --git a/thaw/src/radio/mod.rs b/thaw/src/radio/mod.rs index d281355..048af83 100644 --- a/thaw/src/radio/mod.rs +++ b/thaw/src/radio/mod.rs @@ -1,45 +1,61 @@ mod radio_group; -mod radio_item; pub use radio_group::RadioGroup; -pub use radio_item::RadioItem; -use crate::{theme::use_theme, Theme}; use leptos::*; -use thaw_utils::{class_list, mount_style, Model, OptionalProp}; +use radio_group::RadioGroupInjection; +use thaw_utils::{class_list, mount_style, OptionalProp}; #[component] pub fn Radio( - #[prop(optional, into)] value: Model, #[prop(optional, into)] class: OptionalProp>, - #[prop(optional)] children: Option, + #[prop(optional, into)] value: String, + #[prop(optional, into)] label: MaybeProp, ) -> impl IntoView { - let theme = use_theme(Theme::light); mount_style("radio", include_str!("./radio.css")); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let bg_color = theme.common.color_primary.clone(); - css_vars.push_str(&format!("--thaw-background-color-checked: {bg_color};")); - }); + let id = uuid::Uuid::new_v4().to_string(); + let group = RadioGroupInjection::use_(); + let item_value = StoredValue::new(value); - css_vars + let checked = Memo::new({ + let group = group.clone(); + move |_| { + item_value.with_value(|value| { + group + .0 + .with(|group_value| group_value.as_ref() == Some(value)) + }) + } }); - view! { -
- -
-
{children.map(|children| children())}
-
+ + + { + move || if let Some(label) = label.get() { + view! { + + }.into() + } else { + None + } + } + } } diff --git a/thaw/src/radio/radio.css b/thaw/src/radio/radio.css index 31dbd64..785bf92 100644 --- a/thaw/src/radio/radio.css +++ b/thaw/src/radio/radio.css @@ -1,42 +1,81 @@ .thaw-radio { display: inline-flex; - align-items: center; - cursor: pointer; + position: relative; } .thaw-radio__input { - width: 0; - height: 0; + position: absolute; + left: 0px; + top: 0px; + width: calc(16px + 2 * var(--spacingHorizontalS)); + height: 100%; + box-sizing: border-box; + margin: 0px; opacity: 0; } -.thaw-radio__dot { - display: inline-block; +.thaw-radio__input:enabled { + cursor: pointer; +} + +.thaw-radio__indicator { position: relative; - width: 14px; - height: 14px; - border: 1px solid #ddd; - border-radius: 50%; + width: 16px; + height: 16px; + font-size: 12px; + box-sizing: border-box; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + border: var(--strokeWidthThin) solid; + border-radius: var(--borderRadiusCircular); + margin: var(--spacingVerticalS) var(--spacingHorizontalS); + fill: currentcolor; + pointer-events: none; } -.thaw-radio:hover .thaw-radio__dot, -.thaw-radio--checked .thaw-radio__dot { - border-color: var(--thaw-background-color-checked); +.thaw-radio__input:enabled:not(:checked) ~ .thaw-radio__indicator { + border-color: var(--colorNeutralStrokeAccessible); } -.thaw-radio--checked .thaw-radio__dot::before { - content: ""; +.thaw-radio__input:checked ~ .thaw-radio__indicator { + border-color: var(--colorCompoundBrandStroke); + color: var(--colorCompoundBrandForeground1); +} + +.thaw-radio__indicator::after { position: absolute; - top: 3px; - bottom: 3px; - left: 3px; - right: 3px; - background-color: var(--thaw-background-color-checked); - border-radius: 50%; + width: 16px; + height: 16px; + border-radius: var(--borderRadiusCircular); + transform: scale(0.625); + background-color: currentcolor; +} + +.thaw-radio__input:checked ~ .thaw-radio__indicator::after { + content: ""; } .thaw-radio__label { - display: inline-block; - padding: 0 6px; - user-select: none; + margin-bottom: calc((16px - var(--lineHeightBase300)) / 2); + margin-top: calc((16px - var(--lineHeightBase300)) / 2); + align-self: center; + padding-bottom: var(--spacingVerticalS); + padding-top: var(--spacingVerticalS); + padding-left: var(--spacingHorizontalXS); + padding-right: var(--spacingHorizontalS); + line-height: var(--lineHeightBase300); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground1); +} + +.thaw-radio__input:enabled:not(:checked) ~ .thaw-radio__label { + color: var(--colorNeutralForeground3); +} + +.thaw-radio__input:enabled ~ .thaw-radio__label { + cursor: pointer; } diff --git a/thaw/src/radio/radio_group.rs b/thaw/src/radio/radio_group.rs index 0827c39..5206bed 100644 --- a/thaw/src/radio/radio_group.rs +++ b/thaw/src/radio/radio_group.rs @@ -6,12 +6,20 @@ pub fn RadioGroup( #[prop(optional, into)] value: Model>, children: Children, ) -> impl IntoView { - view! { } + view! { + +
+ {children()} +
+
+ } } #[derive(Clone)] pub(crate) struct RadioGroupInjection(pub Model>); -pub(crate) fn use_radio_group() -> RadioGroupInjection { - expect_context() +impl RadioGroupInjection { + pub fn use_() -> RadioGroupInjection { + expect_context() + } } diff --git a/thaw/src/radio/radio_item.rs b/thaw/src/radio/radio_item.rs deleted file mode 100644 index 10dd1ce..0000000 --- a/thaw/src/radio/radio_item.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::radio::{radio_group::use_radio_group, Radio}; -use leptos::*; -use thaw_utils::OptionalProp; - -#[component] -pub fn RadioItem( - #[prop(optional, into)] class: OptionalProp>, - #[prop(into)] key: String, - #[prop(optional)] children: Option, -) -> impl IntoView { - let radio_group_value = use_radio_group().0; - let checked = RwSignal::new(false); - let item_key = store_value(key); - - let is_checked = Memo::new(move |_| { - radio_group_value.with(|value| item_key.with_value(|key| value.as_ref() == Some(key))) - }); - - Effect::new(move |prev| { - let checked = checked.get(); - if prev.is_some() { - if !is_checked.get_untracked() { - radio_group_value.set(Some(item_key.get_value())) - } - } - - checked - }); - - if let Some(children) = children { - view! { - - {children()} - - } - } else { - view! { } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index aa07a79..ab6414f 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -35,6 +35,8 @@ pub struct ColorTheme { pub color_neutral_stroke_accessible_hover: String, pub color_neutral_stroke_accessible_pressed: String, + pub color_compound_brand_foreground_1: String, + pub color_compound_brand_background: String, pub color_compound_brand_background_hover: String, pub color_compound_brand_background_pressed: String, @@ -90,6 +92,8 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#575757".into(), color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), + color_compound_brand_foreground_1: "#0f6cbd".into(), + color_compound_brand_background: "#0f6cbd".into(), color_compound_brand_background_hover: "#115ea3".into(), color_compound_brand_background_pressed: "#0f548c".into(), @@ -145,6 +149,8 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#bdbdbd".into(), color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), + color_compound_brand_foreground_1: "#479ef5".into(), + color_compound_brand_background: "#479ef5".into(), color_compound_brand_background_hover: "#62abf5".into(), color_compound_brand_background_pressed: "#2886de".into(), From 4aee77908f218f711e824e3090652a1afdfae842 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 23 May 2024 16:05:06 +0800 Subject: [PATCH 024/143] refactor: checkbox --- demo_markdown/docs/checkbox/mod.md | 8 ++-- thaw/src/checkbox/checkbox_group.rs | 6 ++- thaw/src/checkbox/checkbox_item.rs | 44 --------------------- thaw/src/checkbox/mod.rs | 59 +++++++++++++++++++++++------ thaw/src/radio/mod.rs | 1 + 5 files changed, 57 insertions(+), 61 deletions(-) delete mode 100644 thaw/src/checkbox/checkbox_item.rs diff --git a/demo_markdown/docs/checkbox/mod.md b/demo_markdown/docs/checkbox/mod.md index 0e26a48..d67d59a 100644 --- a/demo_markdown/docs/checkbox/mod.md +++ b/demo_markdown/docs/checkbox/mod.md @@ -4,7 +4,7 @@ let checked = RwSignal::new(false); view! { - "Click" + } ``` @@ -18,9 +18,9 @@ let value = RwSignal::new(HashSet::new()); view! { - - - + + +
"value: " {move || format!("{:?}", value.get())}
} diff --git a/thaw/src/checkbox/checkbox_group.rs b/thaw/src/checkbox/checkbox_group.rs index 44bed97..e701b9b 100644 --- a/thaw/src/checkbox/checkbox_group.rs +++ b/thaw/src/checkbox/checkbox_group.rs @@ -19,8 +19,10 @@ pub fn CheckboxGroup( #[derive(Clone)] pub(crate) struct CheckboxGroupInjection(pub Model>); +impl Copy for CheckboxGroupInjection {} + impl CheckboxGroupInjection { - pub fn use_() -> Self { - expect_context() + pub fn use_() -> Option { + use_context() } } diff --git a/thaw/src/checkbox/checkbox_item.rs b/thaw/src/checkbox/checkbox_item.rs deleted file mode 100644 index e5812fc..0000000 --- a/thaw/src/checkbox/checkbox_item.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::{checkbox_group::CheckboxGroupInjection, Checkbox}; -use leptos::*; -use thaw_utils::OptionalProp; - -#[component] -pub fn CheckboxItem( - #[prop(optional, into)] label: Option, - #[prop(optional, into)] class: OptionalProp>, - #[prop(into)] value: String, -) -> impl IntoView { - let group_value = CheckboxGroupInjection::use_().0; - let checked = RwSignal::new(false); - let item_value = StoredValue::new(value); - - let is_checked = Memo::new(move |_| { - group_value.with(|group_value| item_value.with_value(|value| group_value.contains(value))) - }); - - Effect::new(move |_| { - checked.track(); - - if is_checked.get_untracked() { - group_value.update(move |group_value| { - item_value.with_value(|value| { - group_value.remove(value); - }); - }); - } else if checked.get_untracked() { - group_value.update(move |group_value| { - group_value.insert(item_value.get_value()); - }); - } - }); - - if let Some(label) = label { - view! { - - {label} - - } - } else { - view! { } - } -} diff --git a/thaw/src/checkbox/mod.rs b/thaw/src/checkbox/mod.rs index acabd1e..e506cf5 100644 --- a/thaw/src/checkbox/mod.rs +++ b/thaw/src/checkbox/mod.rs @@ -1,33 +1,64 @@ mod checkbox_group; -mod checkbox_item; pub use checkbox_group::CheckboxGroup; -pub use checkbox_item::CheckboxItem; +use checkbox_group::CheckboxGroupInjection; use leptos::*; -use thaw_components::*; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; #[component] pub fn Checkbox( #[prop(optional, into)] checked: Model, #[prop(optional, into)] class: OptionalProp>, - #[prop(optional)] children: Option, + #[prop(optional, into)] value: Option, + #[prop(optional, into)] label: MaybeProp, ) -> impl IntoView { mount_style("checkbox", include_str!("./checkbox.css")); let id = uuid::Uuid::new_v4().to_string(); let input_ref = NodeRef::::new(); + let group = CheckboxGroupInjection::use_(); + let item_value = StoredValue::new(value); + + let group_checked = Memo::new(move |_| { + let Some(group) = group.as_ref() else { + return None; + }; + group.0.with(|group_value| { + item_value.with_value(|value| { + let Some(value) = value else { + return None; + }; + Some(group_value.contains(value)) + }) + }) + }); let on_change = move |_| { let input = input_ref.get_untracked().unwrap(); - checked.set(input.checked()) + if group_checked.get_untracked().is_some() { + if input.checked() { + group.as_ref().unwrap().0.update(move |group_value| { + group_value.insert(item_value.get_value().unwrap()); + }); + } else { + group.as_ref().unwrap().0.update(move |group_value| { + item_value.with_value(|value| { + group_value.remove(value.as_ref().unwrap()); + }); + }); + } + } else { + checked.set(input.checked()) + } }; + let checked = move || group_checked.get().unwrap_or_else(|| checked.get()); + view! { @@ -35,13 +66,13 @@ pub fn Checkbox( class="thaw-checkbox__input" type="checkbox" id=id.clone() - checked=checked.get_untracked() + checked=checked ref=input_ref on:change=on_change /> - - - + { + move || if let Some(label) = label.get() { + view! { + + }.into() + } else { + None + } + } } } diff --git a/thaw/src/radio/mod.rs b/thaw/src/radio/mod.rs index 048af83..ef21e92 100644 --- a/thaw/src/radio/mod.rs +++ b/thaw/src/radio/mod.rs @@ -43,6 +43,7 @@ pub fn Radio( class="thaw-radio__input" type="radio" id=id.clone() + value=item_value.get_value() prop:checked=move || checked.get() on:change=on_change /> From 643a54185cf9a046d298d64add5f1aa6e33f1637 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 23 May 2024 17:44:00 +0800 Subject: [PATCH 025/143] feat: ConfigProvider CSSVars --- thaw/src/config_provider/mod.rs | 21 ++++++------- thaw_utils/src/dom/mod.rs | 2 +- thaw_utils/src/dom/mount_style.rs | 50 +++++++++++++++++++++++++++++-- thaw_utils/src/lib.rs | 2 +- 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/thaw/src/config_provider/mod.rs b/thaw/src/config_provider/mod.rs index 2f1086d..44bf67d 100644 --- a/thaw/src/config_provider/mod.rs +++ b/thaw/src/config_provider/mod.rs @@ -1,6 +1,6 @@ use crate::Theme; use leptos::*; -use thaw_utils::mount_style; +use thaw_utils::{mount_dynamic_style, mount_style}; #[component] pub fn ConfigProvider( @@ -15,25 +15,26 @@ pub fn ConfigProvider( mount_style("config-provider", include_str!("./config-provider.css")); let theme = theme.unwrap_or_else(|| RwSignal::new(Theme::light())); - let css_vars = Memo::new(move |_| { + let id = StoredValue::new(uuid::Uuid::new_v4().to_string()); + mount_dynamic_style(id.get_value(), move || { let mut css_vars = String::new(); theme.with(|theme| { theme.common.write_css_vars(&mut css_vars); theme.color.write_css_vars(&mut css_vars); }); - css_vars + format!( + ".thaw-config-provider[data-thaw-id=\"{}\"]{{{css_vars}}}", + id.get_value() + ) }); - let config_injection = ConfigInjection { - theme, - dir: dir.clone(), - }; + let config_injection = ConfigInjection { theme, dir }; view! {
{children()} @@ -44,8 +45,8 @@ pub fn ConfigProvider( #[derive(Clone)] pub struct ConfigInjection { - theme: RwSignal, - dir: RwSignal>, + pub theme: RwSignal, + pub dir: RwSignal>, } #[derive(Clone)] diff --git a/thaw_utils/src/dom/mod.rs b/thaw_utils/src/dom/mod.rs index d1fc0b6..c5e3111 100644 --- a/thaw_utils/src/dom/mod.rs +++ b/thaw_utils/src/dom/mod.rs @@ -2,4 +2,4 @@ mod get_scroll_parent; mod mount_style; pub use get_scroll_parent::get_scroll_parent; -pub use mount_style::mount_style; +pub use mount_style::{mount_dynamic_style, mount_style}; diff --git a/thaw_utils/src/dom/mount_style.rs b/thaw_utils/src/dom/mount_style.rs index b57571e..461b972 100644 --- a/thaw_utils/src/dom/mount_style.rs +++ b/thaw_utils/src/dom/mount_style.rs @@ -6,13 +6,13 @@ pub fn mount_style(id: &str, content: &'static str) { use leptos::html::style; use leptos_meta::use_head; let meta = use_head(); - let style_el = style().attr("csr-id", format!("thaw-{id}")).child(content); + let style_el = style().attr("data-thaw-id", id).child(content); meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); } else { use leptos::document; let head = document().head().expect("head no exist"); let style = head - .query_selector(&format!("style[csr-id=\"thaw-{id}\"]")) + .query_selector(&format!("style[data-thaw-id=\"{id}\"]")) .expect("query style element error"); #[cfg(feature = "hydrate")] @@ -25,9 +25,53 @@ pub fn mount_style(id: &str, content: &'static str) { let style = document() .create_element("style") .expect("create style element error"); - _ = style.set_attribute("csr-id", &format!("thaw-{id}")); + _ = style.set_attribute("data-thaw-id", id); style.set_text_content(Some(content)); _ = head.prepend_with_node_1(&style); } } } + +pub fn mount_dynamic_style String + 'static>(id: String, f: T) { + cfg_if! { + if #[cfg(feature = "ssr")] { + use leptos::html::style; + use leptos_meta::use_head; + let meta = use_head(); + let content = leptos::untrack(|| f()); + let style_el = style().attr("data-thaw-id", id).child(content); + meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); + } else { + use leptos::document; + let head = document().head().expect("head no exist"); + let style = head + .query_selector(&format!("style[data-thaw-id=\"{id}\"]")) + .expect("query style element error"); + + #[cfg(feature = "hydrate")] + let _ = leptos::leptos_dom::HydrationCtx::id(); + + + leptos::Effect::new_isomorphic(move |prev: Option>| { + let content = f(); + + if let Some(style) = style.as_ref() { + style.set_text_content(Some(&content)); + None + } else if let Some(style) = prev.flatten() { + style.set_text_content(Some(&content)); + Some(style) + } else { + let style = document() + .create_element("style") + .expect("create style element error"); + _ = style.set_attribute("data-thaw-id", &id); + style.set_text_content(Some(&content)); + _ = head.prepend_with_node_1(&style); + + Some(style) + } + }); + } + } +} diff --git a/thaw_utils/src/lib.rs b/thaw_utils/src/lib.rs index 2b6d071..3a80f60 100644 --- a/thaw_utils/src/lib.rs +++ b/thaw_utils/src/lib.rs @@ -7,7 +7,7 @@ mod signals; mod throttle; mod time; -pub use dom::{get_scroll_parent, mount_style}; +pub use dom::{get_scroll_parent, mount_dynamic_style, mount_style}; pub use event_listener::{ add_event_listener, add_event_listener_with_bool, EventListenerHandle, IntoEventTarget, }; From 9e6a1220d529df34086eb42de0cd8f11243f9d12 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 24 May 2024 10:05:54 +0800 Subject: [PATCH 026/143] feat: ConfigProvider CSSVars --- demo/src/app.rs | 2 +- demo/src/pages/components.rs | 13 ++++----- .../docs/{theme => config_provider}/mod.md | 28 +++++++++---------- demo_markdown/src/lib.rs | 2 +- thaw/src/config_provider/mod.rs | 22 ++++++++++++++- 5 files changed, 42 insertions(+), 25 deletions(-) rename demo_markdown/docs/{theme => config_provider}/mod.md (50%) diff --git a/demo/src/app.rs b/demo/src/app.rs index fd2a8d9..06a9ffb 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -59,6 +59,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + @@ -86,7 +87,6 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index af96c43..3474c4c 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -106,7 +106,7 @@ impl IntoView for MenuItemOption { pub(crate) fn gen_menu_data() -> Vec { vec![ MenuGroupOption { - label: "Common Components".into(), + label: "Components".into(), children: vec![ MenuItemOption { value: "accordion".into(), @@ -124,6 +124,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "card".into(), label: "Card".into(), }, + MenuItemOption { + value: "config-provider".into(), + label: "Config Provider".into(), + }, MenuItemOption { value: "divider".into(), label: "Divider".into(), @@ -310,13 +314,6 @@ pub(crate) fn gen_menu_data() -> Vec { label: "Scrollbar".into(), }], }, - MenuGroupOption { - label: "Config Components".into(), - children: vec![MenuItemOption { - value: "theme".into(), - label: "Theme".into(), - }], - }, MenuGroupOption { label: "Mobile Components".into(), children: vec![ diff --git a/demo_markdown/docs/theme/mod.md b/demo_markdown/docs/config_provider/mod.md similarity index 50% rename from demo_markdown/docs/theme/mod.md rename to demo_markdown/docs/config_provider/mod.md index c6239c0..48040f7 100644 --- a/demo_markdown/docs/theme/mod.md +++ b/demo_markdown/docs/config_provider/mod.md @@ -1,47 +1,47 @@ -# Theme +# ConfigProvider -### ThemeProvider +### Theme ```rust demo -let theme = create_rw_signal(Theme::light()); +let theme = RwSignal::new(Theme::light()); view! { - + - + } ``` ### Customize Theme ```rust demo -let theme = create_rw_signal(Theme::light()); +let theme = RwSignal::new(Theme::light()); let on_customize_theme = move |_| { theme.update(|theme| { - theme.common.color_primary = "#f5222d".to_string(); - theme.common.color_primary_hover = "#ff4d4f".to_string(); - theme.common.color_primary_active = "#cf1322".to_string(); + theme.color.color_brand_background = "#f5222d".to_string(); + theme.color.color_brand_background_hover = "#ff4d4f".to_string(); + theme.color.color_brand_background_pressed = "#cf1322".to_string(); }); }; view! { - + - - + + - + } ``` -### ThemeProvider Props +### ConfigProvider Props | Name | Type | Default | Description | | ----- | ------------------------- | -------------------- | ----------- | diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index c1a78ee..b92064d 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -41,6 +41,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "CardMdPage" => "../docs/card/mod.md", "CheckboxMdPage" => "../docs/checkbox/mod.md", "ColorPickerMdPage" => "../docs/color_picker/mod.md", + "ConfigProviderMdPage" => "../docs/config_provider/mod.md", "DatePickerMdPage" => "../docs/date_picker/mod.md", "DividerMdPage" => "../docs/divider/mod.md", "DrawerMdPage" => "../docs/drawer/mod.md", @@ -68,7 +69,6 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "TableMdPage" => "../docs/table/mod.md", "TabsMdPage" => "../docs/tabs/mod.md", "TagMdPage" => "../docs/tag/mod.md", - "ThemeMdPage" => "../docs/theme/mod.md", "TimePickerMdPage" => "../docs/time_picker/mod.md", "TypographyMdPage" => "../docs/typography/mod.md", "UploadMdPage" => "../docs/upload/mod.md" diff --git a/thaw/src/config_provider/mod.rs b/thaw/src/config_provider/mod.rs index 44bf67d..c6ffa8b 100644 --- a/thaw/src/config_provider/mod.rs +++ b/thaw/src/config_provider/mod.rs @@ -16,6 +16,7 @@ pub fn ConfigProvider( let theme = theme.unwrap_or_else(|| RwSignal::new(Theme::light())); let id = StoredValue::new(uuid::Uuid::new_v4().to_string()); + mount_dynamic_style(id.get_value(), move || { let mut css_vars = String::new(); theme.with(|theme| { @@ -28,7 +29,19 @@ pub fn ConfigProvider( ) }); - let config_injection = ConfigInjection { theme, dir }; + on_cleanup(move || { + if let Ok(Some(style)) = + document().query_selector(&format!("head style[data-thaw-id=\"{}\"]", id.get_value())) + { + style.remove(); + } + }); + + let config_injection = ConfigInjection { + theme, + dir, + id: id.get_value(), + }; view! { @@ -47,6 +60,13 @@ pub fn ConfigProvider( pub struct ConfigInjection { pub theme: RwSignal, pub dir: RwSignal>, + id: String, +} + +impl ConfigInjection { + pub fn id(&self) -> &String { + &self.id + } } #[derive(Clone)] From 61b937f688639b1de9c2e76daa8c9ba5d5418907 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 24 May 2024 16:08:18 +0800 Subject: [PATCH 027/143] feat: RadioGroup adds name prop --- thaw/src/radio/mod.rs | 5 +++-- thaw/src/radio/radio_group.rs | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/thaw/src/radio/mod.rs b/thaw/src/radio/mod.rs index ef21e92..ac92ce2 100644 --- a/thaw/src/radio/mod.rs +++ b/thaw/src/radio/mod.rs @@ -23,14 +23,14 @@ pub fn Radio( move |_| { item_value.with_value(|value| { group - .0 + .value .with(|group_value| group_value.as_ref() == Some(value)) }) } }); let on_change = move |_| { - group.0.set(Some(item_value.get_value())); + group.value.set(Some(item_value.get_value())); }; view! { @@ -43,6 +43,7 @@ pub fn Radio( class="thaw-radio__input" type="radio" id=id.clone() + name=group.name value=item_value.get_value() prop:checked=move || checked.get() on:change=on_change diff --git a/thaw/src/radio/radio_group.rs b/thaw/src/radio/radio_group.rs index 5206bed..6c37e35 100644 --- a/thaw/src/radio/radio_group.rs +++ b/thaw/src/radio/radio_group.rs @@ -4,10 +4,15 @@ use thaw_utils::Model; #[component] pub fn RadioGroup( #[prop(optional, into)] value: Model>, + /// The name of this radio group. + #[prop(optional, into)] + name: Option, children: Children, ) -> impl IntoView { + let name = name.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + view! { - +
{children()}
@@ -16,7 +21,10 @@ pub fn RadioGroup( } #[derive(Clone)] -pub(crate) struct RadioGroupInjection(pub Model>); +pub(crate) struct RadioGroupInjection { + pub value: Model>, + pub name: String, +} impl RadioGroupInjection { pub fn use_() -> RadioGroupInjection { From add2a0bae32518ab33acc7e2e28a01c02d4ca7c9 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 30 May 2024 17:11:24 +0800 Subject: [PATCH 028/143] refactor: Slider --- thaw/src/slider/mod.rs | 31 ++------- thaw/src/slider/slider.css | 127 ++++++++++++++++++++++++++++++++++++- thaw/src/slider/theme.rs | 20 ------ thaw/src/theme/color.rs | 7 +- thaw/src/theme/common.rs | 2 + thaw/src/theme/mod.rs | 7 +- 6 files changed, 138 insertions(+), 56 deletions(-) delete mode 100644 thaw/src/slider/theme.rs diff --git a/thaw/src/slider/mod.rs b/thaw/src/slider/mod.rs index 0776298..2719ec1 100644 --- a/thaw/src/slider/mod.rs +++ b/thaw/src/slider/mod.rs @@ -1,10 +1,7 @@ mod slider_label; -mod theme; pub use slider_label::SliderLabel; -pub use theme::SliderTheme; -use crate::{theme::use_theme, Theme}; use leptos::*; use thaw_components::OptionComp; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; @@ -19,23 +16,6 @@ pub fn Slider( #[prop(optional)] children: Option, ) -> impl IntoView { mount_style("slider", include_str!("./slider.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - css_vars.push_str(&format!("--thaw-slider-max: {};", max.get())); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - &theme.slider.background_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-fill: {};", - &theme.common.color_primary - )); - }); - - css_vars - }); let percentage = create_memo(move |_| { if value.get() < 0.0 || max.get() <= 0.0 { @@ -116,14 +96,13 @@ pub fn Slider( view! {
-
-
+ +
+
+
{children()} diff --git a/thaw/src/slider/slider.css b/thaw/src/slider/slider.css index 84d2708..835782b 100644 --- a/thaw/src/slider/slider.css +++ b/thaw/src/slider/slider.css @@ -1,9 +1,130 @@ .thaw-slider { + min-width: 120px; + min-height: 32px; + + justify-items: center; + touch-action: none; + display: inline-grid; + grid-template-columns: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr; + grid-template-rows: 1fr var(--thaw-slider__thumb--size) 1fr; position: relative; - padding: 6px 0; - cursor: pointer; - user-select: none; + align-items: center; + + --thaw-slider__rail--size: 4px; + --thaw-slider__thumb--size: 20px; + + --thaw-slider__thumb--color: var(--colorCompoundBrandBackground); + --thaw-slider__progress--color: var(--colorCompoundBrandBackground); + --thaw-slider__rail--color: var(--colorNeutralStrokeAccessible); } + +.thaw-slider:hover { + --thaw-slider__progress--color: var(--colorCompoundBrandBackgroundHover); + --thaw-slider__thumb--color: var(--colorCompoundBrandBackgroundHover); +} + +.thaw-slider:active { + --thaw-slider__progress--color: var(--colorCompoundBrandBackgroundPressed); + --thaw-slider__thumb--color: var(--colorCompoundBrandBackgroundPressed); +} + +.thaw-slider:focus, +.thaw-slider:focus-visible { + outline-style: none; +} + +.thaw-slider__input { + grid-column-end: -1; + grid-column-start: 1; + grid-row-end: -1; + grid-row-start: 1; + + margin: 0; + padding: 0; + opacity: 0; + + width: 100%; + height: var(--thaw-slider__thumb--size); + + cursor: pointer; +} + +.thaw-slider__rail { + position: relative; + forced-color-adjust: none; + grid-column-end: 2; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 2; + width: 100%; + height: var(--thaw-slider__rail--size); + background-image: linear-gradient( + var(--thaw-slider--direction), + var(--thaw-slider__progress--color) 0%, + var(--thaw-slider__progress--color) var(--thaw-slider--progress), + var(--thaw-slider__rail--color) var(--thaw-slider--progress) + ); + border-radius: var(--borderRadiusXLarge); + outline: 1px solid var(--colorTransparentStroke); + pointer-events: none; +} + +.thaw-slider__rail::before { + content: ""; + position: absolute; + + height: var(--thaw-slider__rail--size); + right: -1px; + left: -1px; + + background-image: repeating-linear-gradient( + var(--thaw-slider--direction), + #0000 0%, + #0000 calc(var(--thaw-slider--steps-percent) - 1px), + var(--colorNeutralBackground1) + calc(var(--thaw-slider--steps-percent) - 1px), + var(--colorNeutralBackground1) var(--thaw-slider--steps-percent) + ); +} + +.thaw-slider__thumb { + position: absolute; + + forced-color-adjust: none; + grid-column-end: 2; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 2; + + height: var(--thaw-slider__thumb--size); + width: var(--thaw-slider__thumb--size); + left: var(--thaw-slider--progress); + + background-color: var(--thaw-slider__thumb--color); + outline-style: none; + pointer-events: none; + border-radius: var(--borderRadiusCircular); + box-shadow: 0 0 0 calc(var(--thaw-slider__thumb--size) * 0.2) + var(--colorNeutralBackground1) inset; + + transform: translateX(-50%); +} + +.thaw-slider__thumb::before { + content: ""; + position: absolute; + + bottom: 0px; + right: 0px; + left: 0px; + top: 0px; + + box-sizing: border-box; + border-radius: var(--borderRadiusCircular); + border: calc(var(--thaw-slider__thumb--size) * 0.05) solid + var(--colorNeutralStroke1); +} + .thaw-slider-rail { height: 4px; background-color: var(--thaw-background-color); diff --git a/thaw/src/slider/theme.rs b/thaw/src/slider/theme.rs deleted file mode 100644 index 296387d..0000000 --- a/thaw/src/slider/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SliderTheme { - pub background_color: String, -} - -impl ThemeMethod for SliderTheme { - fn light() -> Self { - Self { - background_color: "#dbdbdf".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#ffffff33".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index ab6414f..94d7cbe 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -10,7 +10,7 @@ pub struct ColorTheme { pub color_neutral_background_4_hover: String, pub color_neutral_background_4_pressed: String, pub color_neutral_background_6: String, - + pub color_neutral_foreground_disabled: String, pub color_neutral_foreground_1: String, pub color_neutral_foreground_1_hover: String, @@ -52,6 +52,7 @@ pub struct ColorTheme { pub color_transparent_background: String, pub color_transparent_background_hover: String, pub color_transparent_background_pressed: String, + pub color_transparent_stroke: String, pub shadow4: String, } @@ -109,6 +110,7 @@ impl ColorTheme { color_transparent_background: "transparent".into(), color_transparent_background_hover: "transparent".into(), color_transparent_background_pressed: "transparent".into(), + color_transparent_stroke: "transparent".into(), shadow4: "0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14)".into(), } @@ -166,8 +168,9 @@ impl ColorTheme { color_transparent_background: "transparent".into(), color_transparent_background_hover: "transparent".into(), color_transparent_background_pressed: "transparent".into(), + color_transparent_stroke: "transparent".into(), shadow4: "0 0 2px rgba(0,0,0,0.24), 0 2px 4px rgba(0,0,0,0.28)".into(), } } -} \ No newline at end of file +} diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index ca6bf22..fd74955 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -43,6 +43,7 @@ pub struct CommonTheme { pub border_radius_none: String, pub border_radius_medium: String, + pub border_radius_x_large: String, pub border_radius_circular: String, pub spacing_horizontal_x_x_s: String, @@ -115,6 +116,7 @@ impl CommonTheme { border_radius_none: "0".into(), border_radius_medium: "4px".into(), + border_radius_x_large: "8px".into(), border_radius_circular: "10000px".into(), spacing_horizontal_x_x_s: "2px".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 51650c8..4d4d61c 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -6,8 +6,8 @@ use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, - ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme, - SwitchTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, + ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, SwitchTheme, + TableTheme, TagTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -30,7 +30,6 @@ pub struct Theme { pub tag: TagTheme, pub message: MessageTheme, pub select: SelectTheme, - pub slider: SliderTheme, pub switch: SwitchTheme, pub spinner: SpinnerTheme, pub upload: UploadTheme, @@ -63,7 +62,6 @@ impl Theme { tag: TagTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - slider: SliderTheme::light(), switch: SwitchTheme::light(), spinner: SpinnerTheme::light(), upload: UploadTheme::light(), @@ -95,7 +93,6 @@ impl Theme { tag: TagTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), - slider: SliderTheme::dark(), switch: SwitchTheme::dark(), spinner: SpinnerTheme::dark(), upload: UploadTheme::dark(), From f5c0d2a5224133df4635a227c813fb66500b1d5a Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 31 May 2024 17:12:32 +0800 Subject: [PATCH 029/143] refactor: Slider --- demo_markdown/docs/slider/mod.md | 10 +- thaw/src/slider/mod.rs | 172 +++++++++++++++---------------- thaw/src/slider/slider.css | 25 +---- thaw/src/slider/slider_label.css | 3 +- thaw/src/slider/slider_label.rs | 18 +++- 5 files changed, 105 insertions(+), 123 deletions(-) diff --git a/demo_markdown/docs/slider/mod.md b/demo_markdown/docs/slider/mod.md index f37522a..d007071 100644 --- a/demo_markdown/docs/slider/mod.md +++ b/demo_markdown/docs/slider/mod.md @@ -1,7 +1,7 @@ # Slider ```rust demo -let value = create_rw_signal(0.0); +let value = RwSignal::new(0.0); view! { @@ -11,20 +11,20 @@ view! { ### Step ```rust demo -let value = create_rw_signal(0.0); +let value = RwSignal::new(0.0); view! { - + } ``` ## Slider Label ```rust demo -let value = create_rw_signal(0.0); +let value = RwSignal::new(0.0); view! { - + "0" diff --git a/thaw/src/slider/mod.rs b/thaw/src/slider/mod.rs index 2719ec1..ee277d3 100644 --- a/thaw/src/slider/mod.rs +++ b/thaw/src/slider/mod.rs @@ -5,114 +5,106 @@ pub use slider_label::SliderLabel; use leptos::*; use thaw_components::OptionComp; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; -use web_sys::DomRect; #[component] pub fn Slider( #[prop(optional, into)] value: Model, - #[prop(default = MaybeSignal::Static(100f64), into)] max: MaybeSignal, - #[prop(optional, into)] step: MaybeSignal, + #[prop(default = 0f64.into(), into)] min: MaybeSignal, + #[prop(default = 100f64.into(), into)] max: MaybeSignal, + #[prop(optional, into)] step: MaybeProp, #[prop(optional, into)] class: OptionalProp>, #[prop(optional)] children: Option, ) -> impl IntoView { mount_style("slider", include_str!("./slider.css")); - let percentage = create_memo(move |_| { - if value.get() < 0.0 || max.get() <= 0.0 { - 0f64 - } else if value.get() >= max.get() { - 100f64 + let is_chldren = children.is_some(); + let list_id = is_chldren.then(|| uuid::Uuid::new_v4().to_string()); + let current_value = Memo::new(move |_| { + let max = max.get(); + let min = min.get(); + let v = value.get(); + if v > max { + max + } else if v < min { + min } else { - value.get() / max.get() * 100.0 + v } }); - let do_update_value = move |mut val| { - let step = step.get_untracked(); - if step > 0.0 { - let result: f64 = val / step; - if result.fract() != 0.0 { - let prev_multiple = (result.floor() * step).abs(); - let mut next_multiple = (result.ceil() * step).abs(); - let max = max.get_untracked(); - if next_multiple > max { - next_multiple = max; - } - if val - prev_multiple > next_multiple - val { - val = next_multiple; - } else { - val = prev_multiple; - } + let on_input = move |e: ev::Event| { + if let Ok(range_value) = event_target_value(&e).parse::() { + value.set(range_value); + } + }; + + let css_vars = move || { + let max = max.get(); + let min = min.get(); + let mut css_vars = format!( + "--thaw-slider--direction: 90deg;--thaw-slider--progress: {:.2}%;", + if max == min { + 0.0 + } else { + (current_value.get() - min) / (max - min) * 100.0 + } + ); + + if is_chldren { + css_vars.push_str(&format!("--thaw-slider--max: {:.2};", max)); + css_vars.push_str(&format!("--thaw-slider--min: {:.2};", min)); + } + + if let Some(step) = step.get() { + if step > 0.0 { + css_vars.push_str(&format!( + "--thaw-slider--steps-percent: {:.2}%", + step * 100.0 / (max - min) + )); } } - value.set(val); + css_vars }; - let rail_ref = create_node_ref::(); - let (mouse_move_value, set_mouse_move_value) = create_signal::>(None); - let (is_mouse_move, set_mouse_move) = create_signal(false); - let on_mouse_down = move |_| { - set_mouse_move.set(true); - }; - - let check_value_and_update = move |ev_x: f64, rect: DomRect| { - if ev_x <= rect.x() { - set_mouse_move_value.set(Some(0.0)); - } else if ev_x >= rect.x() + rect.width() { - set_mouse_move_value.set(Some(max.get())); - } else { - set_mouse_move_value.set(Some(((ev_x - rect.x()) / rect.width()) * max.get())); - } - if let Some(value) = mouse_move_value.get_untracked() { - do_update_value(value); - } - }; - - let on_mouse_click = move |ev: ev::MouseEvent| { - if let Some(rail) = rail_ref.get_untracked() { - let rect = rail.get_bounding_client_rect(); - let ev_x = f64::from(ev.x()); - check_value_and_update(ev_x, rect); - }; - }; - - let on_mouse_up = window_event_listener(ev::mouseup, move |_| { - set_mouse_move.set(false); - }); - - on_cleanup(move || on_mouse_up.remove()); - - let on_mouse_move = window_event_listener(ev::mousemove, move |ev| { - if is_mouse_move.get_untracked() { - if let Some(rail) = rail_ref.get_untracked() { - let rect = rail.get_bounding_client_rect(); - let ev_x = f64::from(ev.x()); - check_value_and_update(ev_x, rect); - }; - } - }); - on_cleanup(move || on_mouse_move.remove()); - view! { -
- -
-
-
-
- - {children()} - +
- -
+ class=class_list!["thaw-slider", class.map(| c | move || c.get())] + style=css_vars + > + +
+
+
+
+ + + {children()} + + +
+ + } +} + +#[derive(Clone)] +pub(crate) struct SliderInjection { + pub max: MaybeSignal, + pub min: MaybeSignal, +} + +impl SliderInjection { + pub fn use_() -> Self { + expect_context() } } diff --git a/thaw/src/slider/slider.css b/thaw/src/slider/slider.css index 835782b..afa6a74 100644 --- a/thaw/src/slider/slider.css +++ b/thaw/src/slider/slider.css @@ -125,26 +125,9 @@ var(--colorNeutralStroke1); } -.thaw-slider-rail { - height: 4px; - background-color: var(--thaw-background-color); - border-radius: 2px; - cursor: pointer; -} -.thaw-slider-rail__fill { - width: 0%; - height: 4px; - background-color: var(--thaw-background-color-fill); - border-radius: 2px; - cursor: pointer; -} -.thaw-slider-handle { +.thaw-slider__datalist { + display: block; position: absolute; - top: 0px; - width: 16px; - height: 16px; - border-radius: 50%; - background-color: white; - box-shadow: 0px 0px 4px #2224; - transform: translateX(-50%); + width: 100%; + top: calc(var(--thaw-slider__thumb--size) + 4px); } diff --git a/thaw/src/slider/slider_label.css b/thaw/src/slider/slider_label.css index b562b20..725911c 100644 --- a/thaw/src/slider/slider_label.css +++ b/thaw/src/slider/slider_label.css @@ -1,6 +1,5 @@ .thaw-slider-label { position: absolute; - display: inline-block; + display: inline-block; transform: translateX(-50%); - margin-top: 8px; } diff --git a/thaw/src/slider/slider_label.rs b/thaw/src/slider/slider_label.rs index a18860e..9d24004 100644 --- a/thaw/src/slider/slider_label.rs +++ b/thaw/src/slider/slider_label.rs @@ -1,19 +1,27 @@ use leptos::*; use thaw_utils::mount_style; +use crate::SliderInjection; + #[component] pub fn SliderLabel(#[prop(into)] value: MaybeSignal, children: Children) -> impl IntoView { mount_style("slider-label", include_str!("./slider_label.css")); + let slider = SliderInjection::use_(); + + let style = move || { + let value = (value.get() - slider.min.get()) / (slider.max.get() - slider.min.get()); + format!("left: calc({} * (100% - var(--thaw-slider__thumb--size)) + var(--thaw-slider__thumb--size) / 2)", value) + }; + view! { -
{children()} -
+ } } From dd50d450ff74ee59740fa29cf4331114e5efd98c Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 3 Jun 2024 10:44:51 +0800 Subject: [PATCH 030/143] refactor: switch --- demo_markdown/docs/switch/mod.md | 4 +- thaw/src/switch/mod.rs | 61 ++++++++++++---------- thaw/src/switch/switch.css | 89 ++++++++++++++++++++++---------- thaw/src/switch/theme.rs | 20 ------- thaw/src/theme/mod.rs | 7 +-- 5 files changed, 98 insertions(+), 83 deletions(-) delete mode 100644 thaw/src/switch/theme.rs diff --git a/demo_markdown/docs/switch/mod.md b/demo_markdown/docs/switch/mod.md index 399d681..c10cda9 100644 --- a/demo_markdown/docs/switch/mod.md +++ b/demo_markdown/docs/switch/mod.md @@ -1,10 +1,10 @@ # Switch ```rust demo -let value = create_rw_signal(false); +let checked = RwSignal::new(false); view! { - + } ``` diff --git a/thaw/src/switch/mod.rs b/thaw/src/switch/mod.rs index cee6148..a5bb036 100644 --- a/thaw/src/switch/mod.rs +++ b/thaw/src/switch/mod.rs @@ -1,46 +1,51 @@ -mod theme; - -pub use theme::SwitchTheme; - -use crate::{theme::use_theme, Theme}; use leptos::*; use thaw_utils::{class_list, mount_style, Model, OptionalProp}; #[component] pub fn Switch( - #[prop(optional, into)] value: Model, + #[prop(optional, into)] checked: Model, #[prop(optional, into)] class: OptionalProp>, + #[prop(optional, into)] label: MaybeProp, ) -> impl IntoView { mount_style("switch", include_str!("./switch.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.switch.background_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-active: {};", - theme.common.color_primary - )); - }); - css_vars - }); + + let id = uuid::Uuid::new_v4().to_string(); + let input_ref = NodeRef::::new(); + let on_change = move |_| { + let input = input_ref.get_untracked().unwrap(); + checked.set(input.checked()); + }; view! {
-
+ + + { + move || if let Some(label) = label.get() { + view! { + + }.into() + } else { + None + } + }
} } diff --git a/thaw/src/switch/switch.css b/thaw/src/switch/switch.css index 0a2118d..b940ecf 100644 --- a/thaw/src/switch/switch.css +++ b/thaw/src/switch/switch.css @@ -1,42 +1,75 @@ .thaw-switch { + align-items: flex-start; + box-sizing: border-box; + display: inline-flex; position: relative; - display: inline-block; - width: 40px; - height: 22px; - background-color: var(--thaw-background-color); - border-radius: 11px; - cursor: pointer; - box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.05); - transition: all 0.4s ease; - user-select: none; } -.thaw-switch__button { +.thaw-switch__input { position: absolute; - top: 2px; - left: 2px; - display: inline-block; - width: 18px; - height: 18px; - border-radius: 9px; - background-color: #fff; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3), - inset 0 0 1px 0 rgba(0, 0, 0, 0.05); - transition: all 0.4s ease; + top: 0px; + left: 0px; + width: calc(40px + 2 * var(--spacingHorizontalS)); + height: 100%; + margin: 0px; + opacity: 0; + box-sizing: border-box; + cursor: pointer; } -.thaw-switch--active { - background-color: var(--thaw-background-color-active); +.thaw-switch__indicator { + flex-shrink: 0; + width: 40px; + height: 20px; + margin: var(--spacingVerticalS) var(--spacingHorizontalS); + font-size: 18px; + line-height: 0; + border-radius: var(--borderRadiusCircular); + border: 1px solid; + box-sizing: border-box; + fill: currentcolor; + pointer-events: none; + transition-duration: var(--durationNormal); + transition-timing-function: var(--curveEasyEase); + transition-property: background, border, color; } -.thaw-switch--active .thaw-switch__button { - left: 20px; +.thaw-switch__input:enabled:not(:checked) ~ .thaw-switch__indicator { + color: var(--colorNeutralStrokeAccessible); + border-color: var(--colorNeutralStrokeAccessible); } -.thaw-switch--active:active .thaw-switch__button { - left: 14px; +.thaw-switch__input:enabled:checked ~ .thaw-switch__indicator { + background-color: var(--colorCompoundBrandBackground); + color: var(--colorNeutralForegroundInverted); + border-color: var(--colorTransparentStroke); } -.thaw-switch:active .thaw-switch__button { - width: 24px; +.thaw-switch__indicator > svg { + display: inline; + line-height: 0; + + transition-duration: var(--durationNormal); + transition-timing-function: var(--curveEasyEase); + transition-property: transform; +} + +.thaw-switch__input:checked ~ .thaw-switch__indicator > svg { + transform: translateX(20px); +} + +.thaw-switch__label { + margin-top: calc((20px - var(--lineHeightBase300)) / 2); + margin-bottom: calc((20px - var(--lineHeightBase300)) / 2); + padding: var(--spacingVerticalS) var(--spacingHorizontalS); + padding-left: var(--spacingHorizontalXS); + line-height: var(--lineHeightBase300); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground1); + cursor: pointer; +} + +.thaw-switch__input:enabled:not(:checked) ~ .thaw-switch__label { + color: var(--colorNeutralForeground1); } diff --git a/thaw/src/switch/theme.rs b/thaw/src/switch/theme.rs deleted file mode 100644 index b5ddf85..0000000 --- a/thaw/src/switch/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SwitchTheme { - pub background_color: String, -} - -impl ThemeMethod for SwitchTheme { - fn light() -> Self { - Self { - background_color: "#00000024".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#ffffff33".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 4d4d61c..816aae9 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -6,8 +6,8 @@ use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, - ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, SwitchTheme, - TableTheme, TagTheme, TimePickerTheme, UploadTheme, + ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme, + TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -30,7 +30,6 @@ pub struct Theme { pub tag: TagTheme, pub message: MessageTheme, pub select: SelectTheme, - pub switch: SwitchTheme, pub spinner: SpinnerTheme, pub upload: UploadTheme, pub nav_bar: NavBarTheme, @@ -62,7 +61,6 @@ impl Theme { tag: TagTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - switch: SwitchTheme::light(), spinner: SpinnerTheme::light(), upload: UploadTheme::light(), nav_bar: NavBarTheme::light(), @@ -93,7 +91,6 @@ impl Theme { tag: TagTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), - switch: SwitchTheme::dark(), spinner: SpinnerTheme::dark(), upload: UploadTheme::dark(), nav_bar: NavBarTheme::dark(), From 01df9dfe20d796d0c33b645841a199235909da9d Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 3 Jun 2024 11:27:29 +0800 Subject: [PATCH 031/143] perf: dead code --- demo/src/app.rs | 4 +- demo/src/components/site_header.rs | 135 +++++++++------------- demo/src/pages/components.rs | 148 ++++++++++++++----------- demo/src/pages/guide.rs | 141 ----------------------- demo/src/pages/mod.rs | 2 - demo_markdown/docs/input_number/mod.md | 68 ------------ demo_markdown/docs/menu/mod.md | 36 ------ demo_markdown/src/lib.rs | 2 - thaw/src/input_number/mod.rs | 121 -------------------- thaw/src/lib.rs | 4 - thaw/src/theme/mod.rs | 7 +- 11 files changed, 142 insertions(+), 526 deletions(-) delete mode 100644 demo/src/pages/guide.rs delete mode 100644 demo_markdown/docs/input_number/mod.md delete mode 100644 demo_markdown/docs/menu/mod.md delete mode 100644 thaw/src/input_number/mod.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 06a9ffb..2257723 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -35,7 +35,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { view! { - + @@ -67,10 +67,8 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - - diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index 17d6a7e..d1f4413 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -76,7 +76,7 @@ pub fn SiteHeader() -> impl IntoView { }); on_cleanup(move || handle.remove()); - let menu_value = use_menu_value(change_theme); + // let menu_value = use_menu_value(change_theme); view! { - - - - - - - {gen_guide_menu_data().into_view()} - - - - - - - - - } -} - -pub(crate) struct MenuGroupOption { - pub label: String, - pub children: Vec, -} - -impl IntoView for MenuGroupOption { - fn into_view(self) -> View { - let Self { label, children } = self; - view! { - - - {children.into_iter().map(|v| v.into_view()).collect_view()} - - - } - } -} - -pub(crate) struct MenuItemOption { - pub label: String, - pub value: String, -} - -impl IntoView for MenuItemOption { - fn into_view(self) -> View { - let Self { label, value } = self; - view! { } - } -} - -pub(crate) fn gen_guide_menu_data() -> Vec { - vec![ - MenuGroupOption { - label: "Getting Started".into(), - children: vec![ - MenuItemOption { - value: "installation".into(), - label: "Installation".into(), - }, - MenuItemOption { - value: "usage".into(), - label: "Usage".into(), - }, - ], - }, - MenuGroupOption { - label: "Guides".into(), - children: vec![MenuItemOption { - value: "server-sider-rendering".into(), - label: "Server Sider Rendering".into(), - }], - }, - MenuGroupOption { - label: "Development".into(), - children: vec![ - MenuItemOption { - value: "development/guide".into(), - label: "Guide".into(), - }, - MenuItemOption { - value: "development/components".into(), - label: "Components".into(), - }, - ], - }, - ] -} diff --git a/demo/src/pages/mod.rs b/demo/src/pages/mod.rs index 15a8372..b90761d 100644 --- a/demo/src/pages/mod.rs +++ b/demo/src/pages/mod.rs @@ -1,5 +1,4 @@ mod components; -mod guide; mod home; mod markdown; mod mobile; @@ -8,7 +7,6 @@ mod tabbar; mod toast; pub use components::*; -pub use guide::*; pub use home::*; pub use markdown::*; pub use mobile::*; diff --git a/demo_markdown/docs/input_number/mod.md b/demo_markdown/docs/input_number/mod.md deleted file mode 100644 index c50a21c..0000000 --- a/demo_markdown/docs/input_number/mod.md +++ /dev/null @@ -1,68 +0,0 @@ -# Input Number - -```rust demo -let value = create_rw_signal(0); -let value_f64 = create_rw_signal(0.0); - -view! { - - - - -} -``` - -### Min / Max - -```rust demo -let value = create_rw_signal(0); - -view! { - -} -``` - -### Disabled - -```rust demo -let value = create_rw_signal(0); - -view! { - -} -``` - -### Invalid - -```rust demo -let value = create_rw_signal(0); - -view! { - -} -``` - -### InputNumber Props - -| Name | Type | Default | Description | -| --- | --- | --- | --- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the input element. | -| value | `Model` | `T::default()` | Set the input value. | -| placeholder | `OptionalProp>` | `Default::default()` | Placeholder of input number. | -| step | `MaybeSignal` | | The number which the current value is increased or decreased on key or button press. | -| min | `MaybeSignal` | `T::min_value()` | The minimum number that the input value can take. | -| max | `MaybeSignal` | `T::max_value()` | The maximum number that the input value can take. | -| disabled | `MaybeSignal` | `false` | Whether the input is disabled. | -| invalid | `MaybeSignal` | `false` | Whether the input is invalid. | -| attr: | `Vec<(&'static str, Attribute)>` | `Default::default()` | The dom attrs of the input element inside the component. | - -#### T impl - -`T: Add + Sub + PartialOrd + num::Bounded + Default + Clone + FromStr + ToString + 'static` - -### InputNumber Ref - -| Name | Type | Description | -| ----- | ----------- | ------------------------ | -| focus | `Fn(&self)` | Focus the input element. | -| blur | `Fn(&self)` | Blur the input element. | diff --git a/demo_markdown/docs/menu/mod.md b/demo_markdown/docs/menu/mod.md deleted file mode 100644 index ea2ef07..0000000 --- a/demo_markdown/docs/menu/mod.md +++ /dev/null @@ -1,36 +0,0 @@ -# Menu - -```rust demo -let value = create_rw_signal(String::from("o")); - -view! { - - - - -} -``` - -### Menu Props - -| Name | Type | Default | Description | -| -------- | ----------------------------------- | -------------------- | --------------------------------------- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the menu element. | -| value | `Model` | `Default::default()` | The selected item key of the menu. | -| children | `Children` | | Menu's content. | - -### MenuGroup Props - -| Name | Type | Default | Description | -| --- | --- | --- | --- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the menu group element. | -| label | `String` | | The label of the menu group. | -| children | `Children` | | MenuGroup's content. | - -### MenuItem Props - -| Name | Type | Default | Description | -| ----- | ----------------------------------- | -------------------- | -------------------------------------------- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the menu item element. | -| label | `MaybeSignal` | `Default::default()` | The label of the menu item. | -| key | `MaybeSignal` | `Default::default()` | The indentifier of the menu item. | diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index b92064d..6b3329e 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -49,10 +49,8 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "IconMdPage" => "../docs/icon/mod.md", "ImageMdPage" => "../docs/image/mod.md", "InputMdPage" => "../docs/input/mod.md", - "InputNumberMdPage" => "../docs/input_number/mod.md", "LayoutMdPage" => "../docs/layout/mod.md", "LoadingBarMdPage" => "../docs/loading_bar/mod.md", - "MenuMdPage" => "../docs/menu/mod.md", "MessageMdPage" => "../docs/message/mod.md", "ModalMdPage" => "../docs/modal/mod.md", "PopoverMdPage" => "../docs/popover/mod.md", diff --git a/thaw/src/input_number/mod.rs b/thaw/src/input_number/mod.rs deleted file mode 100644 index 2943f11..0000000 --- a/thaw/src/input_number/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::{Button, ButtonAppearance, ComponentRef, Icon, Input, InputRef, InputSuffix}; -use leptos::*; -use num_traits::Bounded; -use std::ops::{Add, Sub}; -use std::str::FromStr; -use thaw_utils::{Model, OptionalProp, StoredMaybeSignal}; - -#[component] -pub fn InputNumber( - #[prop(optional, into)] value: Model, - #[prop(optional, into)] placeholder: OptionalProp>, - #[prop(into)] step: MaybeSignal, - #[prop(optional, into)] disabled: MaybeSignal, - #[prop(optional, into)] invalid: MaybeSignal, - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional)] comp_ref: ComponentRef, - #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, - #[prop(default = MaybeSignal::Static(T::min_value()), into)] min: MaybeSignal, - #[prop(default = MaybeSignal::Static(T::max_value()), into)] max: MaybeSignal, -) -> impl IntoView -where - T: Add + Sub + PartialOrd + Bounded, - T: Default + Clone + FromStr + ToString + 'static, -{ - let input_value = create_rw_signal(String::default()); - Effect::new_isomorphic(move |prev| { - value.with(|value| { - let value = value.to_string(); - if let Some(prev) = prev { - if value == prev { - return prev; - } - } - input_value.set(value.clone()); - value - }) - }); - - let allow_value = Callback::::new(move |v: String| { - let Ok(v) = v.parse::() else { return false }; - value.set(v); - true - }); - let step: StoredMaybeSignal<_> = step.into(); - let min: StoredMaybeSignal<_> = min.into(); - let max: StoredMaybeSignal<_> = max.into(); - - let add = Callback::::new(move |e: ev::MouseEvent| { - e.prevent_default(); - value.set(value.get_untracked() + step.get_untracked()); - }); - let sub = Callback::::new(move |e: ev::MouseEvent| { - e.prevent_default(); - value.set(value.get_untracked() - step.get_untracked()); - }); - - let input_ref = ComponentRef::::new(); - input_ref.on_load(move |_| { - comp_ref.load(InputNumberRef { input_ref }); - }); - - let set_within_range = Callback::::new(move |_| { - let old_value = value.get_untracked(); - let min = min.get_untracked(); - let max = max.get_untracked(); - if old_value < min { - value.set(min); - } else if old_value > max { - value.set(max); - } - }); - - let minus_disabled = create_memo(move |_| disabled.get() || value.get() <= min.get()); - let plus_disabled = create_memo(move |_| disabled.get() || value.get() >= max.get()); - let invalid = create_memo(move |_| { - let value = value.get(); - invalid.get() || value < min.get() || value > max.get() - }); - - view! { - - - - - - - } -} - -#[derive(Clone)] -pub struct InputNumberRef { - input_ref: ComponentRef, -} - -impl InputNumberRef { - pub fn focus(&self) { - if let Some(input_ref) = self.input_ref.get_untracked() { - input_ref.focus(); - } - } - - pub fn blur(&self) { - if let Some(input_ref) = self.input_ref.get_untracked() { - input_ref.blur(); - } - } -} diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 9b4455d..499152f 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -20,10 +20,8 @@ mod grid; mod icon; mod image; mod input; -mod input_number; mod layout; mod loading_bar; -mod menu; mod message; pub mod mobile; mod modal; @@ -69,10 +67,8 @@ pub use grid::*; pub use icon::*; pub use image::*; pub use input::*; -pub use input_number::*; pub use layout::*; pub use loading_bar::*; -pub use menu::*; pub use message::*; pub use modal::*; pub use nav::*; diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 816aae9..be32980 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -5,8 +5,8 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, - ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, - ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme, + ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, + ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; @@ -23,7 +23,6 @@ pub struct Theme { pub common: CommonTheme, pub color: ColorTheme, pub input: InputTheme, - pub menu: MenuTheme, pub table: TableTheme, pub alert: AlertTheme, pub skeletion: SkeletionTheme, @@ -54,7 +53,6 @@ impl Theme { common: CommonTheme::light(), color: ColorTheme::light(), input: InputTheme::light(), - menu: MenuTheme::light(), table: TableTheme::light(), alert: AlertTheme::light(), skeletion: SkeletionTheme::light(), @@ -84,7 +82,6 @@ impl Theme { common: CommonTheme::dark(), color: ColorTheme::dark(), input: InputTheme::dark(), - menu: MenuTheme::dark(), table: TableTheme::dark(), alert: AlertTheme::dark(), skeletion: SkeletionTheme::dark(), From bacda05edc3d99d5ac89b8708383e5f968360cc3 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 3 Jun 2024 16:31:32 +0800 Subject: [PATCH 032/143] feat: text adds style prop --- demo/src/app.rs | 2 +- demo/src/pages/components.rs | 45 ++------ demo_markdown/docs/card/mod.md | 2 +- .../docs/{typography => text}/mod.md | 3 + demo_markdown/src/lib.rs | 2 +- thaw/src/text/mod.rs | 108 ++++++++++++++---- 6 files changed, 102 insertions(+), 60 deletions(-) rename demo_markdown/docs/{typography => text}/mod.md (84%) diff --git a/demo/src/app.rs b/demo/src/app.rs index 2257723..37d666f 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -85,8 +85,8 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + - diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 1577307..2a6a35f 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -75,10 +75,9 @@ pub(crate) struct MenuGroupOption { impl IntoView for MenuGroupOption { fn into_view(self) -> View { let Self { label, children } = self; - let children_len = children.len(); view! { - - {format!("{label} ({children_len})")} + + {label} {children.into_iter().map(|v| v.into_view()).collect_view()} } @@ -169,18 +168,13 @@ pub(crate) fn gen_menu_data() -> Vec { label: "Tag".into(), }, MenuItemOption { - value: "/components/typography".into(), - label: "Typography".into(), + value: "/components/text".into(), + label: "Text".into(), }, MenuItemOption { value: "/components/spin-button".into(), label: "Spin Button".into(), }, - ], - }, - MenuGroupOption { - label: "Data Input Components".into(), - children: vec![ MenuItemOption { value: "/components/auto-complete".into(), label: "Auto Complete".into(), @@ -225,11 +219,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/upload".into(), label: "Upload".into(), }, - ], - }, - MenuGroupOption { - label: "Data Display Components".into(), - children: vec![ MenuItemOption { value: "/components/calendar".into(), label: "Calendar".into(), @@ -242,11 +231,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/table".into(), label: "Table".into(), }, - ], - }, - MenuGroupOption { - label: "Navigation Components".into(), - children: vec![ MenuItemOption { value: "/components/anchor".into(), label: "Anchor".into(), @@ -267,11 +251,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/tabs".into(), label: "Tabs".into(), }, - ], - }, - MenuGroupOption { - label: "Feedback Components".into(), - children: vec![ MenuItemOption { value: "/components/alert".into(), label: "Alert".into(), @@ -308,11 +287,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/skeleton".into(), label: "Skeleton".into(), }, - ], - }, - MenuGroupOption { - label: "Layout Components".into(), - children: vec![ MenuItemOption { value: "/components/layout".into(), label: "Layout".into(), @@ -325,15 +299,12 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/space".into(), label: "Space".into(), }, + MenuItemOption { + value: "/components/scrollbar".into(), + label: "Scrollbar".into(), + }, ], }, - MenuGroupOption { - label: "Utility Components".into(), - children: vec![MenuItemOption { - value: "/components/scrollbar".into(), - label: "Scrollbar".into(), - }], - }, MenuGroupOption { label: "Mobile Components".into(), children: vec![ diff --git a/demo_markdown/docs/card/mod.md b/demo_markdown/docs/card/mod.md index ba6962f..c00115a 100644 --- a/demo_markdown/docs/card/mod.md +++ b/demo_markdown/docs/card/mod.md @@ -5,7 +5,7 @@ view! { - "Header""2022-02-22" + "Header"" 2022-02-22" "Description" diff --git a/demo_markdown/docs/typography/mod.md b/demo_markdown/docs/text/mod.md similarity index 84% rename from demo_markdown/docs/typography/mod.md rename to demo_markdown/docs/text/mod.md index 2f4f6c2..8af48bf 100644 --- a/demo_markdown/docs/typography/mod.md +++ b/demo_markdown/docs/text/mod.md @@ -5,6 +5,9 @@ view! { "text" "code" + "Caption1" + "Caption1Strong" + "Body1" } ``` diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 6b3329e..9a4b6cb 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -68,7 +68,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "TabsMdPage" => "../docs/tabs/mod.md", "TagMdPage" => "../docs/tag/mod.md", "TimePickerMdPage" => "../docs/time_picker/mod.md", - "TypographyMdPage" => "../docs/typography/mod.md", + "TextMdPage" => "../docs/text/mod.md", "UploadMdPage" => "../docs/upload/mod.md" }; diff --git a/thaw/src/text/mod.rs b/thaw/src/text/mod.rs index da1605f..7861e52 100644 --- a/thaw/src/text/mod.rs +++ b/thaw/src/text/mod.rs @@ -4,45 +4,52 @@ use thaw_utils::{class_list, mount_style}; #[component] pub fn Caption1( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { - let class = Signal::derive(move || format!("thaw-caption-1 {:?}", class.get())); + let class = + Signal::derive(move || format!("thaw-caption-1 {}", class.get().unwrap_or_default())); view! { - + } } #[component] pub fn Caption1Strong( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { - let class = Signal::derive(move || format!("thaw-caption-1-strong {:?}", class.get())); + let class = Signal::derive(move || { + format!("thaw-caption-1-strong {}", class.get().unwrap_or_default()) + }); view! { - + } } #[component] pub fn Body1( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { - let class = Signal::derive(move || format!("thaw-body-1 {:?}", class.get())); + let class = Signal::derive(move || format!("thaw-body-1 {}", class.get().unwrap_or_default())); view! { - + } } #[component] pub fn Text( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, #[prop(optional)] code: bool, children: Children, @@ -50,23 +57,84 @@ pub fn Text( mount_style("text", include_str!("./text.css")); match tag { - TextTag::B => todo!(), - TextTag::Em => todo!(), - TextTag::H1 => todo!(), - TextTag::H2 => todo!(), - TextTag::H3 => todo!(), - TextTag::H4 => todo!(), - TextTag::H5 => todo!(), - TextTag::H6 => todo!(), - TextTag::I => todo!(), - TextTag::P => todo!(), - TextTag::Pre => todo!(), + TextTag::B => view! { + + {children()} + + } + .into_view(), + TextTag::Em => view! { + + {children()} + + } + .into_view(), + TextTag::H1 => view! { +

+ {children()} +

+ } + .into_view(), + TextTag::H2 => view! { +

+ {children()} +

+ } + .into_view(), + TextTag::H3 => view! { +

+ {children()} +

+ } + .into_view(), + TextTag::H4 => view! { +

+ {children()} +

+ } + .into_view(), + TextTag::H5 => view! { +
+ {children()} +
+ } + .into_view(), + TextTag::H6 => view! { +
+ {children()} +
+ } + .into_view(), + TextTag::I => view! { + + {children()} + + } + .into_view(), + TextTag::P => view! { +

+ {children()} +

+ } + .into_view(), + TextTag::Pre => view! { +
+                {children()}
+            
+ } + .into_view(), TextTag::Span => view! { - + {children()} - }, - TextTag::Strong => todo!(), + } + .into_view(), + TextTag::Strong => view! { + + {children()} + + } + .into_view(), } } From ab5d17701d4530356bf4c2c8d9681f13f51b4caf Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 3 Jun 2024 17:31:59 +0800 Subject: [PATCH 033/143] refactor: tag --- thaw/src/tag/mod.rs | 67 ++++++----------------------------------- thaw/src/tag/tag.css | 67 +++++++++++++++++++++++++++++------------ thaw/src/tag/theme.rs | 44 --------------------------- thaw/src/theme/color.rs | 18 +++++++++-- thaw/src/theme/mod.rs | 7 ++--- 5 files changed, 74 insertions(+), 129 deletions(-) delete mode 100644 thaw/src/tag/theme.rs diff --git a/thaw/src/tag/mod.rs b/thaw/src/tag/mod.rs index c1b0e22..648918c 100644 --- a/thaw/src/tag/mod.rs +++ b/thaw/src/tag/mod.rs @@ -1,8 +1,4 @@ -mod theme; - -pub use theme::TagTheme; - -use crate::{theme::use_theme, Icon, Theme}; +use crate::Icon; use leptos::*; use thaw_utils::{class_list, mount_style, OptionalProp}; @@ -15,33 +11,6 @@ pub enum TagVariant { Error, } -impl TagVariant { - fn theme_font_color(&self, theme: &Theme) -> String { - match self { - TagVariant::Default => theme.tag.default_font_color.clone(), - TagVariant::Success => theme.common.color_success.clone(), - TagVariant::Warning => theme.common.color_warning.clone(), - TagVariant::Error => theme.common.color_error.clone(), - } - } - fn theme_background_color(&self, theme: &Theme) -> String { - match self { - TagVariant::Default => theme.tag.default_background_color.clone(), - TagVariant::Success => theme.tag.success_background_color.clone(), - TagVariant::Warning => theme.tag.warning_background_color.clone(), - TagVariant::Error => theme.tag.error_background_color.clone(), - } - } - fn theme_border_color(&self, theme: &Theme) -> String { - match self { - TagVariant::Default => theme.tag.default_border_color.clone(), - TagVariant::Success => theme.tag.success_border_color.clone(), - TagVariant::Warning => theme.tag.warning_border_color.clone(), - TagVariant::Error => theme.tag.error_border_color.clone(), - } - } -} - #[component] pub fn Tag( #[prop(optional, into)] variant: MaybeSignal, @@ -51,26 +20,6 @@ pub fn Tag( children: Children, ) -> impl IntoView { mount_style("tag", include_str!("./tag.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let variant = variant.get(); - css_vars.push_str(&format!( - "--thaw-font-color: {};", - variant.theme_font_color(theme) - )); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - variant.theme_background_color(theme) - )); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - variant.theme_border_color(theme) - )); - }); - css_vars - }); let on_close = move |event| { let Some(callback) = on_close.as_ref() else { @@ -80,17 +29,19 @@ pub fn Tag( }; view! { -
- {children()} + {children()} {move || { if closable.get() { view! { } .into() @@ -99,6 +50,6 @@ pub fn Tag( } }} -
+
} } diff --git a/thaw/src/tag/tag.css b/thaw/src/tag/tag.css index 08bf1a2..72949cf 100644 --- a/thaw/src/tag/tag.css +++ b/thaw/src/tag/tag.css @@ -1,33 +1,60 @@ .thaw-tag { - display: inline-flex; - height: 28px; + display: inline-grid; align-items: center; - font-size: 14px; - line-height: 1; - padding: 0 8px; - background-color: var(--thaw-background-color); - color: var(--thaw-font-color); - border: 1px solid var(--thaw-border-color); - border-radius: 3px; + grid-template-areas: + "media primary dismissIcon" + "media secondary dismissIcon"; + width: fit-content; + height: 32px; + padding: 0 7px; + background-color: var(--colorNeutralBackground3); + color: var(--colorNeutralForeground2); + font-family: inherit; + appearance: button; + text-align: unset; + box-sizing: border-box; + border: var(--strokeWidthThin) solid var(--colorTransparentStroke); + border-radius: var(--borderRadiusMedium); +} + +.thaw-tag--closable { + padding-right: 0; +} + +.thaw-tag__primary-text { + grid-row-end: secondary; + grid-row-start: primary; + grid-column-start: primary; + white-space: nowrap; + padding: 0 var(--spacingHorizontalXXS) var(--spacingHorizontalXXS); + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground2); } .thaw-tag__close { - position: relative; - right: -3px; + grid-area: dismissIcon; display: flex; - align-items: center; - justify-content: center; + padding: 0; + padding-right: 7px; + padding-left: var(--spacingHorizontalXS); + font-size: 20px; background-color: transparent; - padding: 1px; - width: 16px; - height: 16px; - color: var(--thaw-font-color); border: none; cursor: pointer; - transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.thaw-tag__close > svg { + display: inline; + line-height: 0; } .thaw-tag__close:hover { - background-color: var(--thaw-border-color); - border-radius: 3px; + color: var(--colorCompoundBrandForeground1Hover); +} + +.thaw-tag__close:active { + color: var(--colorCompoundBrandForeground1Pressed); } diff --git a/thaw/src/tag/theme.rs b/thaw/src/tag/theme.rs deleted file mode 100644 index 4d454fc..0000000 --- a/thaw/src/tag/theme.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct TagTheme { - pub default_font_color: String, - pub default_background_color: String, - pub default_border_color: String, - pub success_background_color: String, - pub success_border_color: String, - pub warning_background_color: String, - pub warning_border_color: String, - pub error_background_color: String, - pub error_border_color: String, -} - -impl ThemeMethod for TagTheme { - fn light() -> Self { - Self { - default_font_color: "#333639".into(), - default_background_color: "#fafafc".into(), - default_border_color: " #e0e0e6".into(), - success_background_color: "#edf7f2".into(), - success_border_color: "#c5e7d5".into(), - warning_background_color: "#fef7ed".into(), - warning_border_color: "#fae0b5".into(), - error_background_color: "#fbeef1".into(), - error_border_color: "#f3cbd3".into(), - } - } - - fn dark() -> Self { - Self { - default_font_color: "#ffffffd1".into(), - default_background_color: "#0000".into(), - default_border_color: "#ffffff3d".into(), - success_background_color: "#0000".into(), - success_border_color: "#63e2b74d".into(), - warning_background_color: "#0000".into(), - warning_border_color: "#f2c97d4d".into(), - error_background_color: "#0000".into(), - error_border_color: "#e880804d".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 94d7cbe..d859ffd 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -6,6 +6,9 @@ pub struct ColorTheme { pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, pub color_neutral_background_1_pressed: String, + pub color_neutral_background_3: String, + pub color_neutral_background_3_hover: String, + pub color_neutral_background_3_pressed: String, pub color_neutral_background_4: String, pub color_neutral_background_4_hover: String, pub color_neutral_background_4_pressed: String, @@ -36,7 +39,8 @@ pub struct ColorTheme { pub color_neutral_stroke_accessible_pressed: String, pub color_compound_brand_foreground_1: String, - + pub color_compound_brand_foreground_1_hover: String, + pub color_compound_brand_foreground_1_pressed: String, pub color_compound_brand_background: String, pub color_compound_brand_background_hover: String, pub color_compound_brand_background_pressed: String, @@ -61,9 +65,12 @@ impl ColorTheme { pub fn light() -> Self { Self { color_neutral_background_disabled: "#f0f0f0".into(), - color_neutral_background_1: "#fff".into(), + color_neutral_background_1: "#ffffff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_background_3: "#f5f5f5".into(), + color_neutral_background_3_hover: "#ebebeb".into(), + color_neutral_background_3_pressed: "#d6d6d6".into(), color_neutral_background_4: "#f0f0f0".into(), color_neutral_background_4_hover: "#fafafa".into(), color_neutral_background_4_pressed: "#f5f5f5".into(), @@ -94,6 +101,8 @@ impl ColorTheme { color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), color_compound_brand_foreground_1: "#0f6cbd".into(), + color_compound_brand_foreground_1_hover: "#115ea3".into(), + color_compound_brand_foreground_1_pressed: "#0f548c".into(), color_compound_brand_background: "#0f6cbd".into(), color_compound_brand_background_hover: "#115ea3".into(), @@ -122,6 +131,9 @@ impl ColorTheme { color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_background_3: "#141414".into(), + color_neutral_background_3_hover: "#292929".into(), + color_neutral_background_3_pressed: "#0a0a0a".into(), color_neutral_background_4: "#0a0a0a".into(), color_neutral_background_4_hover: "#1f1f1f".into(), color_neutral_background_4_pressed: "#000000".into(), @@ -152,6 +164,8 @@ impl ColorTheme { color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), color_compound_brand_foreground_1: "#479ef5".into(), + color_compound_brand_foreground_1_hover: "#62abf5".into(), + color_compound_brand_foreground_1_pressed: "#2886de".into(), color_compound_brand_background: "#479ef5".into(), color_compound_brand_background_hover: "#62abf5".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index be32980..af5882f 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -6,8 +6,8 @@ use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, - ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme, - TimePickerTheme, UploadTheme, + ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TimePickerTheme, + UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -26,7 +26,6 @@ pub struct Theme { pub table: TableTheme, pub alert: AlertTheme, pub skeletion: SkeletionTheme, - pub tag: TagTheme, pub message: MessageTheme, pub select: SelectTheme, pub spinner: SpinnerTheme, @@ -56,7 +55,6 @@ impl Theme { table: TableTheme::light(), alert: AlertTheme::light(), skeletion: SkeletionTheme::light(), - tag: TagTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), spinner: SpinnerTheme::light(), @@ -85,7 +83,6 @@ impl Theme { table: TableTheme::dark(), alert: AlertTheme::dark(), skeletion: SkeletionTheme::dark(), - tag: TagTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), spinner: SpinnerTheme::dark(), From 60f67bc56aa7f7d6b7527ad4c387fece42ca0ca2 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 3 Jun 2024 22:47:11 +0800 Subject: [PATCH 034/143] refactor: image --- demo_markdown/docs/image/mod.md | 11 ++++ thaw/src/image/image.css | 38 +++++++++++ thaw/src/image/mod.rs | 108 ++++++++++++++++++++++---------- 3 files changed, 124 insertions(+), 33 deletions(-) create mode 100644 thaw/src/image/image.css diff --git a/demo_markdown/docs/image/mod.md b/demo_markdown/docs/image/mod.md index 46bee1f..6540b3f 100644 --- a/demo_markdown/docs/image/mod.md +++ b/demo_markdown/docs/image/mod.md @@ -7,6 +7,17 @@ view! { } ``` +### Shape + +```rust demo +view! { + + + +} +``` + + ### Image Props | Name | Type | Default | Desciption | diff --git a/thaw/src/image/image.css b/thaw/src/image/image.css new file mode 100644 index 0000000..28efd3e --- /dev/null +++ b/thaw/src/image/image.css @@ -0,0 +1,38 @@ +.thaw-image { + display: inline-block; + box-sizing: border-box; + border-color: var(--colorNeutralStroke1); + border-radius: var(--borderRadiusNone); +} + +.thaw-image--rounded { + border-radius: var(--borderRadiusMedium); +} + +.thaw-image--circular { + border-radius: var(--borderRadiusCircular); +} + +.thaw-image--block { + width: 100%; +} + +.thaw-image-fit-none { + object-fit: none; +} +.thaw-image-fit-contain { + object-fit: contain; +} +.thaw-image-fit-cover { + object-fit: cover; +} +.thaw-image-fit-fill { + object-fit: fill; +} +.thaw-image-fit-scale-down { + object-fit: scale-down; +} + +.thaw-image--shadow { + box-shadow: var(--shadow4); +} diff --git a/thaw/src/image/mod.rs b/thaw/src/image/mod.rs index 46eaa75..89ddf4b 100644 --- a/thaw/src/image/mod.rs +++ b/thaw/src/image/mod.rs @@ -1,44 +1,86 @@ use leptos::*; -use thaw_utils::OptionalProp; +use thaw_utils::{class_list, mount_style}; #[component] pub fn Image( - #[prop(optional, into)] src: OptionalProp>, - #[prop(optional, into)] alt: OptionalProp>, - #[prop(optional, into)] width: MaybeSignal, - #[prop(optional, into)] height: MaybeSignal, - #[prop(optional, into)] border_radius: MaybeSignal, - #[prop(optional, into)] object_fit: OptionalProp>, - #[prop(optional, into)] class: OptionalProp>, + /// path to the image you want to display + #[prop(optional, into)] + src: MaybeProp, + /// description of the image, which isn't mandatory but is incredibly useful for accessibility + #[prop(optional, into)] + alt: MaybeProp, + #[prop(optional, into)] width: MaybeProp, + #[prop(optional, into)] height: MaybeProp, + /// An image can appear square, circular, or rounded. + #[prop(optional, into)] + shape: MaybeSignal, + /// An image can set how it should be resized to fit its container. + #[prop(optional, into)] + block: MaybeSignal, + /// An image can appear elevated with shadow. + #[prop(optional, into)] + shadow: MaybeSignal, + /// An image can set how it should be resized to fit its container. + #[prop(optional, into)] + fit: MaybeSignal, + #[prop(optional, into)] class: MaybeProp, ) -> impl IntoView { - let style = move || { - let mut style = String::new(); - - let width = width.get(); - if !width.is_empty() { - style.push_str(&format!("width: {width};")) - } - - let height = height.get(); - if !height.is_empty() { - style.push_str(&format!("height: {height};")) - } - - let border_radius = border_radius.get(); - if !border_radius.is_empty() { - style.push_str(&format!("border-radius: {border_radius};")) - } - - style - }; + mount_style("image", include_str!("./image.css")); view! { alt.map(|a| } } + +#[derive(Default, Clone)] +pub enum ImageShape { + Circular, + Rounded, + #[default] + Square, +} + +impl ImageShape { + pub fn as_str(&self) -> &'static str { + match self { + ImageShape::Circular => "circular", + ImageShape::Rounded => "rounded", + ImageShape::Square => "square", + } + } +} + +#[derive(Default, Clone)] +pub enum ImageFit { + None, + Contain, + Cover, + #[default] + Fill, + ScaleDown, +} + +impl ImageFit { + pub fn as_str(&self) -> &'static str { + match self { + ImageFit::None => "none", + ImageFit::Contain => "contain", + ImageFit::Cover => "cover", + ImageFit::Fill => "fill", + ImageFit::ScaleDown => "scale-down", + } + } +} From bba3f006578cfd4072913c234b3a614e1d2c8855 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 4 Jun 2024 10:13:37 +0800 Subject: [PATCH 035/143] refactor: breadcrumb --- demo/src/pages/components.rs | 8 +-- demo_markdown/docs/breadcrumb/mod.md | 26 +++---- thaw/src/breadcrumb/breadcrumb.css | 95 ++++++++++++++++++-------- thaw/src/breadcrumb/breadcrumb_item.rs | 22 ------ thaw/src/breadcrumb/mod.rs | 87 +++++++++++------------ thaw/src/breadcrumb/theme.rs | 26 ------- thaw/src/theme/mod.rs | 5 +- 7 files changed, 129 insertions(+), 140 deletions(-) delete mode 100644 thaw/src/breadcrumb/breadcrumb_item.rs delete mode 100644 thaw/src/breadcrumb/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 2a6a35f..f0a66e2 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -143,6 +143,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/avatar".into(), label: "Avatar".into(), }, + MenuItemOption { + value: "/components/breadcrumb".into(), + label: "Breadcrumb".into(), + }, MenuItemOption { value: "/components/button".into(), label: "Button".into(), @@ -239,10 +243,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/back-top".into(), label: "Back Top".into(), }, - MenuItemOption { - value: "/components/breadcrumb".into(), - label: "Breadcrumb".into(), - }, MenuItemOption { value: "/components/loading-bar".into(), label: "Loading Bar".into(), diff --git a/demo_markdown/docs/breadcrumb/mod.md b/demo_markdown/docs/breadcrumb/mod.md index b0726ca..e41228f 100644 --- a/demo_markdown/docs/breadcrumb/mod.md +++ b/demo_markdown/docs/breadcrumb/mod.md @@ -3,21 +3,17 @@ ```rust demo view! { - "Leptos" - "UI" - "Thaw" - -} -``` - -### Separator - -```rust demo -view! { - - "Leptos" - "UI" - "Thaw" + + "Leptos" + + + + "UI" + + + + "Thaw" + } ``` diff --git a/thaw/src/breadcrumb/breadcrumb.css b/thaw/src/breadcrumb/breadcrumb.css index 0cff1ff..4264fee 100644 --- a/thaw/src/breadcrumb/breadcrumb.css +++ b/thaw/src/breadcrumb/breadcrumb.css @@ -1,41 +1,82 @@ -.thaw-breadcrumb > ul { - list-style: none; - padding: 0; - margin: 0; +.thaw-breadcrumb__list { + list-style-type: none; + display: flex; + align-items: center; + margin: 0px; + padding: 0px; } .thaw-breadcrumb-item { - display: inline-flex; + display: flex; align-items: center; + color: var(--colorNeutralForeground2); + box-sizing: border-box; + flex-wrap: nowrap; } -.thaw-breadcrumb-item__separator { - margin: 0 8px; - color: var(--thaw-font-color); +.thaw-breadcrumb-button { + align-items: center; + box-sizing: border-box; + display: inline-flex; + justify-content: center; + text-decoration-line: none; + vertical-align: middle; + margin: 0px; + overflow: hidden; + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + font-family: var(--fontFamilyBase); + outline-style: none; + border-radius: var(--borderRadiusMedium); + font-size: var(--fontSizeBase300); + line-height: var(--lineHeightBase300); + transition-duration: var(--durationFaster); + transition-property: background, border, color; + transition-timing-function: var(--curveEasyEase); + + flex-wrap: nowrap; + min-width: unset; + height: 32px; + color: var(--colorNeutralForeground2); + background-color: var(--colorSubtleBackground); + border-color: transparent; + font-weight: var(--fontWeightRegular); + padding: var(--spacingHorizontalSNudge); } -.thaw-breadcrumb - .thaw-breadcrumb-item:last-child - .thaw-breadcrumb-item__separator { - display: none; -} - -.thaw-breadcrumb-item__link { - padding: 4px; - border-radius: 3px; - transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - color 0.3s cubic-bezier(0.4, 0, 0.2, 1); - color: var(--thaw-font-color); +.thaw-breadcrumb-button:hover { + color: var(--colorNeutralForeground2Hover); + background-color: var(--colorSubtleBackgroundHover); cursor: pointer; } -.thaw-breadcrumb - .thaw-breadcrumb-item:not(:last-child) - .thaw-breadcrumb-item__link:hover { - color: var(--thaw-font-color-hover); - background-color: var(--thaw-background-color-hover); +.thaw-breadcrumb-button:hover:active { + color: var(--colorNeutralForeground2Pressed); + background-color: var(--colorSubtleBackgroundPressed); + outline-style: none; } -.thaw-breadcrumb .thaw-breadcrumb-item:last-child .thaw-breadcrumb-item__link { - color: var(--thaw-font-color-hover); +.thaw-breadcrumb-button--current { + font-weight: var(--fontWeightSemibold); +} + +.thaw-breadcrumb-button--current:hover { + color: var(--colorNeutralForeground2); + background-color: var(--colorTransparentBackground); + cursor: auto; +} + +.thaw-breadcrumb-button--current:hover:active { + color: var(--colorNeutralForeground2); + background-color: var(--colorTransparentBackground); + outline-style: none; +} + +.thaw-breadcrumb-divider { + font-size: 16px; + display: flex; +} + +.thaw-breadcrumb-divider > svg { + display: inline; + line-height: 0; } diff --git a/thaw/src/breadcrumb/breadcrumb_item.rs b/thaw/src/breadcrumb/breadcrumb_item.rs deleted file mode 100644 index 826742b..0000000 --- a/thaw/src/breadcrumb/breadcrumb_item.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::use_breadcrumb_separator; -use leptos::*; -use thaw_utils::{class_list, OptionalProp}; - -#[component] -pub fn BreadcrumbItem( - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { - let breadcrumb_separator = use_breadcrumb_separator(); - - view! { -
  • - {children()} - - {move || breadcrumb_separator.0.get()} - -
  • - } -} diff --git a/thaw/src/breadcrumb/mod.rs b/thaw/src/breadcrumb/mod.rs index 6332243..eaf69ff 100644 --- a/thaw/src/breadcrumb/mod.rs +++ b/thaw/src/breadcrumb/mod.rs @@ -1,55 +1,58 @@ -mod breadcrumb_item; -mod theme; - -pub use theme::BreadcrumbTheme; - -use crate::{use_theme, Theme}; -pub use breadcrumb_item::BreadcrumbItem; use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_utils::{class_list, mount_style}; #[component] pub fn Breadcrumb( - #[prop(default = MaybeSignal::Static("/".to_string()),into)] separator: MaybeSignal, - #[prop(optional, into)] class: OptionalProp>, + #[prop(optional, into)] class: MaybeProp, children: Children, ) -> impl IntoView { mount_style("breadcrumb", include_str!("./breadcrumb.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-font-color: {};", - theme.breadcrumb.item_font_color - )); - css_vars.push_str(&format!( - "--thaw-font-color-hover: {};", - theme.breadcrumb.item_font_color_hover - )); - css_vars.push_str(&format!( - "--thaw-background-color-hover: {};", - theme.breadcrumb.item_background_color_hover - )); - }); - css_vars - }); view! { - - - + } } -#[derive(Clone)] -pub(crate) struct BreadcrumbSeparatorInjection(MaybeSignal); - -pub(crate) fn use_breadcrumb_separator() -> BreadcrumbSeparatorInjection { - expect_context() +#[component] +pub fn BreadcrumbItem( + #[prop(optional, into)] class: MaybeProp, + children: Children, +) -> impl IntoView { + view! { +
  • + {children()} +
  • + } +} + +#[component] +pub fn BreadcrumbButton( + #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] current: MaybeSignal, + children: Children, +) -> impl IntoView { + view! { + + } +} + +#[component] +pub fn BreadcrumbDivider(#[prop(optional, into)] class: MaybeProp) -> impl IntoView { + view! { + + } } diff --git a/thaw/src/breadcrumb/theme.rs b/thaw/src/breadcrumb/theme.rs deleted file mode 100644 index 96f196f..0000000 --- a/thaw/src/breadcrumb/theme.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct BreadcrumbTheme { - pub item_font_color: String, - pub item_font_color_hover: String, - pub item_background_color_hover: String, -} - -impl ThemeMethod for BreadcrumbTheme { - fn light() -> Self { - Self { - item_font_color: "#767c82".into(), - item_font_color_hover: "#333639".into(), - item_background_color_hover: "#2e333817".into(), - } - } - - fn dark() -> Self { - Self { - item_font_color: "#ffffff85".into(), - item_font_color_hover: "#ffffffd1".into(), - item_background_color_hover: "#ffffff1f".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index af5882f..639c291 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,7 +4,7 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, + AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TimePickerTheme, UploadTheme, @@ -34,7 +34,6 @@ pub struct Theme { pub tabbar: TabbarTheme, pub auto_complete: AutoCompleteTheme, pub color_picker: ColorPickerTheme, - pub breadcrumb: BreadcrumbTheme, pub progress: ProgressTheme, pub calendar: CalendarTheme, pub time_picker: TimePickerTheme, @@ -63,7 +62,6 @@ impl Theme { tabbar: TabbarTheme::light(), auto_complete: AutoCompleteTheme::light(), color_picker: ColorPickerTheme::light(), - breadcrumb: BreadcrumbTheme::light(), progress: ProgressTheme::light(), calendar: CalendarTheme::light(), time_picker: TimePickerTheme::light(), @@ -91,7 +89,6 @@ impl Theme { tabbar: TabbarTheme::dark(), auto_complete: AutoCompleteTheme::dark(), color_picker: ColorPickerTheme::dark(), - breadcrumb: BreadcrumbTheme::dark(), progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), time_picker: TimePickerTheme::dark(), From 18bfea1731c37a25ff4562e9268c88b3281e8904 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 4 Jun 2024 14:18:15 +0800 Subject: [PATCH 036/143] refactor: spinner --- demo/src/pages/components.rs | 16 +-- demo_markdown/docs/spinner/mod.md | 14 ++- thaw/src/spinner/mod.rs | 78 +++++++------ thaw/src/spinner/spinner.css | 181 +++++++++++++++++++++++++++--- thaw/src/spinner/theme.rs | 20 ---- thaw/src/theme/color.rs | 8 ++ thaw/src/theme/common.rs | 8 ++ thaw/src/theme/mod.rs | 10 +- 8 files changed, 250 insertions(+), 85 deletions(-) delete mode 100644 thaw/src/spinner/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index f0a66e2..0094390 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -167,6 +167,14 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/icon".into(), label: "Icon".into(), }, + MenuItemOption { + value: "/components/spin-button".into(), + label: "Spin Button".into(), + }, + MenuItemOption { + value: "/components/spinner".into(), + label: "Spinner".into(), + }, MenuItemOption { value: "/components/tag".into(), label: "Tag".into(), @@ -175,10 +183,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/text".into(), label: "Text".into(), }, - MenuItemOption { - value: "/components/spin-button".into(), - label: "Spin Button".into(), - }, MenuItemOption { value: "/components/auto-complete".into(), label: "Auto Complete".into(), @@ -279,10 +283,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/progress".into(), label: "Progress".into(), }, - MenuItemOption { - value: "/components/spinner".into(), - label: "Spinner".into(), - }, MenuItemOption { value: "/components/skeleton".into(), label: "Skeleton".into(), diff --git a/demo_markdown/docs/spinner/mod.md b/demo_markdown/docs/spinner/mod.md index f3f2f9c..3e9c507 100644 --- a/demo_markdown/docs/spinner/mod.md +++ b/demo_markdown/docs/spinner/mod.md @@ -10,11 +10,15 @@ view! { ```rust demo view! { - - - - - + + + + + + + + + } ``` diff --git a/thaw/src/spinner/mod.rs b/thaw/src/spinner/mod.rs index 42c9e88..8b68b5f 100644 --- a/thaw/src/spinner/mod.rs +++ b/thaw/src/spinner/mod.rs @@ -1,58 +1,72 @@ -mod theme; - -pub use theme::SpinnerTheme; - -use crate::{theme::use_theme, Theme}; use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_utils::{class_list, mount_style}; #[derive(Default, Clone)] pub enum SpinnerSize { + ExtraTiny, Tiny, + ExtraSmall, Small, #[default] Medium, Large, + ExtraLarge, + Huge, } impl SpinnerSize { - fn theme_height(&self, theme: &Theme) -> String { + pub fn as_str(&self) -> &'static str { match self { - SpinnerSize::Tiny => theme.common.height_tiny.clone(), - SpinnerSize::Small => theme.common.height_small.clone(), - SpinnerSize::Medium => theme.common.height_medium.clone(), - SpinnerSize::Large => theme.common.height_large.clone(), + SpinnerSize::ExtraTiny => "extra-tiny", + SpinnerSize::Tiny => "tiny", + SpinnerSize::ExtraSmall => "extra-small", + SpinnerSize::Small => "small", + SpinnerSize::Medium => "medium", + SpinnerSize::Large => "large", + SpinnerSize::ExtraLarge => "extra-large", + SpinnerSize::Huge => "huge", } } } #[component] pub fn Spinner( - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] size: MaybeSignal, + #[prop(optional, into)] class: MaybeProp, + /// An optional label for the Spinner. + #[prop(optional, into)] + label: MaybeProp, + /// The size of the spinner. + #[prop(optional, into)] + size: MaybeSignal, ) -> impl IntoView { mount_style("spinner", include_str!("./spinner.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-height: {};", - size.get().theme_height(theme) - )); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - &theme.spinner.background_color - )); - css_vars.push_str(&format!("--thaw-color: {};", &theme.common.color_primary)); - }); - css_vars - }); + let id = StoredValue::new(uuid::Uuid::new_v4().to_string()); + + let spinner_label = label.clone(); + let labelledby = move || spinner_label.with(|_| true).map(|_| id.get_value()); view! {
    + class=class_list!["thaw-spinner", move || format!("thaw-spinner--{}", size.get().as_str()), class] + role="progressbar" + aria-labelledby=labelledby + > + + + + { + move || { + if let Some(label) = label.get() { + view! { + + }.into() + } else { + None + } + } + } +
    } } diff --git a/thaw/src/spinner/spinner.css b/thaw/src/spinner/spinner.css index 79ab833..d84d433 100644 --- a/thaw/src/spinner/spinner.css +++ b/thaw/src/spinner/spinner.css @@ -1,17 +1,172 @@ .thaw-spinner { - border-color: var(--thaw-color); - border-left-color: var(--thaw-background-color); - border-style: solid; - border-radius: 100px; - border-width: 2px; - width: var(--thaw-height); - height: var(--thaw-height); - outline: 1px solid transparent; - animation: 1s linear 0s infinite normal none running spin; - box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + gap: 8px; + overflow: hidden; } -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } +.thaw-spinner__spinner { + width: 32px; + height: 32px; + position: relative; + flex-shrink: 0; + mask-image: radial-gradient( + closest-side, + transparent calc(100% - var(--thaw-spinner--stroke-width) - 1px), + white calc(100% - var(--thaw-spinner--stroke-width)) calc(100% - 1px), + transparent 100% + ); + background-color: var(--colorBrandStroke2Contrast); + color: var(--colorBrandStroke1); + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-timing-function: linear; + animation-name: thaw-spinner; + + --thaw-spinner--stroke-width: var(--strokeWidthThicker); +} + +.thaw-spinner--extra-tiny > .thaw-spinner__spinner { + --thaw-spinner--stroke-width: var(--strokeWidthThick); + width: 16px; + height: 16px; +} + +.thaw-spinner--tiny > .thaw-spinner__spinner { + --thaw-spinner--stroke-width: var(--strokeWidthThick); + width: 20px; + height: 20px; +} + +.thaw-spinner--extra-small > .thaw-spinner__spinner { + --thaw-spinner--stroke-width: var(--strokeWidthThick); + width: 24px; + height: 24px; +} + +.thaw-spinner--small > .thaw-spinner__spinner { + --thaw-spinner--stroke-width: var(--strokeWidthThick); + width: 28px; + height: 28px; +} + +.thaw-spinner--medium > .thaw-spinner__spinner { + width: 32px; + height: 32px; +} + +.thaw-spinner--large > .thaw-spinner__spinner { + width: 36px; + height: 36px; +} + +.thaw-spinner--extra-large > .thaw-spinner__spinner { + width: 40px; + height: 40px; +} + +.thaw-spinner--huge > .thaw-spinner__spinner { + --thaw-spinner--stroke-width: var(--strokeWidthThickest); + width: 44px; + height: 44px; +} + +@keyframes thaw-spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.thaw-spinner__spinner-tail { + position: absolute; + display: block; + width: 100%; + height: 100%; + mask-image: conic-gradient(transparent 105deg, white 105deg); + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-timing-function: var(--curveEasyEase); + animation-name: thaw-spinner-tail; +} + +@keyframes thaw-spinner-tail { + 0% { + transform: rotate(-135deg); + } + 50% { + transform: rotate(0deg); + } + 100% { + transform: rotate(225deg); + } +} + +.thaw-spinner__spinner-tail::before, +.thaw-spinner__spinner-tail::after { + content: ""; + position: absolute; + display: block; + width: 100%; + height: 100%; + animation: inherit; + background-image: conic-gradient(currentcolor 135deg, transparent 135deg); +} + +.thaw-spinner__spinner-tail::before { + animation-name: thaw-spinner-tail-before; +} + +@keyframes thaw-spinner-tail-before { + 0% { + transform: rotate(0deg); + } + 50% { + transform: rotate(105deg); + } + 100% { + transform: rotate(0deg); + } +} + +.thaw-spinner__spinner-tail::after { + animation-name: thaw-spinner-tail-after; +} + +@keyframes thaw-spinner-tail-after { + 0% { + transform: rotate(0deg); + } + 50% { + transform: rotate(225deg); + } + 100% { + transform: rotate(0deg); + } +} + +.thaw-spinner__label { + font-family: var(--fontFamilyBase); + font-weight: var(--fontWeightSemibold); + font-size: var(--fontSizeBase400); + line-height: var(--lineHeightBase400); + color: var(--colorNeutralForeground1); +} + +.thaw-spinner--extra-tiny > .thaw-spinner__label, +.thaw-spinner--tiny > .thaw-spinner__label, +.thaw-spinner--extra-small > .thaw-spinner__label, +.thaw-spinner--small > .thaw-spinner__label { + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + line-height: var(--lineHeightBase300); +} + +.thaw-spinner--huge > .thaw-spinner__label { + font-size: var(--fontSizeBase500); + line-height: var(--lineHeightBase500); } diff --git a/thaw/src/spinner/theme.rs b/thaw/src/spinner/theme.rs deleted file mode 100644 index e7e7bb2..0000000 --- a/thaw/src/spinner/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SpinnerTheme { - pub background_color: String, -} - -impl ThemeMethod for SpinnerTheme { - fn light() -> Self { - Self { - background_color: "#0000000a".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#2b2f31".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index d859ffd..f5148bf 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -50,6 +50,9 @@ pub struct ColorTheme { pub color_brand_background: String, pub color_brand_background_hover: String, pub color_brand_background_pressed: String, + pub color_brand_stroke_1: String, + pub color_brand_stroke_2_contrast: String, + pub color_subtle_background: String, pub color_subtle_background_hover: String, pub color_subtle_background_pressed: String, @@ -113,6 +116,8 @@ impl ColorTheme { color_brand_background: "#0f6cbd".into(), color_brand_background_hover: "#115ea3".into(), color_brand_background_pressed: "#0c3b5e".into(), + color_brand_stroke_1: "#0f6cbd".into(), + color_brand_stroke_2_contrast: "#b4d6fa".into(), color_subtle_background: "transparent".into(), color_subtle_background_hover: "#f5f5f5".into(), color_subtle_background_pressed: "#e0e0e0".into(), @@ -176,6 +181,9 @@ impl ColorTheme { color_brand_background: "#115ea3".into(), color_brand_background_hover: "#0f6cbd".into(), color_brand_background_pressed: "#0c3b5e".into(), + color_brand_stroke_1: "#479ef5".into(), + color_brand_stroke_2_contrast: "#0e4775".into(), + color_subtle_background: "transparent".into(), color_subtle_background_hover: "#383838".into(), color_subtle_background_pressed: "#2e2e2e".into(), diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index fd74955..2baa548 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -34,12 +34,16 @@ pub struct CommonTheme { pub line_height_base_200: String, pub line_height_base_300: String, pub line_height_base_400: String, + pub line_height_base_500: String, pub font_weight_regular: String, pub font_weight_semibold: String, pub font_weight_bold: String, pub stroke_width_thin: String, + pub stroke_width_thick: String, + pub stroke_width_thicker: String, + pub stroke_width_thickest: String, pub border_radius_none: String, pub border_radius_medium: String, @@ -107,12 +111,16 @@ impl CommonTheme { line_height_base_200: "16px".into(), line_height_base_300: "20px".into(), line_height_base_400: "22px".into(), + line_height_base_500: "28px".into(), font_weight_regular: "400".into(), font_weight_semibold: "600".into(), font_weight_bold: "700".into(), stroke_width_thin: "1px".into(), + stroke_width_thick: "2px".into(), + stroke_width_thicker: "3px".into(), + stroke_width_thickest: "4px".into(), border_radius_none: "0".into(), border_radius_medium: "4px".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 639c291..e053a62 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,10 +4,9 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, - ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, - ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TimePickerTheme, - UploadTheme, + AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, + DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, + SelectTheme, SkeletionTheme, TableTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -28,7 +27,6 @@ pub struct Theme { pub skeletion: SkeletionTheme, pub message: MessageTheme, pub select: SelectTheme, - pub spinner: SpinnerTheme, pub upload: UploadTheme, pub nav_bar: NavBarTheme, pub tabbar: TabbarTheme, @@ -56,7 +54,6 @@ impl Theme { skeletion: SkeletionTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - spinner: SpinnerTheme::light(), upload: UploadTheme::light(), nav_bar: NavBarTheme::light(), tabbar: TabbarTheme::light(), @@ -83,7 +80,6 @@ impl Theme { skeletion: SkeletionTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), - spinner: SpinnerTheme::dark(), upload: UploadTheme::dark(), nav_bar: NavBarTheme::dark(), tabbar: TabbarTheme::dark(), From c7da724cdc4232ed872f3e2fa9d313d6f6b9087d Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 4 Jun 2024 17:30:40 +0800 Subject: [PATCH 037/143] refactor: tab --- demo_markdown/docs/tabs/mod.md | 41 ++----- thaw/src/tabs/mod.rs | 203 +++++++-------------------------- thaw/src/tabs/tab-list.css | 8 ++ thaw/src/tabs/tab.css | 60 +++++++++- thaw/src/tabs/tab.rs | 82 +++++-------- thaw/src/tabs/tabs.css | 20 ---- thaw/src/theme/common.rs | 2 + 7 files changed, 143 insertions(+), 273 deletions(-) create mode 100644 thaw/src/tabs/tab-list.css delete mode 100644 thaw/src/tabs/tabs.css diff --git a/demo_markdown/docs/tabs/mod.md b/demo_markdown/docs/tabs/mod.md index fdc30dc..f473ad7 100644 --- a/demo_markdown/docs/tabs/mod.md +++ b/demo_markdown/docs/tabs/mod.md @@ -1,44 +1,17 @@ # Tabs ```rust demo -let value = create_rw_signal(String::from("apple")); +let selected_value = RwSignal::new(String::new()); view! { - - - "apple" + + + "🍎 Apple" - - "pear" + + "🍐 Pear" - -} -``` - -### Custom tab label - -```rust demo -use leptos_meta::Style; -let value = create_rw_signal(String::from("apple")); - -view! { - - - - - "🍎 Apple" - - "apple" - - - - "🍐 Pear" - - "pear" - - + } ``` diff --git a/thaw/src/tabs/mod.rs b/thaw/src/tabs/mod.rs index 6da1e0a..68cc5c7 100644 --- a/thaw/src/tabs/mod.rs +++ b/thaw/src/tabs/mod.rs @@ -2,189 +2,72 @@ mod tab; pub use tab::*; -use crate::{theme::use_theme, Theme}; use leptos::*; -use thaw_utils::{class_list, mount_style, Model, OptionalProp}; +use std::collections::HashMap; +use thaw_utils::{class_list, mount_style, Model}; #[component] -pub fn Tabs( - #[prop(optional, into)] value: Model, - #[prop(optional, into)] class: OptionalProp>, +pub fn TabList( + #[prop(optional, into)] selected_value: Model, + #[prop(optional, into)] class: MaybeProp, children: Children, ) -> impl IntoView { - mount_style("tabs", include_str!("./tabs.css")); - let tab_options_vec = create_rw_signal(vec![]); + mount_style("tab-list", include_str!("./tab-list.css")); + let registered_tabs = RwSignal::new(HashMap::new()); + // request_animation_frame(move || { + // let list_rect = label_list.get_bounding_client_rect(); + // let rect = label.get_bounding_client_rect(); + // label_line + // .set( + // Some(TabsLabelLine { + // width: rect.width(), + // left: rect.left() - list_rect.left(), + // }), + // ); + // }); view! { - - +
    + {children()} +
    } } -#[component] -fn TabsInner( - value: Model, - tab_options_vec: RwSignal>, - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { - mount_style("tabs", include_str!("./tabs.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let color_primary = theme.common.color_primary.clone(); - css_vars.push_str(&format!( - "--thaw-label-active-background-color: {color_primary};" - )); - }); - css_vars - }); - - let label_line = create_rw_signal::>(None); - let label_line_style = create_memo(move |_| { - let mut style = String::new(); - if let Some(line) = label_line.get() { - style.push_str(&format!("width: {}px; left: {}px", line.width, line.left)) - } - style - }); - let label_list_ref = create_node_ref::(); - - let children = children(); - - view! { -
    -
    - (); - let TabOption { key, label, label_view } = option; - create_effect({ - let key = key.clone(); - move |_| { - let Some(label) = label_ref.get() else { - return; - }; - let Some(label_list) = label_list_ref.get() else { - return; - }; - if key.clone() == value.get() { - request_animation_frame(move || { - let list_rect = label_list.get_bounding_client_rect(); - let rect = label.get_bounding_client_rect(); - label_line - .set( - Some(TabsLabelLine { - width: rect.width(), - left: rect.left() - list_rect.left(), - }), - ); - }); - } - } - }); - let is_active = create_memo({ - let key = key.clone(); - move |_| key == value.get() - }); - if let Some(label_view) = label_view { - let TabLabelView { class, children } = label_view; - view! { - - - {children} - - } - } else { - view! { - - - {if label.is_empty() { key } else { label }} - - } - } - } - /> - - -
    -
    {children}
    -
    - } -} - #[derive(Clone)] -pub(crate) struct TabsLabelLine { - width: f64, - left: f64, +pub(crate) struct TabListInjection { + pub selected_value: Model, + registered_tabs: RwSignal>, } -#[derive(Clone)] -pub(crate) struct TabsInjection { - active_key: Model, - tab_options_vec: RwSignal>, -} +impl Copy for TabListInjection {} -impl TabsInjection { - pub fn get_key(&self) -> String { - self.active_key.get() +impl TabListInjection { + pub fn use_() -> Self { + expect_context() } - pub(crate) fn push_tab_options(&self, options: TabOption) { - self.tab_options_vec.update(|v| { - v.push(options); + pub fn register(&self, data: TabRegisterData) { + self.registered_tabs.update(|map| { + map.insert(data.value.clone(), data); }); } - pub(crate) fn remove_tab_options(&self, key: &String) { - self.tab_options_vec.update(|v| { - if let Some(index) = v.iter().position(|tab| &tab.key == key) { - v.remove(index); - } + pub fn unregister(&self, value: &String) { + self.registered_tabs.update(|map| { + map.remove(value); }); } } -pub(crate) fn use_tabs() -> TabsInjection { - expect_context() +pub(crate) struct TabRegisterData { + value: String, + tab_ref: NodeRef, } diff --git a/thaw/src/tabs/tab-list.css b/thaw/src/tabs/tab-list.css new file mode 100644 index 0000000..74eefac --- /dev/null +++ b/thaw/src/tabs/tab-list.css @@ -0,0 +1,8 @@ +.thaw-tab-list { + position: relative; + display: flex; + flex-wrap: nowrap; + flex-direction: row; + flex-shrink: 0; + align-items: stretch; +} \ No newline at end of file diff --git a/thaw/src/tabs/tab.css b/thaw/src/tabs/tab.css index 4360944..b934239 100644 --- a/thaw/src/tabs/tab.css +++ b/thaw/src/tabs/tab.css @@ -1,7 +1,61 @@ .thaw-tab { - padding-top: 12px; + flex-shrink: 0; + justify-content: center; + align-items: center; + outline-style: none; + position: relative; + display: grid; + grid-template-rows: auto; + grid-template-columns: auto; + grid-auto-flow: column; + column-gap: var(--spacingHorizontalSNudge); + background-color: var(--colorTransparentBackground); + line-height: var(--lineHeightBase300); + font-family: var(--fontFamilyBase); + text-transform: none; + padding: var(--spacingVerticalM) var(--spacingHorizontalMNudge); + cursor: pointer; + overflow: hidden; + border-radius: var(--borderRadiusMedium); + border: none; } -.thaw-tab--hidden { - display: none; +.thaw-tab::before { + right: var(--spacingHorizontalM); + left: var(--spacingHorizontalM); + height: var(--strokeWidthThicker); + bottom: 0px; +} + +.thaw-tab:hover::before { + position: absolute; + content: ""; + background-color: var(--colorNeutralStroke1Hover); + border-radius: var(--borderRadiusCircular); +} + +.thaw-tab:active::before { + position: absolute; + content: ""; + background-color: var(--colorNeutralStroke1Pressed); + border-radius: var(--borderRadiusCircular); +} + +.thaw-tab__content { + grid-row-start: 1; + grid-column-start: 1; + padding: var(--spacingVerticalNone) var(--spacingHorizontalXXS); + color: var(--colorNeutralForeground2); + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + overflow: hidden; +} + +.thaw-tab:hover .thaw-tab__content { + color: var(--colorNeutralForeground2Hover); +} + +.thaw-tab:active .thaw-tab__content { + color: var(--colorNeutralForeground2Pressed); } diff --git a/thaw/src/tabs/tab.rs b/thaw/src/tabs/tab.rs index 3332ad6..8781775 100644 --- a/thaw/src/tabs/tab.rs +++ b/thaw/src/tabs/tab.rs @@ -1,74 +1,44 @@ -use super::use_tabs; +use super::{TabListInjection, TabRegisterData}; use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; - -#[derive(Clone)] -pub(crate) struct TabOption { - pub key: String, - pub label: String, - pub label_view: Option, -} - -#[derive(Clone)] -pub(crate) struct TabLabelView { - pub class: OptionalProp>, - pub children: Fragment, -} - -impl From for TabLabelView { - fn from(tab_label: TabLabel) -> Self { - let TabLabel { class, children } = tab_label; - Self { - class, - children: children(), - } - } -} - -#[slot] -pub struct TabLabel { - #[prop(optional, into)] - class: OptionalProp>, - children: Children, -} +use thaw_utils::{class_list, mount_style}; #[component] pub fn Tab( - #[prop(into)] key: String, - #[prop(optional, into)] label: String, - #[prop(optional)] tab_label: Option, - #[prop(optional, into)] class: OptionalProp>, + #[prop(optional, into)] class: MaybeProp, + #[prop(into)] value: String, children: Children, ) -> impl IntoView { mount_style("tab", include_str!("./tab.css")); - let tabs = use_tabs(); - tabs.push_tab_options(TabOption { - key: key.clone(), - label, - label_view: tab_label.map(|label| label.into()), - }); - let is_active = create_memo({ - let key = key.clone(); - let tabs = tabs.clone(); - move |_| key == tabs.get_key() + let tab_ref = NodeRef::::new(); + let tab_list = TabListInjection::use_(); + let value = StoredValue::new(value); + tab_list.register(TabRegisterData { + value: value.get_value(), + tab_ref, }); - on_cleanup(move || { - tabs.remove_tab_options(&key); + value.with_value(|v| tab_list.unregister(v)); + }); + + let selected = Memo::new(move |_| { + tab_list + .selected_value + .with(|selected_value| value.with_value(|value| value == selected_value)) }); view! { -
    - {children()} -
    + + {children()} + + } } diff --git a/thaw/src/tabs/tabs.css b/thaw/src/tabs/tabs.css deleted file mode 100644 index 173c331..0000000 --- a/thaw/src/tabs/tabs.css +++ /dev/null @@ -1,20 +0,0 @@ -.thaw-tabs__label-list { - position: relative; -} - -.thaw-tabs__label { - padding: 0 20px; - display: inline-block; - height: 40px; - line-height: 40px; - cursor: pointer; -} - -.thaw-tabs-label__line { - position: absolute; - height: 3px; - background-color: var(--thaw-label-active-background-color); - border-radius: 3px; - bottom: 0; - left: 0; -} diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 2baa548..64eadd0 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -59,6 +59,7 @@ pub struct CommonTheme { pub spacing_horizontal_l: String, pub spacing_vertical_s: String, pub spacing_vertical_m_nudge: String, + pub spacing_vertical_m: String, pub spacing_vertical_l: String, pub duration_ultra_fast: String, @@ -136,6 +137,7 @@ impl CommonTheme { spacing_horizontal_l: "16px".into(), spacing_vertical_s: "8px".into(), spacing_vertical_m_nudge: "10px".into(), + spacing_vertical_m: "12px".into(), spacing_vertical_l: "16px".into(), duration_ultra_fast: "50ms".into(), From 938342ab1f6e86458f6ec1d2182f0f21bb92149e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 4 Jun 2024 23:12:21 +0800 Subject: [PATCH 038/143] feat: tab select --- thaw/src/tabs/mod.rs | 30 ++++++++++++++--------------- thaw/src/tabs/tab.css | 25 ++++++++++++++++++++++++ thaw/src/tabs/tab.rs | 41 +++++++++++++++++++++++++++++++++++++++- thaw/src/theme/common.rs | 4 ++++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/thaw/src/tabs/mod.rs b/thaw/src/tabs/mod.rs index 68cc5c7..6cb6458 100644 --- a/thaw/src/tabs/mod.rs +++ b/thaw/src/tabs/mod.rs @@ -8,26 +8,19 @@ use thaw_utils::{class_list, mount_style, Model}; #[component] pub fn TabList( - #[prop(optional, into)] selected_value: Model, #[prop(optional, into)] class: MaybeProp, + /// The value of the currently selected tab. + #[prop(optional, into)] + selected_value: Model, children: Children, ) -> impl IntoView { mount_style("tab-list", include_str!("./tab-list.css")); let registered_tabs = RwSignal::new(HashMap::new()); - // request_animation_frame(move || { - // let list_rect = label_list.get_bounding_client_rect(); - // let rect = label.get_bounding_client_rect(); - // label_line - // .set( - // Some(TabsLabelLine { - // width: rect.width(), - // left: rect.left() - list_rect.left(), - // }), - // ); - // }); + view! { @@ -43,8 +36,9 @@ pub fn TabList( #[derive(Clone)] pub(crate) struct TabListInjection { + pub previous_selected_value: StoredValue, pub selected_value: Model, - registered_tabs: RwSignal>, + pub registered_tabs: RwSignal>, } impl Copy for TabListInjection {} @@ -65,9 +59,15 @@ impl TabListInjection { map.remove(value); }); } + + pub fn on_select(&self, value: String) { + self.previous_selected_value + .set_value(self.selected_value.get_untracked()); + self.selected_value.set(value); + } } pub(crate) struct TabRegisterData { - value: String, - tab_ref: NodeRef, + pub value: String, + pub tab_ref: NodeRef, } diff --git a/thaw/src/tabs/tab.css b/thaw/src/tabs/tab.css index b934239..4f9fd7d 100644 --- a/thaw/src/tabs/tab.css +++ b/thaw/src/tabs/tab.css @@ -59,3 +59,28 @@ .thaw-tab:active .thaw-tab__content { color: var(--colorNeutralForeground2Pressed); } + +.thaw-tab--selected { + overflow: visible; +} + +.thaw-tab--selected .thaw-tab__content { + font-weight: var(--fontWeightSemibold); +} + +.thaw-tab--selected::after { + position: absolute; + content: ""; + transform: translateX(var(--thaw-tab__indicator--offset)) + scaleX(var(--thaw-tab__indicator--scale)); + transform-origin: left center; + transition-timing-function: var(--curveDecelerateMax); + transition-duration: var(--durationSlow); + transition-property: transform; + right: var(--spacingHorizontalM); + left: var(--spacingHorizontalM); + height: var(--strokeWidthThicker); + bottom: 0px; + background-color: var(--colorCompoundBrandStroke); + border-radius: var(--borderRadiusCircular); +} diff --git a/thaw/src/tabs/tab.rs b/thaw/src/tabs/tab.rs index 8781775..32d4484 100644 --- a/thaw/src/tabs/tab.rs +++ b/thaw/src/tabs/tab.rs @@ -1,5 +1,6 @@ use super::{TabListInjection, TabRegisterData}; use leptos::*; +use std::ops::Deref; use thaw_utils::{class_list, mount_style}; #[component] @@ -27,14 +28,52 @@ pub fn Tab( .with(|selected_value| value.with_value(|value| value == selected_value)) }); + Effect::new(move |_| { + let selected = selected.get(); + if selected { + tab_list.registered_tabs.with_untracked(|registered_tabs| { + if let Some(previous_selected_tab) = tab_list + .previous_selected_value + .with_value(|selected_value| registered_tabs.get(selected_value)) + { + let tab_el = tab_ref.get_untracked().unwrap(); + let selected_tab_rect = tab_el.get_bounding_client_rect(); + let previous_selected_tab_rect = previous_selected_tab + .tab_ref + .get_untracked() + .unwrap() + .get_bounding_client_rect(); + + let offset = previous_selected_tab_rect.x() - selected_tab_rect.x(); + let scale = previous_selected_tab_rect.width() / selected_tab_rect.width(); + + let style = tab_el.deref().style(); + let _ = style + .set_property("--thaw-tab__indicator--offset", &format!("{offset:.0}px")); + let _ = + style.set_property("--thaw-tab__indicator--scale", &format!("{scale:.2}")); + + // let _ = style.get_property_value("offsetWidth"); + + // let _ = style.set_property("--thaw-tab__indicator--offset", "0px"); + // let _ = style.set_property("--thaw-tab__indicator--scale", "1"); + } + }) + } + + selected + }); + view! { + } +} diff --git a/thaw/src/tabs/tab.rs b/thaw/src/tabs/tab.rs deleted file mode 100644 index 32d4484..0000000 --- a/thaw/src/tabs/tab.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::{TabListInjection, TabRegisterData}; -use leptos::*; -use std::ops::Deref; -use thaw_utils::{class_list, mount_style}; - -#[component] -pub fn Tab( - #[prop(optional, into)] class: MaybeProp, - #[prop(into)] value: String, - children: Children, -) -> impl IntoView { - mount_style("tab", include_str!("./tab.css")); - - let tab_ref = NodeRef::::new(); - let tab_list = TabListInjection::use_(); - let value = StoredValue::new(value); - tab_list.register(TabRegisterData { - value: value.get_value(), - tab_ref, - }); - on_cleanup(move || { - value.with_value(|v| tab_list.unregister(v)); - }); - - let selected = Memo::new(move |_| { - tab_list - .selected_value - .with(|selected_value| value.with_value(|value| value == selected_value)) - }); - - Effect::new(move |_| { - let selected = selected.get(); - if selected { - tab_list.registered_tabs.with_untracked(|registered_tabs| { - if let Some(previous_selected_tab) = tab_list - .previous_selected_value - .with_value(|selected_value| registered_tabs.get(selected_value)) - { - let tab_el = tab_ref.get_untracked().unwrap(); - let selected_tab_rect = tab_el.get_bounding_client_rect(); - let previous_selected_tab_rect = previous_selected_tab - .tab_ref - .get_untracked() - .unwrap() - .get_bounding_client_rect(); - - let offset = previous_selected_tab_rect.x() - selected_tab_rect.x(); - let scale = previous_selected_tab_rect.width() / selected_tab_rect.width(); - - let style = tab_el.deref().style(); - let _ = style - .set_property("--thaw-tab__indicator--offset", &format!("{offset:.0}px")); - let _ = - style.set_property("--thaw-tab__indicator--scale", &format!("{scale:.2}")); - - // let _ = style.get_property_value("offsetWidth"); - - // let _ = style.set_property("--thaw-tab__indicator--offset", "0px"); - // let _ = style.set_property("--thaw-tab__indicator--scale", "1"); - } - }) - } - - selected - }); - - view! { - - } -} diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index ff8179d..f720706 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -57,6 +57,7 @@ pub struct CommonTheme { pub spacing_horizontal_m_nudge: String, pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, + pub spacing_vertical_none: String, pub spacing_vertical_s: String, pub spacing_vertical_m_nudge: String, pub spacing_vertical_m: String, @@ -137,6 +138,7 @@ impl CommonTheme { spacing_horizontal_m_nudge: "10px".into(), spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), + spacing_vertical_none: "0".into(), spacing_vertical_s: "8px".into(), spacing_vertical_m_nudge: "10px".into(), spacing_vertical_m: "12px".into(), From bd9a4190029a190a1cabe19805bf567113c7d43a Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 5 Jun 2024 11:30:04 +0800 Subject: [PATCH 040/143] fix: tab selected bold style --- thaw/src/tab_list/tab.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/thaw/src/tab_list/tab.css b/thaw/src/tab_list/tab.css index 4f9fd7d..808042c 100644 --- a/thaw/src/tab_list/tab.css +++ b/thaw/src/tab_list/tab.css @@ -64,8 +64,17 @@ overflow: visible; } +/* https://stackoverflow.com/questions/5687035/css-bolding-some-text-without-changing-its-containers-size/46452396#46452396 */ .thaw-tab--selected .thaw-tab__content { - font-weight: var(--fontWeightSemibold); + /* font-weight: var(--fontWeightSemibold); */ + text-shadow: -0.06ex 0 0 currentColor, 0.06ex 0 0 currentColor; +} + +@supports (-webkit-text-stroke-width: 0.04ex) { + .thaw-tab--selected .thaw-tab__content { + text-shadow: -0.03ex 0 0 currentColor, 0.03ex 0 0 currentColor; + -webkit-text-stroke-width: 0.04ex; + } } .thaw-tab--selected::after { From b17f1400a5f7032920f0a25b377db1d2a0c84eb6 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 5 Jun 2024 17:17:17 +0800 Subject: [PATCH 041/143] refactor: badge --- demo/src/pages/components.rs | 8 +- demo_markdown/docs/badge/mod.md | 107 +++++++++++---- thaw/src/badge/badge.css | 234 +++++++++++++++++++++++++++++--- thaw/src/badge/badge.rs | 106 +++++++++++++++ thaw/src/badge/mod.rs | 68 +--------- thaw/src/theme/color.rs | 88 ++++++++++++ 6 files changed, 496 insertions(+), 115 deletions(-) create mode 100644 thaw/src/badge/badge.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 70e5811..491ec12 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -143,6 +143,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/avatar".into(), label: "Avatar".into(), }, + MenuItemOption { + value: "/components/badge".into(), + label: "Badge".into(), + }, MenuItemOption { value: "/components/breadcrumb".into(), label: "Breadcrumb".into(), @@ -259,10 +263,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/alert".into(), label: "Alert".into(), }, - MenuItemOption { - value: "/components/badge".into(), - label: "Badge".into(), - }, MenuItemOption { value: "/components/drawer".into(), label: "Drawer".into(), diff --git a/demo_markdown/docs/badge/mod.md b/demo_markdown/docs/badge/mod.md index 72365a0..a5a8111 100644 --- a/demo_markdown/docs/badge/mod.md +++ b/demo_markdown/docs/badge/mod.md @@ -1,33 +1,92 @@ # Badge ```rust demo -let value = create_rw_signal(0); +view! { + +} +``` +### Appearance + +```rust demo view! { - - - - - - - - - - - - - - - "value:" - {move || value.get()} + "999+" + "999+" + "999+" + "999+" + +} +``` + +### Sizes + +```rust demo +view! { + + + + + + + + +} +``` + +### Color + +```rust demo +view! { + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + + + "999+" + "999+" + "999+" + "999+" + } ``` diff --git a/thaw/src/badge/badge.css b/thaw/src/badge/badge.css index e245bbc..950e519 100644 --- a/thaw/src/badge/badge.css +++ b/thaw/src/badge/badge.css @@ -1,28 +1,220 @@ .thaw-badge { + display: inline-flex; + box-sizing: border-box; + align-items: center; + justify-content: center; position: relative; - display: inline-block; -} -.thaw-badge__sup { - position: absolute; - color: var(--thaw-font-color); - background-color: var(--thaw-background-color); - z-index: 10; -} -.thaw-badge__sup--value { - top: -9px; - right: -9px; - font-size: 12px; - height: 18px; - line-height: 18px; - border-radius: 9px; - padding: 0 6px; - text-align: center; + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase200); + font-weight: var(--fontWeightSemibold); + line-height: var(--lineHeightBase200); + height: 20px; + width: 20px; + min-width: max-content; + padding: 0 calc(var(--spacingHorizontalXS) + var(--spacingHorizontalXXS)); + border-radius: var(--borderRadiusCircular); + border-color: var(--colorTransparentStroke); } -.thaw-badge__sup--dot { - top: -5px; - right: -5px; +.thaw-badge--filled { + color: var(--colorNeutralForegroundOnBrand); + background-color: var(--colorBrandBackground); +} + +.thaw-badge--filled.thaw-badge--danger { + background-color: var(--colorPaletteRedBackground3); +} + +.thaw-badge--filled.thaw-badge--important { + color: var(--colorNeutralBackground1); + background-color: var(--colorNeutralForeground1); +} + +.thaw-badge--filled.thaw-badge--informative { + color: var(--colorNeutralForeground3); + background-color: var(--colorNeutralBackground5); +} + +.thaw-badge--filled.thaw-badge--severe { + background-color: var(--colorPaletteDarkOrangeBackground3); +} + +.thaw-badge--filled.thaw-badge--subtle { + color: var(--colorNeutralForeground1); + background-color: var(--colorNeutralBackground1); +} + +.thaw-badge--filled.thaw-badge--success { + background-color: var(--colorPaletteGreenBackground3); +} + +.thaw-badge--filled.thaw-badge--warning { + color: var(--colorNeutralForeground1Static); + background-color: var(--colorPaletteYellowBackground3); +} + +.thaw-badge--ghost { + color: var(--colorBrandForeground1); +} + +.thaw-badge--ghost.thaw-badge--danger { + color: var(--colorPaletteRedForeground3); +} + +.thaw-badge--ghost.thaw-badge--important { + color: var(--colorNeutralForeground1); +} + +.thaw-badge--ghost.thaw-badge--informative { + color: var(--colorNeutralForeground3); +} + +.thaw-badge--ghost.thaw-badge--severe { + color: var(--colorPaletteDarkOrangeForeground3); +} + +.thaw-badge--ghost.thaw-badge--subtle { + color: var(--colorNeutralForegroundStaticInverted); +} + +.thaw-badge--ghost.thaw-badge--success { + color: var(--colorPaletteGreenForeground3); +} + +.thaw-badge--ghost.thaw-badge--warning { + color: var(--colorPaletteYellowForeground2); +} + +.thaw-badge--outline { + color: var(--colorBrandForeground1); + border-color: currentcolor; +} + +.thaw-badge--outline.thaw-badge--danger { + color: var(--colorPaletteRedForeground3); + border-color: var(--colorPaletteRedBorder2); +} + +.thaw-badge--outline.thaw-badge--important { + color: var(--colorNeutralForeground3); + border-color: var(--colorNeutralStrokeAccessible); +} + +.thaw-badge--outline.thaw-badge--informative { + color: var(--colorNeutralForeground3); + border-color: var(--colorNeutralStroke2); +} + +.thaw-badge--outline.thaw-badge--severe { + color: var(--colorPaletteDarkOrangeForeground3); +} + +.thaw-badge--outline.thaw-badge--subtle { + color: var(--colorNeutralForegroundStaticInverted); +} + +.thaw-badge--outline.thaw-badge--success { + color: var(--colorPaletteGreenForeground3); + border-color: var(--colorPaletteGreenBorder2); +} + +.thaw-badge--outline.thaw-badge--warning { + color: var(--colorPaletteYellowForeground2); +} + +.thaw-badge--tint { + color: var(--colorBrandForeground2); + background-color: var(--colorBrandBackground2); + border-color: var(--colorBrandStroke2); +} + +.thaw-badge--tint.thaw-badge--danger { + background-color: var(--colorPaletteRedBackground1); + color: var(--colorPaletteRedForeground1); + border-color: var(--colorPaletteRedBorder1); +} + +.thaw-badge--tint.thaw-badge--important { + background-color: var(--colorNeutralForeground3); + color: var(--colorNeutralBackground1); + border-color: var(--colorTransparentStroke); +} + +.thaw-badge--tint.thaw-badge--informative { + background-color: var(--colorNeutralBackground4); + color: var(--colorNeutralForeground3); + border-color: var(--colorNeutralStroke2); +} + +.thaw-badge--tint.thaw-badge--severe { + background-color: var(--colorPaletteDarkOrangeBackground1); + color: var(--colorPaletteDarkOrangeForeground1); + border-color: var(--colorPaletteDarkOrangeBorder1); +} + +.thaw-badge--tint.thaw-badge--subtle { + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground3); + border-color: var(--colorNeutralStroke2); +} + +.thaw-badge--tint.thaw-badge--success { + background-color: var(--colorPaletteGreenBackground1); + color: var(--colorPaletteGreenForeground1); + border-color: var(--colorPaletteGreenBorder1); +} + +.thaw-badge--tint.thaw-badge--warning { + background-color: var(--colorPaletteYellowBackground1); + color: var(--colorPaletteYellowForeground1); + border-color: var(--colorPaletteYellowBorder1); +} + +.thaw-badge--tiny { + min-width: unset; + line-height: 4px; + font-size: 4px; + height: 6px; + width: 6px; + padding: unset; +} + +.thaw-badge--extra-small { + min-width: unset; + line-height: 6px; + font-size: 6px; height: 10px; width: 10px; - border-radius: 50%; + padding: unset; +} + +.thaw-badge--small { + line-height: var(--lineHeightBase100); + font-size: var(--fontSizeBase100); + height: 16px; + width: 16px; + padding: 0 calc(var(--spacingHorizontalXXS) + var(--spacingHorizontalXXS)); +} + +.thaw-badge--large { + height: 24px; + width: 24px; + padding: 0 calc(var(--spacingHorizontalXS) + var(--spacingHorizontalXXS)); +} + +.thaw-badge--extra-large { + height: 32px; + width: 32px; + padding: 0 + calc(var(--spacingHorizontalSNudge) + var(--spacingHorizontalXXS)); +} + +.thaw-badge::after { + content: ""; + position: absolute; + inset: 0px; + border-style: solid; + border-color: inherit; + border-width: var(--strokeWidthThin); + border-radius: inherit; } diff --git a/thaw/src/badge/badge.rs b/thaw/src/badge/badge.rs new file mode 100644 index 0000000..9c8b67d --- /dev/null +++ b/thaw/src/badge/badge.rs @@ -0,0 +1,106 @@ +use leptos::*; +use thaw_components::OptionComp; +use thaw_utils::{class_list, mount_style}; + +#[component] +pub fn Badge( + #[prop(optional, into)] class: MaybeProp, + /// A Badge can be filled, outline, ghost, inverted + #[prop(optional, into)] + appearance: MaybeSignal, + /// A Badge can be on of several preset sizes. + #[prop(optional, into)] + size: MaybeSignal, + /// A Badge can be one of preset colors. + #[prop(optional, into)] + color: MaybeSignal, + #[prop(optional)] children: Option, +) -> impl IntoView { + mount_style("badge", include_str!("./badge.css")); + + view! { +
    + + {children()} + +
    + } +} + +#[derive(Default, Clone)] +pub enum BadgeAppearance { + #[default] + Filled, + Ghost, + Outline, + Tint, +} + +impl BadgeAppearance { + pub fn as_str(&self) -> &'static str { + match self { + BadgeAppearance::Filled => "filled", + BadgeAppearance::Ghost => "ghost", + BadgeAppearance::Outline => "outline", + BadgeAppearance::Tint => "tint", + } + } +} + +#[derive(Default, Clone)] +pub enum BadgeSize { + Tiny, + ExtraSmall, + Small, + #[default] + Medium, + Large, + ExtraLarge, +} + +impl BadgeSize { + pub fn as_str(&self) -> &'static str { + match self { + BadgeSize::Tiny => "tiny", + BadgeSize::ExtraSmall => "extra-small", + BadgeSize::Small => "small", + BadgeSize::Medium => "medium", + BadgeSize::Large => "large", + BadgeSize::ExtraLarge => "extra-large", + } + } +} + +#[derive(Default, Clone)] +pub enum BadgeColor { + #[default] + Brand, + Danger, + Important, + Informative, + Severe, + Subtle, + Success, + Warning, +} + +impl BadgeColor { + pub fn as_str(&self) -> &'static str { + match self { + BadgeColor::Brand => "brand", + BadgeColor::Danger => "danger", + BadgeColor::Important => "important", + BadgeColor::Informative => "informative", + BadgeColor::Severe => "severe", + BadgeColor::Subtle => "subtle", + BadgeColor::Success => "success", + BadgeColor::Warning => "warning", + } + } +} diff --git a/thaw/src/badge/mod.rs b/thaw/src/badge/mod.rs index 9af81d6..130902d 100644 --- a/thaw/src/badge/mod.rs +++ b/thaw/src/badge/mod.rs @@ -1,67 +1,3 @@ -use crate::{theme::use_theme, Theme}; -use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +mod badge; -#[derive(Default, Clone)] -pub enum BadgeVariant { - Success, - Warning, - #[default] - Error, -} - -impl BadgeVariant { - fn theme_color(&self, theme: &Theme) -> String { - match self { - BadgeVariant::Success => theme.common.color_success.clone(), - BadgeVariant::Warning => theme.common.color_warning.clone(), - BadgeVariant::Error => theme.common.color_error.clone(), - } - } -} - -#[component] -pub fn Badge( - #[prop(optional, into)] value: MaybeSignal, - #[prop(default = MaybeSignal::Static(u32::MAX), into)] max: MaybeSignal, - #[prop(optional, into)] variant: MaybeSignal, - #[prop(optional, into)] dot: MaybeSignal, - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { - let theme = use_theme(Theme::light); - mount_style("badge", include_str!("./badge.css")); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - css_vars.push_str("--thaw-font-color: #fff;"); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - variant.get().theme_color(theme) - )); - }); - css_vars - }); - let value = create_memo(move |_| { - let value = value.get(); - let max_value = max.get(); - if value == 0 { - String::new() - } else if max_value < value { - format!("{max_value}+") - } else { - value.to_string() - } - }); - - view! { -
    -
    {move || value.get()}
    - {children()} -
    - } -} +pub use badge::*; \ No newline at end of file diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index f5148bf..95ef5bd 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -12,6 +12,7 @@ pub struct ColorTheme { pub color_neutral_background_4: String, pub color_neutral_background_4_hover: String, pub color_neutral_background_4_pressed: String, + pub color_neutral_background_5: String, pub color_neutral_background_6: String, pub color_neutral_foreground_disabled: String, @@ -50,9 +51,37 @@ pub struct ColorTheme { pub color_brand_background: String, pub color_brand_background_hover: String, pub color_brand_background_pressed: String, + pub color_brand_background_2: String, + pub color_brand_foreground_1: String, + pub color_brand_foreground_2: String, pub color_brand_stroke_1: String, + pub color_brand_stroke_2: String, pub color_brand_stroke_2_contrast: String, + pub color_palette_red_background_1: String, + pub color_palette_red_background_3: String, + pub color_palette_red_foreground_1: String, + pub color_palette_red_foreground_3: String, + pub color_palette_red_border_1: String, + pub color_palette_red_border_2: String, + pub color_palette_green_background_1: String, + pub color_palette_green_background_3: String, + pub color_palette_green_foreground_1: String, + pub color_palette_green_foreground_3: String, + pub color_palette_green_border_1: String, + pub color_palette_green_border_2: String, + pub color_palette_yellow_background_1: String, + pub color_palette_yellow_background_3: String, + pub color_palette_yellow_foreground_1: String, + pub color_palette_yellow_foreground_2: String, + pub color_palette_yellow_border_1: String, + + pub color_palette_dark_orange_background_1: String, + pub color_palette_dark_orange_background_3: String, + pub color_palette_dark_orange_foreground_1: String, + pub color_palette_dark_orange_foreground_3: String, + pub color_palette_dark_orange_border_1: String, + pub color_subtle_background: String, pub color_subtle_background_hover: String, pub color_subtle_background_pressed: String, @@ -77,6 +106,7 @@ impl ColorTheme { color_neutral_background_4: "#f0f0f0".into(), color_neutral_background_4_hover: "#fafafa".into(), color_neutral_background_4_pressed: "#f5f5f5".into(), + color_neutral_background_5: "#ebebeb".into(), color_neutral_background_6: "#e6e6e6".into(), color_neutral_foreground_disabled: "#bdbdbd".into(), @@ -116,8 +146,37 @@ impl ColorTheme { color_brand_background: "#0f6cbd".into(), color_brand_background_hover: "#115ea3".into(), color_brand_background_pressed: "#0c3b5e".into(), + color_brand_background_2: "#ebf3fc".into(), + color_brand_foreground_1: "#0f6cbd".into(), + color_brand_foreground_2: "#115ea3".into(), color_brand_stroke_1: "#0f6cbd".into(), + color_brand_stroke_2: "#b4d6fa".into(), color_brand_stroke_2_contrast: "#b4d6fa".into(), + + color_palette_red_background_1: "#fdf6f6".into(), + color_palette_red_background_3: "#d13438".into(), + color_palette_red_foreground_1: "#bc2f32".into(), + color_palette_red_foreground_3: "#d13438".into(), + color_palette_red_border_1: "#f1bbbc".into(), + color_palette_red_border_2: "#d13438".into(), + color_palette_green_background_1: "#f1faf1".into(), + color_palette_green_background_3: "#107c10".into(), + color_palette_green_foreground_1: "#0e700e".into(), + color_palette_green_foreground_3: "#107c10".into(), + color_palette_green_border_1: "#9fd89f".into(), + color_palette_green_border_2: "#107c10".into(), + color_palette_yellow_background_1: "#fffef5".into(), + color_palette_yellow_background_3: "#fde300".into(), + color_palette_yellow_foreground_1: "#817400".into(), + color_palette_yellow_foreground_2: "#817400".into(), + color_palette_yellow_border_1: "#fef7b2".into(), + + color_palette_dark_orange_background_1: "#fdf6f3".into(), + color_palette_dark_orange_background_3: "#da3b01".into(), + color_palette_dark_orange_foreground_1: "#c43501".into(), + color_palette_dark_orange_foreground_3: "#da3b01".into(), + color_palette_dark_orange_border_1: "#f4bfab".into(), + color_subtle_background: "transparent".into(), color_subtle_background_hover: "#f5f5f5".into(), color_subtle_background_pressed: "#e0e0e0".into(), @@ -142,6 +201,7 @@ impl ColorTheme { color_neutral_background_4: "#0a0a0a".into(), color_neutral_background_4_hover: "#1f1f1f".into(), color_neutral_background_4_pressed: "#000000".into(), + color_neutral_background_5: "#000000".into(), color_neutral_background_6: "#333333".into(), color_neutral_foreground_disabled: "#5c5c5c".into(), @@ -181,9 +241,37 @@ impl ColorTheme { color_brand_background: "#115ea3".into(), color_brand_background_hover: "#0f6cbd".into(), color_brand_background_pressed: "#0c3b5e".into(), + color_brand_background_2: "#082338".into(), + color_brand_foreground_1: "#479ef5".into(), + color_brand_foreground_2: "#62abf5".into(), color_brand_stroke_1: "#479ef5".into(), + color_brand_stroke_2: "#0e4775".into(), color_brand_stroke_2_contrast: "#0e4775".into(), + color_palette_red_background_1: "#3f1011".into(), + color_palette_red_background_3: "#d13438".into(), + color_palette_red_foreground_1: "#e37d80".into(), + color_palette_red_foreground_3: "#e37d80".into(), + color_palette_red_border_1: "#d13438".into(), + color_palette_red_border_2: "#e37d80".into(), + color_palette_green_background_1: "#052505".into(), + color_palette_green_background_3: "#107c10".into(), + color_palette_green_foreground_1: "#54b054".into(), + color_palette_green_foreground_3: "#9fd89f".into(), + color_palette_green_border_1: "#107c10".into(), + color_palette_green_border_2: "#9fd89f".into(), + color_palette_yellow_background_1: "#4c4400".into(), + color_palette_yellow_background_3: "#fde300".into(), + color_palette_yellow_foreground_1: "#feee66".into(), + color_palette_yellow_foreground_2: "#fef7b2".into(), + color_palette_yellow_border_1: "#fde300".into(), + + color_palette_dark_orange_background_1: "#411200".into(), + color_palette_dark_orange_background_3: "#da3b01".into(), + color_palette_dark_orange_foreground_1: "#e9835e".into(), + color_palette_dark_orange_foreground_3: "#e9835e".into(), + color_palette_dark_orange_border_1: "#da3b01".into(), + color_subtle_background: "transparent".into(), color_subtle_background_hover: "#383838".into(), color_subtle_background_pressed: "#2e2e2e".into(), From 3a097b166b152e8bf6fd373702a587afa185830c Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 5 Jun 2024 22:56:55 +0800 Subject: [PATCH 042/143] refactor: skeleton --- demo/src/pages/components.rs | 8 ++--- demo_markdown/docs/skeleton/mod.md | 5 +-- thaw/src/skeleton/mod.rs | 52 +++-------------------------- thaw/src/skeleton/skeleton-item.css | 31 +++++++++++++++++ thaw/src/skeleton/skeleton.css | 24 ------------- thaw/src/skeleton/skeleton.rs | 14 ++++++++ thaw/src/skeleton/skeleton_item.rs | 12 +++++++ thaw/src/skeleton/theme.rs | 23 ------------- thaw/src/theme/color.rs | 9 +++++ thaw/src/theme/mod.rs | 5 +-- 10 files changed, 78 insertions(+), 105 deletions(-) create mode 100644 thaw/src/skeleton/skeleton-item.css delete mode 100644 thaw/src/skeleton/skeleton.css create mode 100644 thaw/src/skeleton/skeleton.rs create mode 100644 thaw/src/skeleton/skeleton_item.rs delete mode 100644 thaw/src/skeleton/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 491ec12..6c19b1c 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -171,6 +171,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/icon".into(), label: "Icon".into(), }, + MenuItemOption { + value: "/components/skeleton".into(), + label: "Skeleton".into(), + }, MenuItemOption { value: "/components/spin-button".into(), label: "Spin Button".into(), @@ -283,10 +287,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/progress".into(), label: "Progress".into(), }, - MenuItemOption { - value: "/components/skeleton".into(), - label: "Skeleton".into(), - }, MenuItemOption { value: "/components/layout".into(), label: "Layout".into(), diff --git a/demo_markdown/docs/skeleton/mod.md b/demo_markdown/docs/skeleton/mod.md index 8b10ecd..0330918 100644 --- a/demo_markdown/docs/skeleton/mod.md +++ b/demo_markdown/docs/skeleton/mod.md @@ -2,8 +2,9 @@ ```rust demo view! { - - + + + } ``` diff --git a/thaw/src/skeleton/mod.rs b/thaw/src/skeleton/mod.rs index 8e5daf5..eaddb95 100644 --- a/thaw/src/skeleton/mod.rs +++ b/thaw/src/skeleton/mod.rs @@ -1,49 +1,5 @@ -mod theme; +mod skeleton; +mod skeleton_item; -pub use theme::SkeletionTheme; - -use crate::{theme::use_theme, Theme}; -use leptos::*; -use thaw_utils::mount_style; - -#[component] -pub fn Skeleton( - #[prop(default = MaybeSignal::Static(1), into)] repeat: MaybeSignal, - #[prop(optional, into)] text: MaybeSignal, - #[prop(optional, into)] width: Option>, - #[prop(optional, into)] height: Option>, -) -> impl IntoView { - mount_style("skeleton", include_str!("./skeleton.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - if text.get() { - css_vars.push_str("display: inline-block;"); - } - - if let Some(width) = width.as_ref() { - css_vars.push_str(&format!("width: {};", width.get())); - } - if let Some(height) = height.as_ref() { - css_vars.push_str(&format!("height: {};", height.get())); - } - - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color-start: {};", - theme.skeletion.background_color_start - )); - css_vars.push_str(&format!( - "--thaw-background-color-end: {};", - theme.skeletion.background_color_end - )); - }); - - css_vars - }); - (0..repeat.get()) - .map(|_| { - view! {
    } - }) - .collect_view() -} +pub use skeleton::*; +pub use skeleton_item::*; diff --git a/thaw/src/skeleton/skeleton-item.css b/thaw/src/skeleton/skeleton-item.css new file mode 100644 index 0000000..89bb0d0 --- /dev/null +++ b/thaw/src/skeleton/skeleton-item.css @@ -0,0 +1,31 @@ +.thaw-skeleton-item { + background-image: linear-gradient( + to right, + var(--colorNeutralStencil1) 0%, + var(--colorNeutralStencil2) 50%, + var(--colorNeutralStencil1) 100% + ); + animation-name: thaw-skeleton-item; + animation-timing-function: linear; + animation-duration: 3s; + animation-iteration-count: infinite; + background-attachment: fixed; + background-position-y: 50%; + background-position-x: 50%; + background-size: 300% 100%; + position: relative; + width: 100%; + height: 16px; + border-radius: 4px; + overflow: hidden; +} + +@keyframes thaw-skeleton-item { + 0% { + background-position-x: 300%; + } + + 100% { + background-position-x: 0%; + } +} diff --git a/thaw/src/skeleton/skeleton.css b/thaw/src/skeleton/skeleton.css deleted file mode 100644 index 243b3ef..0000000 --- a/thaw/src/skeleton/skeleton.css +++ /dev/null @@ -1,24 +0,0 @@ -.thaw-skeleton { - width: 100%; - height: 1em; - background-color: var(--thaw-background-color-start); - - background: linear-gradient( - 90deg, - var(--thaw-background-color-start) 25%, - var(--thaw-background-color-end) 37%, - var(--thaw-background-color-start) 63% - ); - animation: thawSkeletonLoading 1.4s ease infinite; - background-size: 400% 100%; -} - -@keyframes thawSkeletonLoading { - from { - background-position: 100% 50%; - } - - to { - background-position: 0 50%; - } -} diff --git a/thaw/src/skeleton/skeleton.rs b/thaw/src/skeleton/skeleton.rs new file mode 100644 index 0000000..4bdec06 --- /dev/null +++ b/thaw/src/skeleton/skeleton.rs @@ -0,0 +1,14 @@ +use leptos::*; + +#[component] +pub fn Skeleton(children: Children) -> impl IntoView { + view! { +
    + {children()} +
    + } +} diff --git a/thaw/src/skeleton/skeleton_item.rs b/thaw/src/skeleton/skeleton_item.rs new file mode 100644 index 0000000..720fa79 --- /dev/null +++ b/thaw/src/skeleton/skeleton_item.rs @@ -0,0 +1,12 @@ +use leptos::*; +use thaw_utils::mount_style; + +#[component] +pub fn SkeletonItem() -> impl IntoView { + mount_style("skeleton-item", include_str!("./skeleton-item.css")); + + view! { +
    +
    + } +} diff --git a/thaw/src/skeleton/theme.rs b/thaw/src/skeleton/theme.rs deleted file mode 100644 index 6b9f337..0000000 --- a/thaw/src/skeleton/theme.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SkeletionTheme { - pub background_color_start: String, - pub background_color_end: String, -} - -impl ThemeMethod for SkeletionTheme { - fn light() -> Self { - Self { - background_color_start: "#f2f2f2".into(), - background_color_end: "#e6e6e6".into(), - } - } - - fn dark() -> Self { - Self { - background_color_start: "rgba(255, 255, 255, 0.12)".into(), - background_color_end: "rgba(255, 255, 255, 0.18)".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 95ef5bd..bfd86b3 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -39,6 +39,9 @@ pub struct ColorTheme { pub color_neutral_stroke_accessible_hover: String, pub color_neutral_stroke_accessible_pressed: String, + pub color_neutral_stencil_1: String, + pub color_neutral_stencil_2: String, + pub color_compound_brand_foreground_1: String, pub color_compound_brand_foreground_1_hover: String, pub color_compound_brand_foreground_1_pressed: String, @@ -133,6 +136,9 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#575757".into(), color_neutral_stroke_accessible_pressed: "#4d4d4d".into(), + color_neutral_stencil_1: "#e6e6e6".into(), + color_neutral_stencil_2: "#fafafa".into(), + color_compound_brand_foreground_1: "#0f6cbd".into(), color_compound_brand_foreground_1_hover: "#115ea3".into(), color_compound_brand_foreground_1_pressed: "#0f548c".into(), @@ -228,6 +234,9 @@ impl ColorTheme { color_neutral_stroke_accessible_hover: "#bdbdbd".into(), color_neutral_stroke_accessible_pressed: "#b3b3b3".into(), + color_neutral_stencil_1: "#575757".into(), + color_neutral_stencil_2: "#333333".into(), + color_compound_brand_foreground_1: "#479ef5".into(), color_compound_brand_foreground_1_hover: "#62abf5".into(), color_compound_brand_foreground_1_pressed: "#2886de".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index e053a62..986a5ee 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -6,7 +6,7 @@ use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, - SelectTheme, SkeletionTheme, TableTheme, TimePickerTheme, UploadTheme, + SelectTheme, TableTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -24,7 +24,6 @@ pub struct Theme { pub input: InputTheme, pub table: TableTheme, pub alert: AlertTheme, - pub skeletion: SkeletionTheme, pub message: MessageTheme, pub select: SelectTheme, pub upload: UploadTheme, @@ -51,7 +50,6 @@ impl Theme { input: InputTheme::light(), table: TableTheme::light(), alert: AlertTheme::light(), - skeletion: SkeletionTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), upload: UploadTheme::light(), @@ -77,7 +75,6 @@ impl Theme { input: InputTheme::dark(), table: TableTheme::dark(), alert: AlertTheme::dark(), - skeletion: SkeletionTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), upload: UploadTheme::dark(), From 902da02e30a03d2570921465697bad228f61ff32 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 6 Jun 2024 10:53:04 +0800 Subject: [PATCH 043/143] refactor: table --- demo/src/pages/components.rs | 8 +-- demo_markdown/docs/table/mod.md | 50 ++++++++------ demo_markdown/src/markdown/mod.rs | 22 +++--- thaw/src/table/mod.rs | 107 ++++++++++++++++++------------ thaw/src/table/table.css | 94 ++++++++++++++++++-------- thaw/src/table/theme.rs | 26 -------- thaw/src/theme/mod.rs | 5 +- 7 files changed, 180 insertions(+), 132 deletions(-) delete mode 100644 thaw/src/table/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 6c19b1c..d5fb3a3 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -187,6 +187,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/tab-list".into(), label: "Tab List".into(), }, + MenuItemOption { + value: "/components/table".into(), + label: "Table".into(), + }, MenuItemOption { value: "/components/tag".into(), label: "Tag".into(), @@ -247,10 +251,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/image".into(), label: "Image".into(), }, - MenuItemOption { - value: "/components/table".into(), - label: "Table".into(), - }, MenuItemOption { value: "/components/anchor".into(), label: "Anchor".into(), diff --git a/demo_markdown/docs/table/mod.md b/demo_markdown/docs/table/mod.md index d658fe5..5112844 100644 --- a/demo_markdown/docs/table/mod.md +++ b/demo_markdown/docs/table/mod.md @@ -3,25 +3,37 @@ ```rust demo view! { - - - - - - - - - - - - - - - - - - - + + + "Tag" + "Count" + "Date" + + + + + + + "div" + + + + + "2" + + + + + "2023-10-08" + + + + + "span" + "2" + "2023-10-08" + +
    "tag""count""date"
    "div""2""2023-10-08"
    "span""2""2023-10-08"
    } ``` diff --git a/demo_markdown/src/markdown/mod.rs b/demo_markdown/src/markdown/mod.rs index 95f8d0d..f443044 100644 --- a/demo_markdown/src/markdown/mod.rs +++ b/demo_markdown/src/markdown/mod.rs @@ -96,22 +96,22 @@ fn iter_nodes<'a>( quote!(
    - - +
    + #(#header_children)* - - + + #(#children)* - +
    ) } NodeValue::TableRow(_) => { quote!( - + #(#children)* - + ) } NodeValue::TableCell => { @@ -122,15 +122,15 @@ fn iter_nodes<'a>( }; if is_header { quote!( - + #(#children)* - + ) } else { quote!( - + #(#children)* - + ) } } diff --git a/thaw/src/table/mod.rs b/thaw/src/table/mod.rs index 7b10127..37efef5 100644 --- a/thaw/src/table/mod.rs +++ b/thaw/src/table/mod.rs @@ -1,56 +1,81 @@ -mod theme; - -pub use theme::TableTheme; - -use crate::{theme::use_theme, Theme}; use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_components::OptionComp; +use thaw_utils::{class_list, mount_style}; #[component] pub fn Table( - #[prop(optional, into)] style: MaybeSignal, - #[prop(default=true.into(), into)] single_row: MaybeSignal, - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] single_column: MaybeSignal, + #[prop(optional, into)] style: MaybeProp, + #[prop(optional, into)] class: MaybeProp, children: Children, ) -> impl IntoView { mount_style("table", include_str!("./table.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.table.background_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-striped: {};", - theme.table.background_color_striped - )); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.table.border_color - )); - css_vars.push_str(&format!( - "--thaw-border-radius: {};", - theme.common.border_radius - )); - }); - - css_vars - }); view! { {children()}
    } } + +#[component] +pub fn TableHeader(children: Children) -> impl IntoView { + view! { + + {children()} + + } +} + +#[component] +pub fn TableHeaderCell(#[prop(optional)] children: Option) -> impl IntoView { + view! { + + + + } +} + +#[component] +pub fn TableBody(children: Children) -> impl IntoView { + view! { + + {children()} + + } +} + +#[component] +pub fn TableRow(children: Children) -> impl IntoView { + view! { + + {children()} + + } +} + +#[component] +pub fn TableCell(#[prop(optional)] children: Option) -> impl IntoView { + view! { + + + {children()} + + + } +} + +#[component] +pub fn TableCellLayout(children: Children) -> impl IntoView { + view! { +
    + {children()} +
    + } +} diff --git a/thaw/src/table/table.css b/thaw/src/table/table.css index 5aa6a87..47cbcd1 100644 --- a/thaw/src/table/table.css +++ b/thaw/src/table/table.css @@ -1,39 +1,79 @@ .thaw-table { + display: table; + table-layout: fixed; + vertical-align: middle; + border-collapse: collapse; width: 100%; - border-collapse: separate; - border-spacing: 0; - background-color: var(--thaw-background-color); - border: 1px solid var(--thaw-border-color); - border-radius: var(--thaw-border-radius); + background-color: var(--colorSubtleBackground); } -.thaw-table th { - text-align: inherit; - background-color: var(--thaw-background-color-striped); +.thaw-table-header { + display: table-row-group; } -.thaw-table td, -.thaw-table th { - padding: 12px; - border-right: 1px solid var(--thaw-border-color); - border-bottom: 1px solid var(--thaw-border-color); +.thaw-table-header-cell { + position: relative; + display: table-cell; + vertical-align: middle; + font-weight: var(--fontWeightRegular); + padding: 0px var(--spacingHorizontalS); } -.thaw-table.thaw-table--single-row td, -.thaw-table.thaw-table--single-row th { - border-right: none; -} -.thaw-table.thaw-table--single-column td { - border-bottom: none; -} -.thaw-table td:last-child, -.thaw-table th:last-child { - border-right: none; +.thaw-table-header-cell__button { + position: relative; + display: flex; + flex: 1 1 0px; + align-items: center; + gap: var(--spacingHorizontalXS); + padding: 0px; + width: 100%; + height: 100%; + min-height: 32px; + text-align: unset; + font-family: inherit; + font-size: inherit; + line-height: normal; + color: inherit; + background-color: inherit; + box-sizing: content-box; + resize: horizontal; + overflow: visible; + outline-style: none; + border: none; } -.thaw-table tbody tr:last-child td { - border-bottom: none; +.thaw-table-body { + display: table-row-group; } -.thaw-table tr { - border-bottom: 1px solid var(--thaw-border-color); + +.thaw-table-row { + display: table-row; + box-sizing: border-box; + color: var(--colorNeutralForeground1); + border-bottom: var(--strokeWidthThin) solid var(--colorNeutralStroke2); +} + +.thaw-table-body > .thaw-table-row:hover { + color: var(--colorNeutralForeground1Hover); + background-color: var(--colorSubtleBackgroundHover); +} + +.thaw-table-body > .thaw-table-row:active { + color: var(--colorNeutralForeground1Pressed); + background-color: var(--colorSubtleBackgroundPressed); +} + +.thaw-table-cell { + position: relative; + height: 44px; + display: table-cell; + vertical-align: middle; + padding: 0px var(--spacingHorizontalS); +} + +.thaw-table-cell-layout { + display: flex; + flex: 1 1 0px; + align-items: center; + gap: var(--spacingHorizontalS); } diff --git a/thaw/src/table/theme.rs b/thaw/src/table/theme.rs deleted file mode 100644 index c1f46c6..0000000 --- a/thaw/src/table/theme.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct TableTheme { - pub background_color: String, - pub background_color_striped: String, - pub border_color: String, -} - -impl ThemeMethod for TableTheme { - fn light() -> Self { - Self { - background_color: "#fff".into(), - background_color_striped: "#fafafc".into(), - border_color: "#efeff5".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#18181c".into(), - background_color_striped: "#26262a".into(), - border_color: "#2d2d30".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 986a5ee..aee64de 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -6,7 +6,7 @@ use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, - SelectTheme, TableTheme, TimePickerTheme, UploadTheme, + SelectTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -22,7 +22,6 @@ pub struct Theme { pub common: CommonTheme, pub color: ColorTheme, pub input: InputTheme, - pub table: TableTheme, pub alert: AlertTheme, pub message: MessageTheme, pub select: SelectTheme, @@ -48,7 +47,6 @@ impl Theme { common: CommonTheme::light(), color: ColorTheme::light(), input: InputTheme::light(), - table: TableTheme::light(), alert: AlertTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), @@ -73,7 +71,6 @@ impl Theme { common: CommonTheme::dark(), color: ColorTheme::dark(), input: InputTheme::dark(), - table: TableTheme::dark(), alert: AlertTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), From c41d1777829a80ef449efd0ad71efea8417ecbaa Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 10 Jun 2024 22:35:49 +0800 Subject: [PATCH 044/143] refactor: save popover --- thaw/src/config_provider/mod.rs | 4 + thaw/src/popover/mod.rs | 41 +++------- thaw/src/popover/popover.css | 137 ++++++++++++++------------------ thaw/src/popover/theme.rs | 23 ------ thaw/src/theme/color.rs | 3 + thaw/src/theme/mod.rs | 5 +- 6 files changed, 77 insertions(+), 136 deletions(-) delete mode 100644 thaw/src/popover/theme.rs diff --git a/thaw/src/config_provider/mod.rs b/thaw/src/config_provider/mod.rs index c6ffa8b..cf1498c 100644 --- a/thaw/src/config_provider/mod.rs +++ b/thaw/src/config_provider/mod.rs @@ -67,6 +67,10 @@ impl ConfigInjection { pub fn id(&self) -> &String { &self.id } + + pub fn use_() -> ConfigInjection { + expect_context() + } } #[derive(Clone)] diff --git a/thaw/src/popover/mod.rs b/thaw/src/popover/mod.rs index 93614ff..56a7d88 100644 --- a/thaw/src/popover/mod.rs +++ b/thaw/src/popover/mod.rs @@ -1,8 +1,4 @@ -mod theme; - -pub use theme::PopoverTheme; - -use crate::{use_theme, Theme}; +use crate::ConfigInjection; use leptos::{leptos_dom::helpers::TimeoutHandle, *}; use std::time::Duration; use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement}; @@ -25,27 +21,8 @@ pub fn Popover( children: Children, ) -> impl IntoView { mount_style("popover", include_str!("./popover.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let background_color = if tooltip { - &theme.popover.tooltip_background_color - } else { - &theme.popover.background_color - }; - css_vars.push_str(&format!("--thaw-background-color: {};", background_color)); - let font_color = if tooltip { - "#fff" - } else { - // TODO - // &theme.common.font_color - "" - }; - css_vars.push_str(&format!("--thaw-font-color: {};", font_color)); - }); - css_vars - }); + let config_provider = ConfigInjection::use_(); + let popover_ref = create_node_ref::(); let target_ref = create_node_ref::(); let is_show_popover = create_rw_signal(false); @@ -140,18 +117,20 @@ pub fn Popover( let:display >
    {children()}
    -
    -
    +
    diff --git a/thaw/src/popover/popover.css b/thaw/src/popover/popover.css index a96e1b3..71daa91 100644 --- a/thaw/src/popover/popover.css +++ b/thaw/src/popover/popover.css @@ -1,75 +1,56 @@ -.thaw-popover { +div.thaw-popover-surface { position: relative; - padding: 8px 14px; - background-color: var(--thaw-background-color); - color: var(--thaw-font-color); - border-radius: 3px; transform-origin: inherit; + + padding: 16px; + border-radius: var(--borderRadiusMedium); + border: 1px solid var(--colorTransparentStroke); + box-shadow: var(--shadow16); + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); +} + +.thaw-popover-surface__angle { + position: absolute; + background-color: inherit; + width: 10px; + height: 10px; } .thaw-popover-trigger { display: inline-block; } -.thaw-popover__angle-container { - position: absolute; -} - -.thaw-popover__angle { - position: absolute; - background: var(--thaw-background-color); - width: 10px; - height: 10px; -} - -[data-thaw-placement="top-start"] > .thaw-popover, -[data-thaw-placement="top-end"] > .thaw-popover, -[data-thaw-placement="top"] > .thaw-popover { +[data-thaw-placement="top-start"] > .thaw-popover-surface, +[data-thaw-placement="top-end"] > .thaw-popover-surface, +[data-thaw-placement="top"] > .thaw-popover-surface { margin-bottom: 10px; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); } -[data-thaw-placement="top-start"] .thaw-popover__angle-container, -[data-thaw-placement="top-end"] .thaw-popover__angle-container, -[data-thaw-placement="top"] .thaw-popover__angle-container { - width: 100%; - height: 10px; - bottom: -10px; - left: 0; - right: 0; -} - -[data-thaw-placement="top-start"] .thaw-popover__angle, -[data-thaw-placement="top-end"] .thaw-popover__angle, -[data-thaw-placement="top"] .thaw-popover__angle { - left: 50%; +[data-thaw-placement="top-start"] .thaw-popover-surface__angle, +[data-thaw-placement="top-end"] .thaw-popover-surface__angle, +[data-thaw-placement="top"] .thaw-popover-surface__angle { transform: rotate(45deg) translateX(-7px); -} - -[data-thaw-placement="bottom-start"] > .thaw-popover, -[data-thaw-placement="bottom-end"] > .thaw-popover, -[data-thaw-placement="bottom"] > .thaw-popover { - margin-top: 10px; - box-shadow: 0 -3px 6px -4px rgba(0, 0, 0, 0.12), - 0 -6px 16px 0 rgba(0, 0, 0, 0.08), 0 -9px 28px 8px rgba(0, 0, 0, 0.05); -} - -[data-thaw-placement="bottom-start"] .thaw-popover__angle-container, -[data-thaw-placement="bottom-end"] .thaw-popover__angle-container, -[data-thaw-placement="bottom"] .thaw-popover__angle-container { - width: 100%; - height: 10px; - top: -10px; - left: 0; - right: 0; -} - -[data-thaw-placement="bottom-start"] .thaw-popover__angle, -[data-thaw-placement="bottom-end"] .thaw-popover__angle, -[data-thaw-placement="bottom"] .thaw-popover__angle { + bottom: -10px; left: 50%; +} + +[data-thaw-placement="bottom-start"] > .thaw-popover-surface, +[data-thaw-placement="bottom-end"] > .thaw-popover-surface, +[data-thaw-placement="bottom"] > .thaw-popover-surface { + margin-top: 10px; +} + +[data-thaw-placement="bottom-start"] .thaw-popover-surface__angle, +[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle, +[data-thaw-placement="bottom"] .thaw-popover-surface__angle { transform: rotate(45deg) translateY(7px); + top: -10px; + left: 50%; } [data-thaw-placement="left-start"] > .thaw-popover, @@ -80,9 +61,9 @@ 6px 0 16px 0 rgba(0, 0, 0, 0.08), 9px 0 28px 8px rgba(0, 0, 0, 0.05); } -[data-thaw-placement="left-start"] .thaw-popover__angle-container, -[data-thaw-placement="left-end"] .thaw-popover__angle-container, -[data-thaw-placement="left"] .thaw-popover__angle-container { +[data-thaw-placement="left-start"] .thaw-popover-surface__angle, +[data-thaw-placement="left-end"] .thaw-popover-surface__angle, +[data-thaw-placement="left"] .thaw-popover-surface__angle { width: 10px; height: 100%; right: -10px; @@ -90,9 +71,9 @@ bottom: 0; } -[data-thaw-placement="left-start"] .thaw-popover__angle, -[data-thaw-placement="left-end"] .thaw-popover__angle, -[data-thaw-placement="left"] .thaw-popover__angle { +[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before, +[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before, +[data-thaw-placement="left"] .thaw-popover-surface__angle::before { top: 50%; transform: rotate(45deg) translateX(-7px); } @@ -105,9 +86,9 @@ -6px 0 16px 0 rgba(0, 0, 0, 0.08), -9px 0 28px 8px rgba(0, 0, 0, 0.05); } -[data-thaw-placement="right-start"] .thaw-popover__angle-container, -[data-thaw-placement="right-end"] .thaw-popover__angle-container, -[data-thaw-placement="right"] .thaw-popover__angle-container { +[data-thaw-placement="right-start"] .thaw-popover-surface__angle, +[data-thaw-placement="right-end"] .thaw-popover-surface__angle, +[data-thaw-placement="right"] .thaw-popover-surface__angle { width: 10px; height: 100%; left: -10px; @@ -115,28 +96,28 @@ bottom: 0; } -[data-thaw-placement="right-start"] .thaw-popover__angle, -[data-thaw-placement="right-end"] .thaw-popover__angle, -[data-thaw-placement="right"] .thaw-popover__angle { +[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before, +[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before, +[data-thaw-placement="right"] .thaw-popover-surface__angle::before { top: 50%; transform: rotate(45deg) translateY(-7px); } -[data-thaw-placement="bottom-start"] .thaw-popover__angle, -[data-thaw-placement="top-start"] .thaw-popover__angle { +[data-thaw-placement="bottom-start"] .thaw-popover-surface__angle, +[data-thaw-placement="top-start"] .thaw-popover-surface__angle { left: 16px; } -[data-thaw-placement="bottom-end"] .thaw-popover__angle, -[data-thaw-placement="top-end"] .thaw-popover__angle { +[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle::before, +[data-thaw-placement="top-end"] .thaw-popover-surface__angle::before { left: initial; right: 7px; } -[data-thaw-placement="right-start"] .thaw-popover__angle, -[data-thaw-placement="left-start"] .thaw-popover__angle { +[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before, +[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before { top: 16px; } -[data-thaw-placement="right-end"] .thaw-popover__angle, -[data-thaw-placement="left-end"] .thaw-popover__angle { +[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before, +[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before { top: initial; bottom: 7px; } diff --git a/thaw/src/popover/theme.rs b/thaw/src/popover/theme.rs deleted file mode 100644 index 21f1a4f..0000000 --- a/thaw/src/popover/theme.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct PopoverTheme { - pub background_color: String, - pub tooltip_background_color: String, -} - -impl ThemeMethod for PopoverTheme { - fn light() -> Self { - Self { - background_color: "#fff".into(), - tooltip_background_color: "#262626".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#48484e".into(), - tooltip_background_color: "#48484e".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index bfd86b3..5340105 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -94,6 +94,7 @@ pub struct ColorTheme { pub color_transparent_stroke: String, pub shadow4: String, + pub shadow16: String, } impl ColorTheme { @@ -192,6 +193,7 @@ impl ColorTheme { color_transparent_stroke: "transparent".into(), shadow4: "0 0 2px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.14)".into(), + shadow16: "0 0 2px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.14)".into(), } } @@ -290,6 +292,7 @@ impl ColorTheme { color_transparent_stroke: "transparent".into(), shadow4: "0 0 2px rgba(0,0,0,0.24), 0 2px 4px rgba(0,0,0,0.28)".into(), + shadow16: "0 0 2px rgba(0,0,0,0.24), 0 8px 16px rgba(0,0,0,0.28)".into(), } } } diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index aee64de..dce520d 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -5,7 +5,7 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, - DatePickerTheme, InputTheme, MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, + DatePickerTheme, InputTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; @@ -34,7 +34,6 @@ pub struct Theme { pub calendar: CalendarTheme, pub time_picker: TimePickerTheme, pub date_picker: DatePickerTheme, - pub popover: PopoverTheme, pub scrollbar: ScrollbarTheme, pub back_top: BackTopTheme, pub anchor: AnchorTheme, @@ -59,7 +58,6 @@ impl Theme { calendar: CalendarTheme::light(), time_picker: TimePickerTheme::light(), date_picker: DatePickerTheme::light(), - popover: PopoverTheme::light(), scrollbar: ScrollbarTheme::light(), back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), @@ -83,7 +81,6 @@ impl Theme { calendar: CalendarTheme::dark(), time_picker: TimePickerTheme::dark(), date_picker: DatePickerTheme::dark(), - popover: PopoverTheme::dark(), scrollbar: ScrollbarTheme::dark(), back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(), From f999e252e497f30612111857364e7256e269c923 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 11 Jun 2024 16:48:41 +0800 Subject: [PATCH 045/143] feat: popover appearance --- demo/src/components/demo.rs | 2 +- demo_markdown/docs/popover/mod.md | 14 +++- thaw/src/popover/mod.rs | 49 ++++++++---- thaw/src/popover/popover.css | 93 +++++++++-------------- thaw/src/theme/color.rs | 6 ++ thaw_components/src/css_transition/mod.rs | 6 +- 6 files changed, 93 insertions(+), 77 deletions(-) diff --git a/demo/src/components/demo.rs b/demo/src/components/demo.rs index 0f6f662..a962380 100644 --- a/demo/src/components/demo.rs +++ b/demo/src/components/demo.rs @@ -68,7 +68,7 @@ pub fn Demo(demo_code: DemoCode, #[prop(optional)] children: Option) - view! {
    {children()}
    - + { diff --git a/demo_markdown/docs/popover/mod.md b/demo_markdown/docs/popover/mod.md index 28b2be5..f3201c1 100644 --- a/demo_markdown/docs/popover/mod.md +++ b/demo_markdown/docs/popover/mod.md @@ -54,7 +54,7 @@ view! { - + @@ -70,7 +70,7 @@ view! { - + @@ -129,12 +129,18 @@ view! { } ``` -### Tooltip +### Appearance ```rust demo view! { - + + + + + "Content" + + diff --git a/thaw/src/popover/mod.rs b/thaw/src/popover/mod.rs index 56a7d88..bf96551 100644 --- a/thaw/src/popover/mod.rs +++ b/thaw/src/popover/mod.rs @@ -1,32 +1,33 @@ use crate::ConfigInjection; use leptos::{leptos_dom::helpers::TimeoutHandle, *}; +use palette::bool_mask::BoolMask; use std::time::Duration; use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement}; -use thaw_utils::{add_event_listener, class_list, mount_style, OptionalProp}; +use thaw_utils::{add_event_listener, class_list, mount_style}; #[slot] pub struct PopoverTrigger { #[prop(optional, into)] - class: OptionalProp>, + class: MaybeProp, children: Children, } #[component] pub fn Popover( - #[prop(optional, into)] class: OptionalProp>, + #[prop(optional, into)] class: MaybeProp, #[prop(optional)] trigger_type: PopoverTriggerType, popover_trigger: PopoverTrigger, #[prop(optional)] placement: PopoverPlacement, - #[prop(optional)] tooltip: bool, + #[prop(optional, into)] appearance: Option>, children: Children, ) -> impl IntoView { mount_style("popover", include_str!("./popover.css")); let config_provider = ConfigInjection::use_(); - let popover_ref = create_node_ref::(); - let target_ref = create_node_ref::(); - let is_show_popover = create_rw_signal(false); - let show_popover_handle = store_value(None::); + let popover_ref = NodeRef::::new(); + let target_ref = NodeRef::::new(); + let is_show_popover = RwSignal::new(false); + let show_popover_handle = StoredValue::new(None::); let on_mouse_enter = move |_| { if trigger_type != PopoverTriggerType::Hover { @@ -63,6 +64,9 @@ pub fn Popover( if trigger_type != PopoverTriggerType::Click { return; } + if !is_show_popover.get_untracked() { + return; + } let el = ev.target(); let mut el: Option = el.into_js_result().map_or(None, |el| Some(el.into())); @@ -101,7 +105,7 @@ pub fn Popover( view! {
    -
    {children()}
    + {children()}
    @@ -139,6 +143,21 @@ pub fn Popover( } } +#[derive(Clone)] +pub enum PopoverAppearance { + Brand, + Inverted, +} + +impl PopoverAppearance { + pub fn as_str(&self) -> &'static str { + match self { + PopoverAppearance::Brand => "brand", + PopoverAppearance::Inverted => "inverted", + } + } +} + #[derive(Default, PartialEq, Clone)] pub enum PopoverTriggerType { #[default] diff --git a/thaw/src/popover/popover.css b/thaw/src/popover/popover.css index 71daa91..1f1afff 100644 --- a/thaw/src/popover/popover.css +++ b/thaw/src/popover/popover.css @@ -14,6 +14,16 @@ div.thaw-popover-surface { color: var(--colorNeutralForeground1); } +div.thaw-popover-surface--brand { + background-color: var(--colorBrandBackground); + color: var(--colorNeutralForegroundOnBrand); +} + +div.thaw-popover-surface--inverted { + background-color: var(--colorNeutralBackgroundStatic); + color: var(--colorNeutralForegroundStaticInverted); +} + .thaw-popover-surface__angle { position: absolute; background-color: inherit; @@ -53,99 +63,70 @@ div.thaw-popover-surface { left: 50%; } -[data-thaw-placement="left-start"] > .thaw-popover, -[data-thaw-placement="left-end"] > .thaw-popover, -[data-thaw-placement="left"] > .thaw-popover { +[data-thaw-placement="left-start"] > .thaw-popover-surface, +[data-thaw-placement="left-end"] > .thaw-popover-surface, +[data-thaw-placement="left"] > .thaw-popover-surface { margin-right: 10px; - box-shadow: 3px 0 6px -4px rgba(0, 0, 0, 0.12), - 6px 0 16px 0 rgba(0, 0, 0, 0.08), 9px 0 28px 8px rgba(0, 0, 0, 0.05); } [data-thaw-placement="left-start"] .thaw-popover-surface__angle, [data-thaw-placement="left-end"] .thaw-popover-surface__angle, [data-thaw-placement="left"] .thaw-popover-surface__angle { - width: 10px; - height: 100%; - right: -10px; - top: 0; - bottom: 0; -} - -[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before, -[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before, -[data-thaw-placement="left"] .thaw-popover-surface__angle::before { - top: 50%; transform: rotate(45deg) translateX(-7px); + top: 50%; + right: -10px; } -[data-thaw-placement="right-start"] > .thaw-popover, -[data-thaw-placement="right-end"] > .thaw-popover, -[data-thaw-placement="right"] > .thaw-popover { +[data-thaw-placement="right-start"] > .thaw-popover-surface, +[data-thaw-placement="right-end"] > .thaw-popover-surface, +[data-thaw-placement="right"] > .thaw-popover-surface { margin-left: 10px; - box-shadow: -3px 0 6px -4px rgba(0, 0, 0, 0.12), - -6px 0 16px 0 rgba(0, 0, 0, 0.08), -9px 0 28px 8px rgba(0, 0, 0, 0.05); } [data-thaw-placement="right-start"] .thaw-popover-surface__angle, [data-thaw-placement="right-end"] .thaw-popover-surface__angle, [data-thaw-placement="right"] .thaw-popover-surface__angle { - width: 10px; - height: 100%; - left: -10px; - top: 0; - bottom: 0; -} - -[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before, -[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before, -[data-thaw-placement="right"] .thaw-popover-surface__angle::before { - top: 50%; transform: rotate(45deg) translateY(-7px); + top: 50%; + left: -10px; } [data-thaw-placement="bottom-start"] .thaw-popover-surface__angle, [data-thaw-placement="top-start"] .thaw-popover-surface__angle { left: 16px; } -[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle::before, -[data-thaw-placement="top-end"] .thaw-popover-surface__angle::before { +[data-thaw-placement="bottom-end"] .thaw-popover-surface__angle, +[data-thaw-placement="top-end"] .thaw-popover-surface__angle { left: initial; right: 7px; } -[data-thaw-placement="right-start"] .thaw-popover-surface__angle::before, -[data-thaw-placement="left-start"] .thaw-popover-surface__angle::before { +[data-thaw-placement="right-start"] .thaw-popover-surface__angle, +[data-thaw-placement="left-start"] .thaw-popover-surface__angle { top: 16px; } -[data-thaw-placement="right-end"] .thaw-popover-surface__angle::before, -[data-thaw-placement="left-end"] .thaw-popover-surface__angle::before { +[data-thaw-placement="right-end"] .thaw-popover-surface__angle, +[data-thaw-placement="left-end"] .thaw-popover-surface__angle { top: initial; bottom: 7px; } -.thaw-popover.popover-transition-enter-from, -.thaw-popover.popover-transition-leave-to { +.thaw-popover-surface.popover-transition-enter-from, +.thaw-popover-surface.popover-transition-leave-to { opacity: 0; transform: scale(0.85); } -.thaw-popover.popover-transition-enter-to, -.thaw-popover.popover-transition-leave-from { +.thaw-popover-surface.popover-transition-enter-to, +.thaw-popover-surface.popover-transition-leave-from { transform: scale(1); opacity: 1; } -.thaw-popover.popover-transition-enter-active { - transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.15s cubic-bezier(0, 0, 0.2, 1), - transform 0.15s cubic-bezier(0, 0, 0.2, 1); -} - -.thaw-popover.popover-transition-leave-active { - transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.15s cubic-bezier(0.4, 0, 1, 1), - transform 0.15s cubic-bezier(0.4, 0, 1, 1); +.thaw-popover-surface.popover-transition-leave-active, +.thaw-popover-surface.popover-transition-enter-active { + transition: box-shadow var(--durationSlow) var(--curveDecelerateMid), + background-color var(--durationSlow) var(--curveDecelerateMid), + color var(--durationSlow) var(--curveDecelerateMid), + opacity var(--durationNormal) var(--curveDecelerateMid), + transform var(--durationNormal) var(--curveDecelerateMid); } diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 5340105..b621229 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -2,6 +2,7 @@ use thaw_macro::WriteCSSVars; #[derive(Clone, WriteCSSVars)] pub struct ColorTheme { + pub color_neutral_background_static: String, pub color_neutral_background_disabled: String, pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, @@ -15,6 +16,7 @@ pub struct ColorTheme { pub color_neutral_background_5: String, pub color_neutral_background_6: String, + pub color_neutral_foreground_static_inverted: String, pub color_neutral_foreground_disabled: String, pub color_neutral_foreground_1: String, pub color_neutral_foreground_1_hover: String, @@ -100,6 +102,7 @@ pub struct ColorTheme { impl ColorTheme { pub fn light() -> Self { Self { + color_neutral_background_static: "#333333".into(), color_neutral_background_disabled: "#f0f0f0".into(), color_neutral_background_1: "#ffffff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), @@ -113,6 +116,7 @@ impl ColorTheme { color_neutral_background_5: "#ebebeb".into(), color_neutral_background_6: "#e6e6e6".into(), + color_neutral_foreground_static_inverted: "#ffffff".into(), color_neutral_foreground_disabled: "#bdbdbd".into(), color_neutral_foreground_1: "#242424".into(), color_neutral_foreground_1_hover: "#242424".into(), @@ -199,6 +203,7 @@ impl ColorTheme { pub fn dark() -> Self { Self { + color_neutral_background_static: "#3d3d3d".into(), color_neutral_background_disabled: "#141414".into(), color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), @@ -212,6 +217,7 @@ impl ColorTheme { color_neutral_background_5: "#000000".into(), color_neutral_background_6: "#333333".into(), + color_neutral_foreground_static_inverted: "#ffffff".into(), color_neutral_foreground_disabled: "#5c5c5c".into(), color_neutral_foreground_1: "#fff".into(), color_neutral_foreground_1_hover: "#fff".into(), diff --git a/thaw_components/src/css_transition/mod.rs b/thaw_components/src/css_transition/mod.rs index aeb8a88..1e199d7 100644 --- a/thaw_components/src/css_transition/mod.rs +++ b/thaw_components/src/css_transition/mod.rs @@ -260,7 +260,11 @@ fn get_timeout(mut delays: Vec, durations: &Vec) -> u64 { return 0; } - let s = s.split_at(s.len() - 1).0; + let s = if s.ends_with("ms") { + s.split_at(s.len() - 2).0 + } else { + s.split_at(s.len() - 1).0 + }; (s.parse::().unwrap_or_default() * 1000.0).floor() as u64 } From c5cc6337b7c0e16503f1632d4337f12729df491a Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 14 Jun 2024 17:23:02 +0800 Subject: [PATCH 046/143] refactor: auto_complete --- demo/src/components/site_header.rs | 1 + demo_markdown/docs/auto_complete/mod.md | 21 +- thaw/src/auto_complete/auto-complete.css | 64 ++++-- .../src/auto_complete/auto_complete_option.rs | 20 ++ thaw/src/auto_complete/mod.rs | 189 +++++++++--------- thaw/src/auto_complete/theme.rs | 23 --- thaw/src/popover/mod.rs | 1 - thaw/src/theme/common.rs | 2 + thaw/src/theme/mod.rs | 9 +- 9 files changed, 186 insertions(+), 144 deletions(-) create mode 100644 thaw/src/auto_complete/auto_complete_option.rs delete mode 100644 thaw/src/auto_complete/theme.rs diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index d1f4413..960700e 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -149,6 +149,7 @@ pub fn SiteHeader() -> impl IntoView { +

    diff --git a/demo_markdown/docs/auto_complete/mod.md b/demo_markdown/docs/auto_complete/mod.md index 9074973..4602621 100644 --- a/demo_markdown/docs/auto_complete/mod.md +++ b/demo_markdown/docs/auto_complete/mod.md @@ -1,23 +1,30 @@ # Auto Complete ```rust demo -let value = create_rw_signal(String::new()); -let options = create_memo(move |_| { +let value = RwSignal::new(String::new()); +let options = Memo::>::new(move |_| { let prefix = value .get() .split_once('@') .map_or(value.get(), |v| v.0.to_string()); vec!["@gmail.com", "@163.com"] .into_iter() - .map(|suffix| AutoCompleteOption { - label: format!("{prefix}{suffix}"), - value: format!("{prefix}{suffix}"), - }) + .map(|suffix| (format!("{prefix}{suffix}"), format!("{prefix}{suffix}"))) .collect() }); view! { - + + + + {option.1} + + + } ``` diff --git a/thaw/src/auto_complete/auto-complete.css b/thaw/src/auto_complete/auto-complete.css index 16bb61c..da394f7 100644 --- a/thaw/src/auto_complete/auto-complete.css +++ b/thaw/src/auto_complete/auto-complete.css @@ -1,13 +1,27 @@ -.thaw-auto-complete__menu { +.thaw-auto-complete { + display: inline-flex; +} + +.thaw-auto-complete > .thaw-input { + min-width: 250px; +} + +div.thaw-auto-complete__listbox { width: 100%; + + row-gap: var(--spacingHorizontalXXS); + display: flex; + flex-direction: column; + min-width: 160px; + /* max-height: 80vh; */ max-height: 200px; - padding: 5px; - background-color: var(--thaw-background-color); - border-radius: 3px; + background-color: var(--colorNeutralBackground1); + padding: var(--spacingHorizontalXS); + outline: 1px solid var(--colorTransparentStroke); + border-radius: var(--borderRadiusMedium); box-sizing: border-box; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); - overflow: auto; + box-shadow: var(--shadow16); + overflow-y: auto; } .thaw-auto-complete__menu-item { padding: 6px 5px; @@ -19,7 +33,7 @@ background-color: var(--thaw-background-color-hover); } -.thaw-auto-complete__menu.fade-in-scale-up-transition-leave-active { +.thaw-auto-complete__listbox.fade-in-scale-up-transition-leave-active { transform-origin: inherit; transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), transform 0.2s cubic-bezier(0.4, 0, 1, 1), @@ -27,7 +41,7 @@ box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.thaw-auto-complete__menu.fade-in-scale-up-transition-enter-active { +.thaw-auto-complete__listbox.fade-in-scale-up-transition-enter-active { transform-origin: inherit; transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1), @@ -35,14 +49,38 @@ box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.thaw-auto-complete__menu.fade-in-scale-up-transition-enter-from, -.thaw-auto-complete__menu.fade-in-scale-up-transition-leave-to { +.thaw-auto-complete__listbox.fade-in-scale-up-transition-enter-from, +.thaw-auto-complete__listbox.fade-in-scale-up-transition-leave-to { opacity: 0; transform: scale(0.9); } -.thaw-auto-complete__menu.fade-in-scale-up-transition-leave-from, -.thaw-auto-complete__menu.fade-in-scale-up-transition-enter-to { +.thaw-auto-complete__listbox.fade-in-scale-up-transition-leave-from, +.thaw-auto-complete__listbox.fade-in-scale-up-transition-enter-to { opacity: 1; transform: scale(1); } + +.thaw-auto-complete-option { + column-gap: var(--spacingHorizontalXS); + position: relative; + display: flex; + align-items: center; + padding: var(--spacingVerticalSNudge) var(--spacingHorizontalS); + line-height: var(--lineHeightBase300); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground1); + border-radius: var(--borderRadiusMedium); + cursor: pointer; +} + +.thaw-auto-complete-option:hover { + color: var(--colorNeutralForeground1Hover); + background-color: var(--colorNeutralBackground1Hover); +} + +.thaw-auto-complete-option:active { + color: var(--colorNeutralForeground1Pressed); + background-color: var(--colorNeutralBackground1Pressed); +} \ No newline at end of file diff --git a/thaw/src/auto_complete/auto_complete_option.rs b/thaw/src/auto_complete/auto_complete_option.rs new file mode 100644 index 0000000..a242b5c --- /dev/null +++ b/thaw/src/auto_complete/auto_complete_option.rs @@ -0,0 +1,20 @@ +use leptos::*; +use super::AutoCompleteInjection; + +#[component] +pub fn AutoCompleteOption2(key: String, children: Children) -> impl IntoView { + let auto_complete = AutoCompleteInjection::use_(); + let is_selected = Memo::new(move |_| { + auto_complete.is_selected(&key) + }); + + view! { +
    + {children()} +
    + } +} diff --git a/thaw/src/auto_complete/mod.rs b/thaw/src/auto_complete/mod.rs index 4e3bbd5..9d8326d 100644 --- a/thaw/src/auto_complete/mod.rs +++ b/thaw/src/auto_complete/mod.rs @@ -1,10 +1,12 @@ -mod theme; +mod auto_complete_option; -pub use theme::AutoCompleteTheme; +pub use auto_complete_option::AutoCompleteOption2; -use crate::{use_theme, ComponentRef, Input, InputPrefix, InputRef, InputSuffix, Theme}; +use crate::{ComponentRef, ConfigInjection, Input, InputPrefix, InputRef, InputSuffix}; use leptos::*; -use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth}; +use thaw_components::{ + Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth, OptionComp, +}; use thaw_utils::{class_list, mount_style, Model, OptionalProp, StoredMaybeSignal}; #[derive(Clone, PartialEq)] @@ -39,24 +41,10 @@ pub fn AutoComplete( #[prop(optional)] auto_complete_suffix: Option, #[prop(optional)] comp_ref: ComponentRef, #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, + #[prop(optional)] children: Option, ) -> impl IntoView { mount_style("auto-complete", include_str!("./auto-complete.css")); - let theme = use_theme(Theme::light); - let menu_css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.select.menu_background_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-hover: {};", - theme.select.menu_background_color_hover - )); - }); - css_vars - }); - + let config_provider = ConfigInjection::use_(); let input_ref = ComponentRef::::new(); let default_index = if allow_free_input { None } else { Some(0) }; @@ -201,88 +189,101 @@ pub fn AutoComplete( placement=FollowerPlacement::BottomStart width=FollowerWidth::Target > - -
    + +
    - {move || { - options - .get() - .into_iter() - .enumerate() - .map(|(index, v)| { - let AutoCompleteOption { value: option_value, label } = v; - let menu_item_ref = create_node_ref::(); - let on_click = move |_| { - select_value(option_value.clone()); - }; - let on_mouseenter = move |_| { - select_option_index.set(Some(index)); - }; - let on_mousedown = move |ev: ev::MouseEvent| { - ev.prevent_default(); - }; - create_effect(move |_| { - if Some(index) == select_option_index.get() { - if !is_show_menu.get() { - return; - } - if let Some(menu_item_ref) = menu_item_ref.get() { - let menu_ref = menu_ref.get().unwrap(); - let menu_rect = menu_ref.get_bounding_client_rect(); - let item_rect = menu_item_ref.get_bounding_client_rect(); - if item_rect.y() < menu_rect.y() { - menu_item_ref.scroll_into_view_with_bool(true); - } else if item_rect.y() + item_rect.height() - > menu_rect.y() + menu_rect.height() - { - menu_item_ref.scroll_into_view_with_bool(false); - } - } - } - }); - view! { -
    (); + // let on_click = move |_| { + // select_value(option_value.clone()); + // }; + // let on_mouseenter = move |_| { + // select_option_index.set(Some(index)); + // }; + // let on_mousedown = move |ev: ev::MouseEvent| { + // ev.prevent_default(); + // }; + // create_effect(move |_| { + // if Some(index) == select_option_index.get() { + // if !is_show_menu.get() { + // return; + // } + // if let Some(menu_item_ref) = menu_item_ref.get() { + // let menu_ref = menu_ref.get().unwrap(); + // let menu_rect = menu_ref.get_bounding_client_rect(); + // let item_rect = menu_item_ref.get_bounding_client_rect(); + // if item_rect.y() < menu_rect.y() { + // menu_item_ref.scroll_into_view_with_bool(true); + // } else if item_rect.y() + item_rect.height() + // > menu_rect.y() + menu_rect.height() + // { + // menu_item_ref.scroll_into_view_with_bool(false); + // } + // } + // } + // }); + // view! { + //
    - {label} -
    - } - }) - .collect_view() - }} - -
    - + // on:click=on_click + // on:mousedown=on_mousedown + // on:mouseenter=on_mouseenter + // ref=menu_item_ref + // > + // {label} + //
    + // } + // }) + // .collect_view() + // }} + + {children()} + +
    +
    + } } +#[derive(Clone)] +pub(crate) struct AutoCompleteInjection(pub Model); + +impl AutoCompleteInjection { + pub fn use_() -> Self { + expect_context() + } + + pub fn is_selected(&self, key: &String) -> bool { + self.0.with(|value| value == key) + } +} + #[derive(Clone)] pub struct AutoCompleteRef { input_ref: ComponentRef, diff --git a/thaw/src/auto_complete/theme.rs b/thaw/src/auto_complete/theme.rs deleted file mode 100644 index 83549c7..0000000 --- a/thaw/src/auto_complete/theme.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct AutoCompleteTheme { - pub menu_background_color: String, - pub menu_background_color_hover: String, -} - -impl ThemeMethod for AutoCompleteTheme { - fn light() -> Self { - Self { - menu_background_color: "#fff".into(), - menu_background_color_hover: "#f3f5f6".into(), - } - } - - fn dark() -> Self { - Self { - menu_background_color: "#48484e".into(), - menu_background_color_hover: "#ffffff17".into(), - } - } -} diff --git a/thaw/src/popover/mod.rs b/thaw/src/popover/mod.rs index bf96551..0a6d416 100644 --- a/thaw/src/popover/mod.rs +++ b/thaw/src/popover/mod.rs @@ -1,6 +1,5 @@ use crate::ConfigInjection; use leptos::{leptos_dom::helpers::TimeoutHandle, *}; -use palette::bool_mask::BoolMask; use std::time::Duration; use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement}; use thaw_utils::{add_event_listener, class_list, mount_style}; diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index f720706..a184beb 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -58,6 +58,7 @@ pub struct CommonTheme { pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, pub spacing_vertical_none: String, + pub spacing_vertical_s_nudge: String, pub spacing_vertical_s: String, pub spacing_vertical_m_nudge: String, pub spacing_vertical_m: String, @@ -139,6 +140,7 @@ impl CommonTheme { spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), spacing_vertical_none: "0".into(), + spacing_vertical_s_nudge: "6px".into(), spacing_vertical_s: "8px".into(), spacing_vertical_m_nudge: "10px".into(), spacing_vertical_m: "12px".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index dce520d..7b2fe4a 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,9 +4,9 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, - DatePickerTheme, InputTheme, MessageTheme, ProgressTheme, ScrollbarTheme, - SelectTheme, TimePickerTheme, UploadTheme, + AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, + InputTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, + UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -28,7 +28,6 @@ pub struct Theme { pub upload: UploadTheme, pub nav_bar: NavBarTheme, pub tabbar: TabbarTheme, - pub auto_complete: AutoCompleteTheme, pub color_picker: ColorPickerTheme, pub progress: ProgressTheme, pub calendar: CalendarTheme, @@ -52,7 +51,6 @@ impl Theme { upload: UploadTheme::light(), nav_bar: NavBarTheme::light(), tabbar: TabbarTheme::light(), - auto_complete: AutoCompleteTheme::light(), color_picker: ColorPickerTheme::light(), progress: ProgressTheme::light(), calendar: CalendarTheme::light(), @@ -75,7 +73,6 @@ impl Theme { upload: UploadTheme::dark(), nav_bar: NavBarTheme::dark(), tabbar: TabbarTheme::dark(), - auto_complete: AutoCompleteTheme::dark(), color_picker: ColorPickerTheme::dark(), progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), From 7e04778a44978f59eb90733438adc7284c697af0 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sat, 22 Jun 2024 22:14:31 +0800 Subject: [PATCH 047/143] refactor: ColorPicker --- thaw/src/auto_complete/auto-complete.css | 2 +- thaw/src/color_picker/color-picker.css | 20 +++++----- thaw/src/color_picker/mod.rs | 49 ++++++++---------------- thaw/src/color_picker/theme.rs | 20 ---------- thaw/src/theme/common.rs | 2 + thaw/src/theme/mod.rs | 5 +-- 6 files changed, 30 insertions(+), 68 deletions(-) delete mode 100644 thaw/src/color_picker/theme.rs diff --git a/thaw/src/auto_complete/auto-complete.css b/thaw/src/auto_complete/auto-complete.css index da394f7..3580831 100644 --- a/thaw/src/auto_complete/auto-complete.css +++ b/thaw/src/auto_complete/auto-complete.css @@ -83,4 +83,4 @@ div.thaw-auto-complete__listbox { .thaw-auto-complete-option:active { color: var(--colorNeutralForeground1Pressed); background-color: var(--colorNeutralBackground1Pressed); -} \ No newline at end of file +} diff --git a/thaw/src/color_picker/color-picker.css b/thaw/src/color_picker/color-picker.css index 31e4528..2c2911d 100644 --- a/thaw/src/color_picker/color-picker.css +++ b/thaw/src/color_picker/color-picker.css @@ -1,10 +1,10 @@ .thaw-color-picker-trigger { display: inline-block; - padding: 4px; + padding: var(--spacingVerticalXS) var(--spacingHorizontalXS); width: 100%; - height: 34px; - border: 1px solid #e0e0e6; - border-radius: 3px; + height: 32px; + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + border-radius: var(--borderRadiusMedium); box-sizing: border-box; cursor: pointer; } @@ -14,17 +14,15 @@ justify-content: center; align-items: center; height: 100%; - font-size: 14px; } -.thaw-color-picker-popover { +div.thaw-color-picker-popover { width: 240px; - padding: 12px; - background-color: var(--thaw-background-color); - border-radius: 3px; + padding: var(--spacingVerticalM) var(--spacingHorizontalM); + background-color: var(--colorNeutralBackground1); + border-radius: var(--borderRadiusMedium); box-sizing: border-box; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); + box-shadow: var(--shadow16); } .thaw-color-picker-popover__panel { diff --git a/thaw/src/color_picker/mod.rs b/thaw/src/color_picker/mod.rs index c7d4b5f..9ddbca3 100644 --- a/thaw/src/color_picker/mod.rs +++ b/thaw/src/color_picker/mod.rs @@ -1,10 +1,8 @@ mod color; -mod theme; pub use color::*; -pub use theme::ColorPickerTheme; -use crate::{use_theme, Theme}; +use crate::ConfigInjection; use leptos::leptos_dom::helpers::WindowListenerHandle; use leptos::*; use palette::{Hsv, IntoColor, Srgb}; @@ -17,20 +15,11 @@ pub fn ColorPicker( #[prop(optional, into)] class: OptionalProp>, ) -> impl IntoView { mount_style("color-picker", include_str!("./color-picker.css")); - let theme = use_theme(Theme::light); - let popover_css_vars = create_memo(move |_| { - theme.with(|theme| { - format!( - "--thaw-background-color: {};", - theme.color_picker.popover_background_color - ) - }) - }); - - let hue = create_rw_signal(0f32); - let sv = create_rw_signal((0f32, 0f32)); - let label = create_rw_signal(String::new()); - let style = create_memo(move |_| { + let config_provider = ConfigInjection::use_(); + let hue = RwSignal::new(0f32); + let sv = RwSignal::new((0f32, 0f32)); + let label = RwSignal::new(String::new()); + let style = Memo::new(move |_| { let mut style = String::new(); value.with(|color| { @@ -77,7 +66,7 @@ pub fn ColorPicker( style }); - create_effect(move |prev| { + Effect::new(move |prev| { let (s, v) = sv.get(); let hue_value = hue.get(); if prev.is_none() { @@ -106,9 +95,9 @@ pub fn ColorPicker( } }); - let is_show_popover = create_rw_signal(false); - let trigger_ref = create_node_ref::(); - let popover_ref = create_node_ref::(); + let is_show_popover = RwSignal::new(false); + let trigger_ref = NodeRef::::new(); + let popover_ref = NodeRef::::new(); let show_popover = move |_| { is_show_popover.set(true); }; @@ -157,14 +146,10 @@ pub fn ColorPicker( let:display >
    @@ -178,8 +163,8 @@ pub fn ColorPicker( #[component] fn ColorPanel(hue: ReadSignal, sv: RwSignal<(f32, f32)>) -> impl IntoView { - let panel_ref = create_node_ref::(); - let mouse = store_value(Vec::::new()); + let panel_ref = NodeRef::::new(); + let mouse = StoredValue::new(Vec::::new()); let on_mouse_down = move |ev| { let cb = move |ev: ev::MouseEvent| { @@ -251,8 +236,8 @@ fn ColorPanel(hue: ReadSignal, sv: RwSignal<(f32, f32)>) -> impl IntoView { #[component] fn HueSlider(hue: RwSignal) -> impl IntoView { - let rail_ref = create_node_ref::(); - let mouse = store_value(Vec::::new()); + let rail_ref = NodeRef::::new(); + let mouse = StoredValue::new(Vec::::new()); let on_mouse_down = move |ev| { let cb = move |ev: ev::MouseEvent| { diff --git a/thaw/src/color_picker/theme.rs b/thaw/src/color_picker/theme.rs deleted file mode 100644 index 5fa8ea7..0000000 --- a/thaw/src/color_picker/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct ColorPickerTheme { - pub popover_background_color: String, -} - -impl ThemeMethod for ColorPickerTheme { - fn light() -> Self { - Self { - popover_background_color: "#fff".into(), - } - } - - fn dark() -> Self { - Self { - popover_background_color: "#48484e".into(), - } - } -} diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index a184beb..7a5cae1 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -58,6 +58,7 @@ pub struct CommonTheme { pub spacing_horizontal_m: String, pub spacing_horizontal_l: String, pub spacing_vertical_none: String, + pub spacing_vertical_x_s: String, pub spacing_vertical_s_nudge: String, pub spacing_vertical_s: String, pub spacing_vertical_m_nudge: String, @@ -140,6 +141,7 @@ impl CommonTheme { spacing_horizontal_m: "12px".into(), spacing_horizontal_l: "16px".into(), spacing_vertical_none: "0".into(), + spacing_vertical_x_s: "4px".into(), spacing_vertical_s_nudge: "6px".into(), spacing_vertical_s: "8px".into(), spacing_vertical_m_nudge: "10px".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 7b2fe4a..cb21dd8 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,7 +4,7 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, ColorPickerTheme, DatePickerTheme, + AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, DatePickerTheme, InputTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, UploadTheme, }; @@ -28,7 +28,6 @@ pub struct Theme { pub upload: UploadTheme, pub nav_bar: NavBarTheme, pub tabbar: TabbarTheme, - pub color_picker: ColorPickerTheme, pub progress: ProgressTheme, pub calendar: CalendarTheme, pub time_picker: TimePickerTheme, @@ -51,7 +50,6 @@ impl Theme { upload: UploadTheme::light(), nav_bar: NavBarTheme::light(), tabbar: TabbarTheme::light(), - color_picker: ColorPickerTheme::light(), progress: ProgressTheme::light(), calendar: CalendarTheme::light(), time_picker: TimePickerTheme::light(), @@ -73,7 +71,6 @@ impl Theme { upload: UploadTheme::dark(), nav_bar: NavBarTheme::dark(), tabbar: TabbarTheme::dark(), - color_picker: ColorPickerTheme::dark(), progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), time_picker: TimePickerTheme::dark(), From 0bf842536fefaa5832177be07823a8657046fc38 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sun, 23 Jun 2024 23:33:09 +0800 Subject: [PATCH 048/143] refactor: Textarea --- demo/src/app.rs | 1 + demo/src/pages/components.rs | 4 ++ demo_markdown/docs/input/mod.md | 3 - demo_markdown/docs/textarea/mod.md | 26 +++++++ demo_markdown/src/lib.rs | 1 + thaw/src/input/mod.rs | 6 -- thaw/src/input/theme.rs | 35 ---------- thaw/src/lib.rs | 6 +- thaw/src/textarea/mod.rs | 106 +++++++++++++++++++++++++++++ thaw/src/textarea/textarea.css | 95 ++++++++++++++++++++++++++ thaw/src/theme/mod.rs | 8 +-- 11 files changed, 239 insertions(+), 52 deletions(-) create mode 100644 demo_markdown/docs/textarea/mod.md delete mode 100644 thaw/src/input/theme.rs create mode 100644 thaw/src/textarea/mod.rs create mode 100644 thaw/src/textarea/textarea.css diff --git a/demo/src/app.rs b/demo/src/app.rs index 5b8b81d..01c5978 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -86,6 +86,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index d5fb3a3..72f4338 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -199,6 +199,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/text".into(), label: "Text".into(), }, + MenuItemOption { + value: "/components/textarea".into(), + label: "Textarea".into(), + }, MenuItemOption { value: "/components/auto-complete".into(), label: "Auto Complete".into(), diff --git a/demo_markdown/docs/input/mod.md b/demo_markdown/docs/input/mod.md index 2115557..da8d71f 100644 --- a/demo_markdown/docs/input/mod.md +++ b/demo_markdown/docs/input/mod.md @@ -7,7 +7,6 @@ view! { - + + } +} + +#[derive(Clone)] +pub struct TextAreaRef { + textarea_ref: NodeRef, +} + +impl TextAreaRef { + pub fn focus(&self) { + if let Some(textarea_el) = self.textarea_ref.get_untracked() { + _ = textarea_el.focus(); + } + } + + pub fn blur(&self) { + if let Some(textarea_el) = self.textarea_ref.get_untracked() { + _ = textarea_el.blur(); + } + } +} diff --git a/thaw/src/textarea/textarea.css b/thaw/src/textarea/textarea.css new file mode 100644 index 0000000..c2341e0 --- /dev/null +++ b/thaw/src/textarea/textarea.css @@ -0,0 +1,95 @@ +.thaw-textarea { + position: relative; + display: inline-flex; + margin: 0px; + padding: 0 0 var(--strokeWidthThick) 0; + background-color: var(--colorNeutralBackground1); + border-radius: var(--borderRadiusMedium); + border-bottom-color: var(--colorNeutralStrokeAccessible); + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + box-sizing: border-box; +} + +.thaw-textarea:focus-within { + border-bottom-color: var(--colorCompoundBrandStroke); + outline-width: var(--strokeWidthThick); + outline-color: transparent; + outline-style: solid; + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); +} + +.thaw-textarea:hover { + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1Hover); + border-bottom-color: var(--colorNeutralStrokeAccessibleHover); +} + +.thaw-textarea:active { + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1Pressed); + border-bottom-color: var(--colorNeutralStrokeAccessiblePressed); +} + +/* .thaw-textarea--focus, +.thaw-textarea:hover:not(.thaw-textarea--disabled, .thaw-textarea--invalid) { + border-color: var(--thaw-border-color-hover); +} + +.thaw-textarea--disabled, +.thaw-textarea--disabled .thaw-textarea__textarea-el { + cursor: not-allowed; + background-color: var(--thaw-background-color-disabled); + color: var(--thaw-font-color-disabled); +} */ + +.thaw-textarea::after { + content: ""; + position: absolute; + bottom: -1px; + right: -1px; + left: -1px; + height: max(var(--strokeWidthThick), var(--borderRadiusMedium)); + border-bottom-right-radius: var(--borderRadiusMedium); + border-bottom-left-radius: var(--borderRadiusMedium); + box-sizing: border-box; + border-bottom: var(--strokeWidthThick) solid var(--colorCompoundBrandStroke); + transition-delay: var(--curveAccelerateMid); + transition-duration: var(--durationUltraFast); + transition-property: transform; + transform: scaleX(0); + clip-path: inset(calc(100% - var(--strokeWidthThick)) 0 0 0); +} + +.thaw-textarea:focus-within::after { + transition-delay: var(--curveDecelerateMid); + transition-duration: var(--durationNormal); + transition-property: transform; + transform: scaleX(1); +} + +.thaw-textarea:focus-within:active::after { + border-bottom-color: var(--colorCompoundBrandStrokePressed); +} + +.thaw-textarea__textarea { + flex-grow: 1; + height: 100%; + max-height: 260px; + min-height: 52px; + + margin: 0px; + padding: var(--spacingVerticalSNudge) + calc(var(--spacingHorizontalMNudge) + var(--spacingHorizontalXXS)); + outline-style: none; + background-color: transparent; + color: var(--colorNeutralForeground1); + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + border-style: none; + box-sizing: border-box; + resize: none; +} + +.thaw-textarea__textarea-el::placeholder { + color: var(--thaw-placeholder-color); +} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index cb21dd8..11a7d63 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,9 +4,8 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, DatePickerTheme, - InputTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, - UploadTheme, + AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, DatePickerTheme, MessageTheme, + ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -21,7 +20,6 @@ pub struct Theme { pub name: String, pub common: CommonTheme, pub color: ColorTheme, - pub input: InputTheme, pub alert: AlertTheme, pub message: MessageTheme, pub select: SelectTheme, @@ -43,7 +41,6 @@ impl Theme { name: "light".into(), common: CommonTheme::light(), color: ColorTheme::light(), - input: InputTheme::light(), alert: AlertTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), @@ -64,7 +61,6 @@ impl Theme { name: "dark".into(), common: CommonTheme::dark(), color: ColorTheme::dark(), - input: InputTheme::dark(), alert: AlertTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), From 2cbb4daa9aa2d0894c774e4b3f0fea4f6544ef69 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 24 Jun 2024 23:26:03 +0800 Subject: [PATCH 049/143] feat: Textarea adds resize prop --- demo_markdown/docs/textarea/mod.md | 13 +++ thaw/src/input/text-area.css | 54 ----------- thaw/src/input/text_area.rs | 150 ----------------------------- thaw/src/textarea/mod.rs | 53 ++++++---- thaw/src/textarea/textarea.css | 41 +++++--- 5 files changed, 77 insertions(+), 234 deletions(-) delete mode 100644 thaw/src/input/text-area.css delete mode 100644 thaw/src/input/text_area.rs diff --git a/demo_markdown/docs/textarea/mod.md b/demo_markdown/docs/textarea/mod.md index e1c6417..bf8160f 100644 --- a/demo_markdown/docs/textarea/mod.md +++ b/demo_markdown/docs/textarea/mod.md @@ -22,5 +22,18 @@ view! { } ``` +### Resize + +```rust demo +view! { + + -
    - } -} - -#[derive(Clone)] -pub struct TextAreaRef { - textarea_ref: NodeRef, -} - -impl TextAreaRef { - pub fn focus(&self) { - if let Some(textarea_el) = self.textarea_ref.get_untracked() { - _ = textarea_el.focus(); - } - } - - pub fn blur(&self) { - if let Some(textarea_el) = self.textarea_ref.get_untracked() { - _ = textarea_el.blur(); - } - } -} diff --git a/thaw/src/textarea/mod.rs b/thaw/src/textarea/mod.rs index ab7515c..d114405 100644 --- a/thaw/src/textarea/mod.rs +++ b/thaw/src/textarea/mod.rs @@ -1,22 +1,23 @@ use leptos::*; -use thaw_utils::{class_list, mount_style, ComponentRef, Model, OptionalProp}; +use thaw_utils::{class_list, mount_style, ComponentRef, Model}; #[component] pub fn Textarea( #[prop(optional, into)] value: Model, #[prop(optional, into)] allow_value: Option>, - #[prop(optional, into)] placeholder: OptionalProp>, + #[prop(optional, into)] placeholder: MaybeProp, #[prop(optional, into)] on_focus: Option>, #[prop(optional, into)] on_blur: Option>, #[prop(optional, into)] disabled: MaybeSignal, - #[prop(optional, into)] invalid: MaybeSignal, - #[prop(optional)] comp_ref: ComponentRef, - #[prop(optional, into)] class: OptionalProp>, + /// Which direction the Textarea is allowed to be resized. + #[prop(optional, into)] resize: MaybeSignal, + #[prop(optional)] comp_ref: ComponentRef, + #[prop(optional, into)] class: MaybeProp, #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, ) -> impl IntoView { mount_style("textarea", include_str!("./textarea.css")); - let value_trigger = create_trigger(); + let value_trigger = Trigger::new(); let on_input = move |ev| { let input_value = event_target_value(&ev); if let Some(allow_value) = allow_value.as_ref() { @@ -27,23 +28,20 @@ pub fn Textarea( } value.set(input_value); }; - let is_focus = create_rw_signal(false); let on_internal_focus = move |ev| { - is_focus.set(true); if let Some(on_focus) = on_focus.as_ref() { on_focus.call(ev); } }; let on_internal_blur = move |ev| { - is_focus.set(false); if let Some(on_blur) = on_blur.as_ref() { on_blur.call(ev); } }; - let textarea_ref = create_node_ref::(); + let textarea_ref = NodeRef::::new(); textarea_ref.on_load(move |_| { - comp_ref.load(TextAreaRef { textarea_ref }); + comp_ref.load(TextareaRef { textarea_ref }); }); #[cfg(debug_assertions)] @@ -62,9 +60,10 @@ pub fn Textarea( view! { @@ -87,11 +86,11 @@ pub fn Textarea( } #[derive(Clone)] -pub struct TextAreaRef { +pub struct TextareaRef { textarea_ref: NodeRef, } -impl TextAreaRef { +impl TextareaRef { pub fn focus(&self) { if let Some(textarea_el) = self.textarea_ref.get_untracked() { _ = textarea_el.focus(); @@ -104,3 +103,23 @@ impl TextAreaRef { } } } + +#[derive(Clone, Default)] +pub enum TextareaResize { + #[default] + None, + Both, + Horizontal, + Vertical, +} + +impl TextareaResize { + pub fn as_str(&self) -> &'static str { + match self { + TextareaResize::None => "none", + TextareaResize::Both => "both", + TextareaResize::Horizontal => "horizontal", + TextareaResize::Vertical => "vertical", + } + } +} diff --git a/thaw/src/textarea/textarea.css b/thaw/src/textarea/textarea.css index c2341e0..f0bafdc 100644 --- a/thaw/src/textarea/textarea.css +++ b/thaw/src/textarea/textarea.css @@ -5,8 +5,8 @@ padding: 0 0 var(--strokeWidthThick) 0; background-color: var(--colorNeutralBackground1); border-radius: var(--borderRadiusMedium); - border-bottom-color: var(--colorNeutralStrokeAccessible); border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + border-bottom-color: var(--colorNeutralStrokeAccessible); box-sizing: border-box; } @@ -28,18 +28,6 @@ border-bottom-color: var(--colorNeutralStrokeAccessiblePressed); } -/* .thaw-textarea--focus, -.thaw-textarea:hover:not(.thaw-textarea--disabled, .thaw-textarea--invalid) { - border-color: var(--thaw-border-color-hover); -} - -.thaw-textarea--disabled, -.thaw-textarea--disabled .thaw-textarea__textarea-el { - cursor: not-allowed; - background-color: var(--thaw-background-color-disabled); - color: var(--thaw-font-color-disabled); -} */ - .thaw-textarea::after { content: ""; position: absolute; @@ -93,3 +81,30 @@ .thaw-textarea__textarea-el::placeholder { color: var(--thaw-placeholder-color); } + +.thaw-textarea.thaw-textarea--disabled { + background-color: var(--colorTransparentBackground); + border: var(--strokeWidthThin) solid var(--colorNeutralStrokeDisabled); +} + +.thaw-textarea--disabled > .thaw-textarea__textarea { + background-color: var(--colorTransparentBackground); + color: var(--colorNeutralForegroundDisabled); + cursor: not-allowed; +} + +.thaw-textarea--disabled > .thaw-textarea__textarea::placeholder { + color: var(--colorNeutralForegroundDisabled); +} + +.thaw-textarea--resize-vertical > .thaw-textarea__textarea { + resize: vertical; +} + +.thaw-textarea--resize-horizontal > .thaw-textarea__textarea { + resize: horizontal; +} + +.thaw-textarea--resize-both > .thaw-textarea__textarea { + resize: both; +} From 14437c07a8a7f5238618ce381be044eb44c2073e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 25 Jun 2024 22:57:44 +0800 Subject: [PATCH 050/143] refactor: DatePicker --- demo/src/pages/components.rs | 8 ++-- thaw/src/date_picker/date-picker.css | 38 +++++++---------- thaw/src/date_picker/mod.rs | 4 -- thaw/src/date_picker/panel/mod.rs | 61 ++++++++++++++-------------- thaw/src/date_picker/theme.rs | 29 ------------- thaw/src/theme/mod.rs | 5 +-- 6 files changed, 50 insertions(+), 95 deletions(-) delete mode 100644 thaw/src/date_picker/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 72f4338..4b2fb5c 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -163,6 +163,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/config-provider".into(), label: "Config Provider".into(), }, + MenuItemOption { + value: "/components/date-picker".into(), + label: "Date Picker".into(), + }, MenuItemOption { value: "/components/divider".into(), label: "Divider".into(), @@ -215,10 +219,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/checkbox".into(), label: "Checkbox".into(), }, - MenuItemOption { - value: "/components/date-picker".into(), - label: "Date Picker".into(), - }, MenuItemOption { value: "/components/input".into(), label: "Input".into(), diff --git a/thaw/src/date_picker/date-picker.css b/thaw/src/date_picker/date-picker.css index d00891b..f3f6343 100644 --- a/thaw/src/date_picker/date-picker.css +++ b/thaw/src/date_picker/date-picker.css @@ -1,10 +1,9 @@ .thaw-date-picker-panel { width: 300px; - background-color: var(--thaw-background-color); - border-radius: 3px; + background-color: var(--colorNeutralBackground1); + border-radius: var(--borderRadiusMedium); box-sizing: border-box; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); + box-shadow: var(--shadow16); } .thaw-date-picker-date-panel__calendar { @@ -18,10 +17,6 @@ justify-content: space-between; } -.thaw-date-picker-date-panel__header > button { - color: var(--thaw-font-color-other-month); -} - .thaw-date-picker-date-panel__header-month-year { flex: 1; display: flex; @@ -37,7 +32,7 @@ } .thaw-date-picker-date-panel__weekdays { - border-bottom: 1px solid var(--thaw-item-border-color); + border-bottom: var(--strokeWidthThin) solid var(--colorNeutralStroke1); margin-bottom: 2px; padding: 6px 4px; } @@ -55,7 +50,7 @@ } .thaw-date-picker-date-panel__item--other-month { - color: var(--thaw-font-color-other-month); + color: var(--colorNeutralForegroundDisabled); } .thaw-date-picker-date-panel__item-day { @@ -75,17 +70,17 @@ height: 4px; width: 4px; border-radius: 2px; - background-color: var(--thaw-background-color-today); + background-color: var(--colorBrandBackground); } .thaw-date-picker-date-panel__item:hover .thaw-date-picker-date-panel__item-day { - background-color: var(--thaw-item-background-color-hover); + background-color: var(--colorNeutralBackground1Hover); } .thaw-date-picker-date-panel__item--selected .thaw-date-picker-date-panel__item-day { - background-color: var(--thaw-background-color-today) !important; + background-color: var(--colorBrandBackground) !important; color: white; } @@ -95,7 +90,7 @@ flex-direction: row-reverse; justify-content: space-between; align-items: center; - border-top: 1px solid var(--thaw-item-border-color); + border-top: var(--strokeWidthThin) solid var(--colorNeutralStroke1); } .thaw-date-picker-date-panel__header-year { @@ -110,7 +105,7 @@ grid-template-columns: 28px 1fr 28px; align-items: center; justify-content: space-between; - border-bottom: 1px solid var(--thaw-item-border-color); + border-bottom: var(--strokeWidthThin) solid var(--colorNeutralStroke1); padding: 2px 6px; } @@ -118,15 +113,10 @@ display: flex; justify-content: space-between; align-items: center; - border-bottom: 1px solid var(--thaw-item-border-color); + border-bottom: var(--strokeWidthThin) solid var(--colorNeutralStroke1); padding: 4px 6px; } -.thaw-date-picker-year-panel__header > button, -.thaw-date-picker-month-panel__header > button { - color: var(--thaw-font-color-other-month); -} - .thaw-date-picker-year-panel__years, .thaw-date-picker-month-panel__months { display: grid; @@ -137,7 +127,7 @@ .thaw-date-picker-year-panel__item:first-child, .thaw-date-picker-year-panel__item:last-child { - color: var(--thaw-font-color-other-month); + color: var(--colorNeutralForegroundDisabled); } .thaw-date-picker-year-panel__item, @@ -153,7 +143,7 @@ .thaw-date-picker-year-panel__item-year, .thaw-date-picker-month-panel__item--selected .thaw-date-picker-month-panel__item-month { - background-color: var(--thaw-background-color-today) !important; + background-color: var(--colorBrandBackground) !important; color: white; } @@ -161,7 +151,7 @@ .thaw-date-picker-year-panel__item-year, .thaw-date-picker-month-panel__item:hover .thaw-date-picker-month-panel__item-month { - background-color: var(--thaw-item-background-color-hover); + background-color: var(--colorNeutralBackground1Hover); } .thaw-date-picker-year-panel__item-year, diff --git a/thaw/src/date_picker/mod.rs b/thaw/src/date_picker/mod.rs index 6797885..de35d39 100644 --- a/thaw/src/date_picker/mod.rs +++ b/thaw/src/date_picker/mod.rs @@ -1,8 +1,4 @@ mod panel; -mod theme; - -pub use theme::DatePickerTheme; - use crate::{Icon, Input, InputSuffix, SignalWatch}; use chrono::NaiveDate; use leptos::*; diff --git a/thaw/src/date_picker/panel/mod.rs b/thaw/src/date_picker/panel/mod.rs index 30e42ca..ddba399 100644 --- a/thaw/src/date_picker/panel/mod.rs +++ b/thaw/src/date_picker/panel/mod.rs @@ -2,7 +2,7 @@ mod date_panel; mod month_panel; mod year_panel; -use crate::{use_theme, Theme}; +use crate::ConfigInjection; use chrono::NaiveDate; use date_panel::DatePanel; use leptos::*; @@ -19,33 +19,33 @@ pub fn Panel( #[prop(into)] is_show_panel: MaybeSignal, #[prop(optional)] comp_ref: ComponentRef, ) -> impl IntoView { - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color-today: {};", - theme.common.color_primary - )); - css_vars.push_str(&format!( - "--thaw-font-color-other-month: {};", - theme.date_picker.panel_other_month_font_color, - )); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.date_picker.panel_background_color - )); - css_vars.push_str(&format!( - "--thaw-item-background-color-hover: {};", - theme.date_picker.panel_date_item_background_color_hover - )); - css_vars.push_str(&format!( - "--thaw-item-border-color: {};", - theme.date_picker.panel_border_color - )); - }); - css_vars - }); + let config_provider = ConfigInjection::use_(); + // let css_vars = create_memo(move |_| { + // let mut css_vars = String::new(); + // theme.with(|theme| { + // css_vars.push_str(&format!( + // "--thaw-background-color-today: {};", + // theme.common.color_primary + // )); + // css_vars.push_str(&format!( + // "--thaw-font-color-other-month: {};", + // theme.date_picker.panel_other_month_font_color, + // )); + // css_vars.push_str(&format!( + // "--thaw-background-color: {};", + // theme.date_picker.panel_background_color + // )); + // css_vars.push_str(&format!( + // "--thaw-item-background-color-hover: {};", + // theme.date_picker.panel_date_item_background_color_hover + // )); + // css_vars.push_str(&format!( + // "--thaw-item-border-color: {};", + // theme.date_picker.panel_border_color + // )); + // }); + // css_vars + // }); let panel_ref = create_node_ref::(); #[cfg(any(feature = "csr", feature = "hydrate"))] @@ -98,8 +98,9 @@ pub fn Panel( let:display >
    diff --git a/thaw/src/date_picker/theme.rs b/thaw/src/date_picker/theme.rs deleted file mode 100644 index c7597ca..0000000 --- a/thaw/src/date_picker/theme.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct DatePickerTheme { - pub panel_background_color: String, - pub panel_date_item_background_color_hover: String, - pub panel_border_color: String, - pub panel_other_month_font_color: String, -} - -impl ThemeMethod for DatePickerTheme { - fn light() -> Self { - Self { - panel_background_color: "#fff".into(), - panel_date_item_background_color_hover: "#f1f3f5".into(), - panel_border_color: "#e0e0e6".into(), - panel_other_month_font_color: "#c2c2c2".into(), - } - } - - fn dark() -> Self { - Self { - panel_background_color: "#48484e".into(), - panel_date_item_background_color_hover: "#ffffff1a".into(), - panel_border_color: "#ffffff3d".into(), - panel_other_month_font_color: "#ffffff61".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 11a7d63..052d21e 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,7 +4,7 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, DatePickerTheme, MessageTheme, + AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; @@ -29,7 +29,6 @@ pub struct Theme { pub progress: ProgressTheme, pub calendar: CalendarTheme, pub time_picker: TimePickerTheme, - pub date_picker: DatePickerTheme, pub scrollbar: ScrollbarTheme, pub back_top: BackTopTheme, pub anchor: AnchorTheme, @@ -50,7 +49,6 @@ impl Theme { progress: ProgressTheme::light(), calendar: CalendarTheme::light(), time_picker: TimePickerTheme::light(), - date_picker: DatePickerTheme::light(), scrollbar: ScrollbarTheme::light(), back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), @@ -70,7 +68,6 @@ impl Theme { progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), time_picker: TimePickerTheme::dark(), - date_picker: DatePickerTheme::dark(), scrollbar: ScrollbarTheme::dark(), back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(), From cdcc764b4870f449d8360de222476c1e31c862f1 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 25 Jun 2024 23:31:05 +0800 Subject: [PATCH 051/143] refactor: DatePicker --- thaw/src/date_picker/mod.rs | 8 +++--- thaw/src/date_picker/panel/date_panel.rs | 6 ++--- thaw/src/date_picker/panel/mod.rs | 33 +++-------------------- thaw/src/date_picker/panel/month_panel.rs | 6 ++--- 4 files changed, 13 insertions(+), 40 deletions(-) diff --git a/thaw/src/date_picker/mod.rs b/thaw/src/date_picker/mod.rs index de35d39..bc1a362 100644 --- a/thaw/src/date_picker/mod.rs +++ b/thaw/src/date_picker/mod.rs @@ -13,9 +13,9 @@ pub fn DatePicker( #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, ) -> impl IntoView { mount_style("date-picker", include_str!("./date-picker.css")); - let date_picker_ref = create_node_ref::(); - let is_show_panel = create_rw_signal(false); - let show_date_text = create_rw_signal(String::new()); + let date_picker_ref = NodeRef::::new(); + let is_show_panel = RwSignal::new(false); + let show_date_text = RwSignal::new(String::new()); let show_date_format = "%Y-%m-%d"; let update_show_date_text = move || { value.with_untracked(move |date| { @@ -27,7 +27,7 @@ pub fn DatePicker( }; update_show_date_text(); let panel_ref = ComponentRef::::default(); - let panel_selected_date = create_rw_signal(None::); + let panel_selected_date = RwSignal::new(None::); _ = panel_selected_date.watch(move |date| { let text = date.as_ref().map_or(String::new(), |date| { date.format(show_date_format).to_string() diff --git a/thaw/src/date_picker/panel/date_panel.rs b/thaw/src/date_picker/panel/date_panel.rs index 7691bfb..8b1df88 100644 --- a/thaw/src/date_picker/panel/date_panel.rs +++ b/thaw/src/date_picker/panel/date_panel.rs @@ -1,5 +1,5 @@ use super::PanelVariant; -use crate::{Button, ButtonSize, ButtonAppearance, CalendarItemDate}; +use crate::{Button, ButtonAppearance, ButtonSize, CalendarItemDate}; use chrono::{Datelike, Days, Month, Months, NaiveDate}; use leptos::*; use std::ops::Deref; @@ -12,7 +12,7 @@ pub fn DatePanel( close_panel: Callback>, panel_variant: RwSignal, ) -> impl IntoView { - let dates = create_memo(move |_| { + let dates = Memo::new(move |_| { let show_date = show_date.get(); let show_date_month = show_date.month(); let mut dates = vec![]; @@ -167,7 +167,7 @@ pub fn DatePanel( #[component] fn DatePanelItem(value: RwSignal>, date: CalendarItemDate) -> impl IntoView { - let is_selected = create_memo({ + let is_selected = Memo::new({ let date = date.clone(); move |_| value.with(|value_date| value_date.as_ref() == Some(date.deref())) }); diff --git a/thaw/src/date_picker/panel/mod.rs b/thaw/src/date_picker/panel/mod.rs index ddba399..f19b614 100644 --- a/thaw/src/date_picker/panel/mod.rs +++ b/thaw/src/date_picker/panel/mod.rs @@ -20,34 +20,7 @@ pub fn Panel( #[prop(optional)] comp_ref: ComponentRef, ) -> impl IntoView { let config_provider = ConfigInjection::use_(); - // let css_vars = create_memo(move |_| { - // let mut css_vars = String::new(); - // theme.with(|theme| { - // css_vars.push_str(&format!( - // "--thaw-background-color-today: {};", - // theme.common.color_primary - // )); - // css_vars.push_str(&format!( - // "--thaw-font-color-other-month: {};", - // theme.date_picker.panel_other_month_font_color, - // )); - // css_vars.push_str(&format!( - // "--thaw-background-color: {};", - // theme.date_picker.panel_background_color - // )); - // css_vars.push_str(&format!( - // "--thaw-item-background-color-hover: {};", - // theme.date_picker.panel_date_item_background_color_hover - // )); - // css_vars.push_str(&format!( - // "--thaw-item-border-color: {};", - // theme.date_picker.panel_border_color - // )); - // }); - // css_vars - // }); - - let panel_ref = create_node_ref::(); + let panel_ref = NodeRef::::new(); #[cfg(any(feature = "csr", feature = "hydrate"))] { use leptos::wasm_bindgen::__rt::IntoJsResult; @@ -82,8 +55,8 @@ pub fn Panel( _ = date_picker_ref; _ = panel_ref; } - let panel_variant = create_rw_signal(PanelVariant::Date); - let show_date = create_rw_signal(selected_date.get_untracked().unwrap_or(now_date())); + let panel_variant = RwSignal::new(PanelVariant::Date); + let show_date = RwSignal::new(selected_date.get_untracked().unwrap_or(now_date())); comp_ref.load(PanelRef { show_date, variant: panel_variant, diff --git a/thaw/src/date_picker/panel/month_panel.rs b/thaw/src/date_picker/panel/month_panel.rs index 9b32170..ef35d69 100644 --- a/thaw/src/date_picker/panel/month_panel.rs +++ b/thaw/src/date_picker/panel/month_panel.rs @@ -1,5 +1,5 @@ use super::PanelVariant; -use crate::{Button, ButtonSize, ButtonAppearance}; +use crate::{Button, ButtonAppearance, ButtonSize}; use chrono::{Datelike, Month, Months, NaiveDate}; use leptos::*; @@ -8,7 +8,7 @@ pub fn MonthPanel( date_panel_show_date: RwSignal, panel_variant: RwSignal, ) -> impl IntoView { - let show_date = create_rw_signal(date_panel_show_date.get_untracked()); + let show_date = RwSignal::new(date_panel_show_date.get_untracked()); let previous_year = move |_| { show_date.update(|date| { *date = *date - Months::new(12); @@ -72,7 +72,7 @@ pub fn MonthPanel( #[component] fn MonthPanelItem(date_panel_show_date: RwSignal, month: Month) -> impl IntoView { - let is_selected = create_memo(move |_| { + let is_selected = Memo::new(move |_| { date_panel_show_date.with(|date| date.month() == month.number_from_month()) }); From 425bc43270707aaf46551ff059996deded78cd3a Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 25 Jun 2024 23:42:53 +0800 Subject: [PATCH 052/143] refactor: TimePicker --- demo/src/pages/components.rs | 8 ++--- thaw/src/date_picker/date-picker.css | 2 +- thaw/src/theme/mod.rs | 7 ++--- thaw/src/time_picker/mod.rs | 47 +++++++--------------------- thaw/src/time_picker/theme.rs | 26 --------------- thaw/src/time_picker/time-picker.css | 15 +++++---- 6 files changed, 25 insertions(+), 80 deletions(-) delete mode 100644 thaw/src/time_picker/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 4b2fb5c..2b0a374 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -207,6 +207,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/textarea".into(), label: "Textarea".into(), }, + MenuItemOption { + value: "/components/time-picker".into(), + label: "Time Picker".into(), + }, MenuItemOption { value: "/components/auto-complete".into(), label: "Auto Complete".into(), @@ -239,10 +243,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/switch".into(), label: "Switch".into(), }, - MenuItemOption { - value: "/components/time-picker".into(), - label: "Time Picker".into(), - }, MenuItemOption { value: "/components/upload".into(), label: "Upload".into(), diff --git a/thaw/src/date_picker/date-picker.css b/thaw/src/date_picker/date-picker.css index f3f6343..b79b952 100644 --- a/thaw/src/date_picker/date-picker.css +++ b/thaw/src/date_picker/date-picker.css @@ -1,4 +1,4 @@ -.thaw-date-picker-panel { +div.thaw-date-picker-panel { width: 300px; background-color: var(--colorNeutralBackground1); border-radius: var(--borderRadiusMedium); diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 052d21e..ae95a5c 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -4,8 +4,8 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, - ProgressTheme, ScrollbarTheme, SelectTheme, TimePickerTheme, UploadTheme, + AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, ProgressTheme, + ScrollbarTheme, SelectTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -28,7 +28,6 @@ pub struct Theme { pub tabbar: TabbarTheme, pub progress: ProgressTheme, pub calendar: CalendarTheme, - pub time_picker: TimePickerTheme, pub scrollbar: ScrollbarTheme, pub back_top: BackTopTheme, pub anchor: AnchorTheme, @@ -48,7 +47,6 @@ impl Theme { tabbar: TabbarTheme::light(), progress: ProgressTheme::light(), calendar: CalendarTheme::light(), - time_picker: TimePickerTheme::light(), scrollbar: ScrollbarTheme::light(), back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), @@ -67,7 +65,6 @@ impl Theme { tabbar: TabbarTheme::dark(), progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), - time_picker: TimePickerTheme::dark(), scrollbar: ScrollbarTheme::dark(), back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(), diff --git a/thaw/src/time_picker/mod.rs b/thaw/src/time_picker/mod.rs index 51009ff..6a1cbb8 100644 --- a/thaw/src/time_picker/mod.rs +++ b/thaw/src/time_picker/mod.rs @@ -1,10 +1,6 @@ -mod theme; - -pub use theme::TimePickerTheme; - use crate::{ - use_theme, Button, ButtonSize, ButtonAppearance, Icon, Input, InputSuffix, Scrollbar, - ScrollbarRef, SignalWatch, Theme, + Button, ButtonSize, ConfigInjection, Icon, Input, InputSuffix, Scrollbar, ScrollbarRef, + SignalWatch, }; use chrono::{Local, NaiveTime, Timelike}; use leptos::*; @@ -18,11 +14,11 @@ pub fn TimePicker( #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, ) -> impl IntoView { mount_style("time-picker", include_str!("./time-picker.css")); - let time_picker_ref = create_node_ref::(); + let time_picker_ref = NodeRef::::new(); let panel_ref = ComponentRef::::default(); - let is_show_panel = create_rw_signal(false); + let is_show_panel = RwSignal::new(false); let show_time_format = "%H:%M:%S"; - let show_time_text = create_rw_signal(String::new()); + let show_time_text = RwSignal::new(String::new()); let update_show_time_text = move || { value.with_untracked(move |time| { let text = time.as_ref().map_or(String::new(), |time| { @@ -32,7 +28,7 @@ pub fn TimePicker( }); }; update_show_time_text(); - let panel_selected_time = create_rw_signal(None::); + let panel_selected_time = RwSignal::new(None::); _ = panel_selected_time.watch(move |time| { let text = time.as_ref().map_or(String::new(), |time| { time.format(show_time_format).to_string() @@ -102,29 +98,7 @@ fn Panel( #[prop(into)] is_show_panel: MaybeSignal, comp_ref: ComponentRef, ) -> impl IntoView { - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-item-font-color: {};", - theme.common.color_primary - )); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.time_picker.panel_background_color - )); - css_vars.push_str(&format!( - "--thaw-item-background-color-hover: {};", - theme.time_picker.panel_time_item_background_color_hover - )); - css_vars.push_str(&format!( - "--thaw-item-border-color: {};", - theme.time_picker.panel_border_color - )); - }); - css_vars - }); + let config_provider = ConfigInjection::use_(); let now = Callback::new(move |_| { close_panel.call(Some(now_time())); }); @@ -132,7 +106,7 @@ fn Panel( close_panel.call(selected_time.get_untracked()); }); - let panel_ref = create_node_ref::(); + let panel_ref = NodeRef::::new(); #[cfg(any(feature = "csr", feature = "hydrate"))] { use leptos::wasm_bindgen::__rt::IntoJsResult; @@ -183,8 +157,9 @@ fn Panel( let:display >
    diff --git a/thaw/src/time_picker/theme.rs b/thaw/src/time_picker/theme.rs deleted file mode 100644 index 12cc7ac..0000000 --- a/thaw/src/time_picker/theme.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct TimePickerTheme { - pub panel_background_color: String, - pub panel_time_item_background_color_hover: String, - pub panel_border_color: String, -} - -impl ThemeMethod for TimePickerTheme { - fn light() -> Self { - Self { - panel_background_color: "#fff".into(), - panel_time_item_background_color_hover: "#f1f3f5".into(), - panel_border_color: "#e0e0e6".into(), - } - } - - fn dark() -> Self { - Self { - panel_background_color: "#48484e".into(), - panel_time_item_background_color_hover: "#ffffff1a".into(), - panel_border_color: "#ffffff3d".into(), - } - } -} diff --git a/thaw/src/time_picker/time-picker.css b/thaw/src/time_picker/time-picker.css index 696938f..8e51259 100644 --- a/thaw/src/time_picker/time-picker.css +++ b/thaw/src/time_picker/time-picker.css @@ -1,11 +1,10 @@ -.thaw-time-picker-panel { +div.thaw-time-picker-panel { width: 160px; height: 260px; - background-color: var(--thaw-background-color); - border-radius: 3px; + background-color: var(--colorNeutralBackground1); + border-radius: var(--borderRadiusMedium); box-sizing: border-box; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); + box-shadow: var(--shadow16); } .thaw-time-picker-panel__time { @@ -35,11 +34,11 @@ .thaw-time-picker-panel__time-item--slected, .thaw-time-picker-panel__time-item:hover { - background-color: var(--thaw-item-background-color-hover); + background-color: var(--colorNeutralBackground1Hover); } .thaw-time-picker-panel__time-item--slected { - color: var(--thaw-item-font-color); + color: var(--colorBrandForeground1); } .thaw-time-picker-panel__footer { @@ -48,7 +47,7 @@ height: 38px; justify-content: space-evenly; align-items: center; - border-top: 1px solid var(--thaw-item-border-color); + border-top: var(--strokeWidthThin) solid var(--colorNeutralStroke1); } .thaw-time-picker-panel.fade-in-scale-up-transition-leave-active { From 4bda29d741fcd976c42cf7798571b2d4c2f084d6 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 22:10:57 +0800 Subject: [PATCH 053/143] refactor: Upload --- thaw/src/theme/mod.rs | 5 +---- thaw/src/upload/mod.rs | 2 -- thaw/src/upload/theme.rs | 23 ----------------------- thaw/src/upload/upload-dragger.css | 6 +++--- thaw/src/upload/upload_dragger.rs | 21 ++------------------- 5 files changed, 6 insertions(+), 51 deletions(-) delete mode 100644 thaw/src/upload/theme.rs diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index ae95a5c..03578ed 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -5,7 +5,7 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, ProgressTheme, - ScrollbarTheme, SelectTheme, UploadTheme, + ScrollbarTheme, SelectTheme, }; pub use color::ColorTheme; use leptos::*; @@ -23,7 +23,6 @@ pub struct Theme { pub alert: AlertTheme, pub message: MessageTheme, pub select: SelectTheme, - pub upload: UploadTheme, pub nav_bar: NavBarTheme, pub tabbar: TabbarTheme, pub progress: ProgressTheme, @@ -42,7 +41,6 @@ impl Theme { alert: AlertTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - upload: UploadTheme::light(), nav_bar: NavBarTheme::light(), tabbar: TabbarTheme::light(), progress: ProgressTheme::light(), @@ -60,7 +58,6 @@ impl Theme { alert: AlertTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), - upload: UploadTheme::dark(), nav_bar: NavBarTheme::dark(), tabbar: TabbarTheme::dark(), progress: ProgressTheme::dark(), diff --git a/thaw/src/upload/mod.rs b/thaw/src/upload/mod.rs index cbeef28..90a3bba 100644 --- a/thaw/src/upload/mod.rs +++ b/thaw/src/upload/mod.rs @@ -1,7 +1,5 @@ -mod theme; mod upload_dragger; -pub use theme::UploadTheme; pub use upload_dragger::UploadDragger; pub use web_sys::FileList; diff --git a/thaw/src/upload/theme.rs b/thaw/src/upload/theme.rs deleted file mode 100644 index 17443eb..0000000 --- a/thaw/src/upload/theme.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct UploadTheme { - pub dragger_background_color: String, - pub dragger_border_color: String, -} - -impl ThemeMethod for UploadTheme { - fn light() -> Self { - Self { - dragger_background_color: "#fafafc".into(), - dragger_border_color: "#e0e0e6".into(), - } - } - - fn dark() -> Self { - Self { - dragger_background_color: "#ffffff0f".into(), - dragger_border_color: "#ffffff3d".into(), - } - } -} diff --git a/thaw/src/upload/upload-dragger.css b/thaw/src/upload/upload-dragger.css index bfb10a2..79c2d60 100644 --- a/thaw/src/upload/upload-dragger.css +++ b/thaw/src/upload/upload-dragger.css @@ -1,8 +1,8 @@ .thaw-upload-dragger { width: 100%; padding: 20px; - background-color: var(--thaw-background-color); - border: 1px dashed var(--thaw-border-color); + background-color: var(--colorNeutralBackground1Hover); + border: var(--strokeWidthThin) dashed var(--colorNeutralStroke1); border-radius: 3px; text-align: center; cursor: pointer; @@ -11,5 +11,5 @@ } .thaw-upload-dragger:hover, .thaw-upload--drag-over .thaw-upload-dragger { - border: 1px dashed var(--thaw-border-color-hover); + border: var(--strokeWidthThin) dashed var(--colorBrandForeground1); } diff --git a/thaw/src/upload/upload_dragger.rs b/thaw/src/upload/upload_dragger.rs index 2ec16ad..991b878 100644 --- a/thaw/src/upload/upload_dragger.rs +++ b/thaw/src/upload/upload_dragger.rs @@ -1,29 +1,12 @@ -use crate::{use_theme, Theme}; use leptos::*; use thaw_utils::mount_style; #[component] pub fn UploadDragger(children: Children) -> impl IntoView { mount_style("upload-dragger", include_str!("./upload-dragger.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.upload.dragger_background_color - )); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.upload.dragger_border_color - )); - let border_color_hover = theme.common.color_primary.clone(); - css_vars.push_str(&format!("--thaw-border-color-hover: {border_color_hover};")); - }); - css_vars - }); + view! { -
    +
    {children()}
    } From 75a926e6b23362cef5f0d2dba8eab11dd7b180b4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 22:12:28 +0800 Subject: [PATCH 054/143] pref: nav --- demo/src/pages/components.rs | 184 +++++++++++++++++------------------ thaw/src/menu/menu-group.css | 6 -- thaw/src/menu/menu-item.css | 22 ----- thaw/src/menu/menu_group.rs | 30 ------ thaw/src/menu/menu_item.rs | 53 ---------- thaw/src/menu/mod.rs | 30 ------ thaw/src/menu/theme.rs | 26 ----- 7 files changed, 92 insertions(+), 259 deletions(-) delete mode 100644 thaw/src/menu/menu-group.css delete mode 100644 thaw/src/menu/menu-item.css delete mode 100644 thaw/src/menu/menu_group.rs delete mode 100644 thaw/src/menu/menu_item.rs delete mode 100644 thaw/src/menu/mod.rs delete mode 100644 thaw/src/menu/theme.rs diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 2b0a374..a2b213d 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -139,10 +139,26 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/accordion".into(), label: "Accordion".into(), }, + MenuItemOption { + value: "/components/alert".into(), + label: "Alert".into(), + }, + MenuItemOption { + value: "/components/anchor".into(), + label: "Anchor".into(), + }, + MenuItemOption { + value: "/components/auto-complete".into(), + label: "Auto Complete".into(), + }, MenuItemOption { value: "/components/avatar".into(), label: "Avatar".into(), }, + MenuItemOption { + value: "/components/back-top".into(), + label: "Back Top".into(), + }, MenuItemOption { value: "/components/badge".into(), label: "Badge".into(), @@ -155,10 +171,22 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/button".into(), label: "Button".into(), }, + MenuItemOption { + value: "/components/calendar".into(), + label: "Calendar".into(), + }, MenuItemOption { value: "/components/card".into(), label: "Card".into(), }, + MenuItemOption { + value: "/components/checkbox".into(), + label: "Checkbox".into(), + }, + MenuItemOption { + value: "/components/color-picker".into(), + label: "Color Picker".into(), + }, MenuItemOption { value: "/components/config-provider".into(), label: "Config Provider".into(), @@ -171,14 +199,74 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/divider".into(), label: "Divider".into(), }, + MenuItemOption { + value: "/components/drawer".into(), + label: "Drawer".into(), + }, + MenuItemOption { + value: "/components/grid".into(), + label: "Grid".into(), + }, MenuItemOption { value: "/components/icon".into(), label: "Icon".into(), }, + MenuItemOption { + value: "/components/image".into(), + label: "Image".into(), + }, + MenuItemOption { + value: "/components/input".into(), + label: "Input".into(), + }, + MenuItemOption { + value: "/components/layout".into(), + label: "Layout".into(), + }, + MenuItemOption { + value: "/components/loading-bar".into(), + label: "Loading Bar".into(), + }, + MenuItemOption { + value: "/components/message".into(), + label: "Message".into(), + }, + MenuItemOption { + value: "/components/modal".into(), + label: "Modal".into(), + }, + MenuItemOption { + value: "/components/popover".into(), + label: "Popover".into(), + }, + MenuItemOption { + value: "/components/progress".into(), + label: "Progress".into(), + }, + MenuItemOption { + value: "/components/radio".into(), + label: "Radio".into(), + }, + MenuItemOption { + value: "/components/scrollbar".into(), + label: "Scrollbar".into(), + }, + MenuItemOption { + value: "/components/select".into(), + label: "Select".into(), + }, MenuItemOption { value: "/components/skeleton".into(), label: "Skeleton".into(), }, + MenuItemOption { + value: "/components/slider".into(), + label: "Slider".into(), + }, + MenuItemOption { + value: "/components/space".into(), + label: "Space".into(), + }, MenuItemOption { value: "/components/spin-button".into(), label: "Spin Button".into(), @@ -187,6 +275,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/spinner".into(), label: "Spinner".into(), }, + MenuItemOption { + value: "/components/switch".into(), + label: "Switch".into(), + }, MenuItemOption { value: "/components/tab-list".into(), label: "Tab List".into(), @@ -211,102 +303,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/time-picker".into(), label: "Time Picker".into(), }, - MenuItemOption { - value: "/components/auto-complete".into(), - label: "Auto Complete".into(), - }, - MenuItemOption { - value: "/components/color-picker".into(), - label: "Color Picker".into(), - }, - MenuItemOption { - value: "/components/checkbox".into(), - label: "Checkbox".into(), - }, - MenuItemOption { - value: "/components/input".into(), - label: "Input".into(), - }, - MenuItemOption { - value: "/components/radio".into(), - label: "Radio".into(), - }, - MenuItemOption { - value: "/components/select".into(), - label: "Select".into(), - }, - MenuItemOption { - value: "/components/slider".into(), - label: "Slider".into(), - }, - MenuItemOption { - value: "/components/switch".into(), - label: "Switch".into(), - }, MenuItemOption { value: "/components/upload".into(), label: "Upload".into(), }, - MenuItemOption { - value: "/components/calendar".into(), - label: "Calendar".into(), - }, - MenuItemOption { - value: "/components/image".into(), - label: "Image".into(), - }, - MenuItemOption { - value: "/components/anchor".into(), - label: "Anchor".into(), - }, - MenuItemOption { - value: "/components/back-top".into(), - label: "Back Top".into(), - }, - MenuItemOption { - value: "/components/loading-bar".into(), - label: "Loading Bar".into(), - }, - MenuItemOption { - value: "/components/alert".into(), - label: "Alert".into(), - }, - MenuItemOption { - value: "/components/drawer".into(), - label: "Drawer".into(), - }, - MenuItemOption { - value: "/components/message".into(), - label: "Message".into(), - }, - MenuItemOption { - value: "/components/modal".into(), - label: "Modal".into(), - }, - MenuItemOption { - value: "/components/popover".into(), - label: "Popover".into(), - }, - MenuItemOption { - value: "/components/progress".into(), - label: "Progress".into(), - }, - MenuItemOption { - value: "/components/layout".into(), - label: "Layout".into(), - }, - MenuItemOption { - value: "/components/grid".into(), - label: "Grid".into(), - }, - MenuItemOption { - value: "/components/space".into(), - label: "Space".into(), - }, - MenuItemOption { - value: "/components/scrollbar".into(), - label: "Scrollbar".into(), - }, ], }, MenuGroupOption { diff --git a/thaw/src/menu/menu-group.css b/thaw/src/menu/menu-group.css deleted file mode 100644 index 2825d93..0000000 --- a/thaw/src/menu/menu-group.css +++ /dev/null @@ -1,6 +0,0 @@ -.thaw-menu-group { - padding: 0.85rem 1.15em 0.1rem; - font-size: 0.86rem; - font-weight: bold; - color: var(--thaw-font-color); -} diff --git a/thaw/src/menu/menu-item.css b/thaw/src/menu/menu-item.css deleted file mode 100644 index 7a8772a..0000000 --- a/thaw/src/menu/menu-item.css +++ /dev/null @@ -1,22 +0,0 @@ -.thaw-menu-item__content { - margin: 0.3rem 0.4rem; - padding: 0.5rem 0.75rem; - color: var(--thaw-font-color); - cursor: pointer; - border-radius: 0.25rem; - font-size: 0.875rem; - line-height: 1.25rem; - - transition-property: color, background-color; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 0.15s; -} - -.thaw-menu-item__content:hover:not(.thaw-menu-item__content--selected) { - background-color: var(--thaw-background-color-hover); -} - -.thaw-menu-item__content--selected { - color: var(--thaw-font-color-active); - background-color: var(--thaw-background-color); -} diff --git a/thaw/src/menu/menu_group.rs b/thaw/src/menu/menu_group.rs deleted file mode 100644 index ab54667..0000000 --- a/thaw/src/menu/menu_group.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::{theme::use_theme, Theme}; -use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; - -#[component] -pub fn MenuGroup( - #[prop(into)] label: String, - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { - mount_style("menu-group", include_str!("./menu-group.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!("--thaw-font-color: {};", theme.menu.group_color)); - }); - css_vars - }); - - view! { -
    - {label} -
    - {children()} - } -} diff --git a/thaw/src/menu/menu_item.rs b/thaw/src/menu/menu_item.rs deleted file mode 100644 index f72fe16..0000000 --- a/thaw/src/menu/menu_item.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::use_menu; -use crate::{theme::use_theme, Theme}; -use leptos::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; - -#[component] -pub fn MenuItem( - #[prop(into)] key: MaybeSignal, - #[prop(into)] label: MaybeSignal, - #[prop(optional, into)] class: OptionalProp>, -) -> impl IntoView { - mount_style("menu-item", include_str!("./menu-item.css")); - let theme = use_theme(Theme::light); - let menu = use_menu(); - let click_key = key.clone(); - let on_click = move |_| { - let click_key = click_key.get(); - if menu.0.with(|key| key != &click_key) { - menu.0.set(click_key); - } - }; - - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let font_color = theme.common.color_primary.clone(); - css_vars.push_str(&format!("--thaw-font-color-active: {font_color};")); - css_vars.push_str(&format!("--thaw-font-color: {};", theme.menu.color)); - css_vars.push_str(&format!("--thaw-background-color: {font_color}1a;")); - css_vars.push_str(&format!( - "--thaw-background-color-hover: {};", - theme.menu.item_color_hover - )); - }); - css_vars - }); - - view! { -
    -
    - {move || label.get()} -
    -
    - } -} diff --git a/thaw/src/menu/mod.rs b/thaw/src/menu/mod.rs deleted file mode 100644 index 08598dc..0000000 --- a/thaw/src/menu/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -mod menu_group; -mod menu_item; -mod theme; - -pub use menu_group::MenuGroup; -pub use menu_item::*; -pub use theme::MenuTheme; - -use leptos::*; -use thaw_utils::{class_list, Model, OptionalProp}; - -#[component] -pub fn Menu( - #[prop(optional, into)] value: Model, - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { - view! { - -
    {children()}
    -
    - } -} - -#[derive(Clone)] -pub(crate) struct MenuInjection(pub Model); - -pub(crate) fn use_menu() -> MenuInjection { - expect_context() -} diff --git a/thaw/src/menu/theme.rs b/thaw/src/menu/theme.rs deleted file mode 100644 index 0305d69..0000000 --- a/thaw/src/menu/theme.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct MenuTheme { - pub color: String, - pub item_color_hover: String, - pub group_color: String, -} - -impl ThemeMethod for MenuTheme { - fn light() -> Self { - Self { - color: "#4b5263".into(), - item_color_hover: "#f3f5f6".into(), - group_color: "#111727".into(), - } - } - - fn dark() -> Self { - Self { - color: "#9ca5b0".into(), - item_color_hover: "#383f5233".into(), - group_color: "#ffffffe6".into(), - } - } -} From 137bb5263c8211da4d62d007882d486aed41e3b7 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 22:28:08 +0800 Subject: [PATCH 055/143] refactor: Loadingbar --- thaw/src/loading_bar/loading-bar.css | 2 +- thaw/src/loading_bar/mod.rs | 32 ++++++++-------------------- thaw/src/theme/color.rs | 9 ++++++++ 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/thaw/src/loading_bar/loading-bar.css b/thaw/src/loading_bar/loading-bar.css index 5049175..529178c 100644 --- a/thaw/src/loading_bar/loading-bar.css +++ b/thaw/src/loading_bar/loading-bar.css @@ -1,4 +1,4 @@ -.thaw-loading-bar-container { +div.thaw-loading-bar-container { position: fixed; top: 0; left: 0; diff --git a/thaw/src/loading_bar/mod.rs b/thaw/src/loading_bar/mod.rs index 3374185..a30d0a6 100644 --- a/thaw/src/loading_bar/mod.rs +++ b/thaw/src/loading_bar/mod.rs @@ -2,9 +2,9 @@ mod loading_bar_provider; pub use loading_bar_provider::{use_loading_bar, LoadingBarProvider}; -use crate::{use_theme, Theme}; use leptos::*; use thaw_utils::{mount_style, ComponentRef}; +use crate::ConfigInjection; #[derive(Clone)] pub(crate) struct LoadingBarRef { @@ -28,29 +28,15 @@ impl LoadingBarRef { #[component] pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef) -> impl IntoView { mount_style("loading-bar", include_str!("./loading-bar.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.common.color_success - )); - css_vars.push_str(&format!( - "--thaw-background-color-error: {};", - theme.common.color_error - )); - }); - css_vars - }); - let loading_bar_ref = create_node_ref::(); - let loading = create_rw_signal(false); + let config_provider = ConfigInjection::use_(); + let loading_bar_ref = NodeRef::::new(); + let loading = RwSignal::new(false); let start = Callback::new(move |_| { loading.set(true); if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() { let loading_bar_ref = loading_bar_ref - .style("background-color", "var(--thaw-background-color)") + .style("background-color", "var(--colorStatusSuccessForeground1)") .style("transition", "none") .style("max-width", "0"); _ = loading_bar_ref.offset_width(); @@ -69,7 +55,7 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef let finish = Callback::new(move |_| { if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() { _ = loading_bar_ref - .style("background-color", "var(--thaw-background-color)") + .style("background-color", "var(--colorStatusSuccessForeground1)") .style("transition", "max-width 0.5s linear") .style("max-width", "100%"); is_on_transitionend.set_value(true); @@ -86,7 +72,7 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef _ = loading_bar_ref.offset_width(); } _ = loading_bar_ref - .style("background-color", "var(--thaw-background-color-error)") + .style("background-color", "var(--colorStatusDangerForeground1)") .style("transition", "max-width 0.5s linear") .style("max-width", "100%"); is_on_transitionend.set_value(true); @@ -100,13 +86,13 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef }); view! {
    diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index b621229..7455eb8 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -87,6 +87,9 @@ pub struct ColorTheme { pub color_palette_dark_orange_foreground_3: String, pub color_palette_dark_orange_border_1: String, + pub color_status_success_foreground_1: String, + pub color_status_danger_foreground_1: String, + pub color_subtle_background: String, pub color_subtle_background_hover: String, pub color_subtle_background_pressed: String, @@ -188,6 +191,9 @@ impl ColorTheme { color_palette_dark_orange_foreground_3: "#da3b01".into(), color_palette_dark_orange_border_1: "#f4bfab".into(), + color_status_success_foreground_1: "#0e700e".into(), + color_status_danger_foreground_1: "#b10e1c".into(), + color_subtle_background: "transparent".into(), color_subtle_background_hover: "#f5f5f5".into(), color_subtle_background_pressed: "#e0e0e0".into(), @@ -289,6 +295,9 @@ impl ColorTheme { color_palette_dark_orange_foreground_3: "#e9835e".into(), color_palette_dark_orange_border_1: "#da3b01".into(), + color_status_success_foreground_1: "#54b054".into(), + color_status_danger_foreground_1: "#dc626d".into(), + color_subtle_background: "transparent".into(), color_subtle_background_hover: "#383838".into(), color_subtle_background_pressed: "#2e2e2e".into(), From 7c431f66b5159a302d16562e621f57e0e2a2e438 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 22:32:13 +0800 Subject: [PATCH 056/143] refactor: mobile component --- demo/src/app.rs | 12 +++---- demo/src/pages/components.rs | 34 +++++++++---------- demo/src/pages/mod.rs | 16 ++++----- demo_markdown/src/lib.rs | 6 ++-- thaw/src/lib.rs | 1 - thaw/src/theme/mod.rs | 8 +---- {thaw/src/mobile => thaw_mobile}/mod.rs | 0 .../src/mobile => thaw_mobile}/nav_bar/mod.rs | 0 .../nav_bar/nav-bar.css | 0 .../mobile => thaw_mobile}/nav_bar/theme.rs | 0 .../src/mobile => thaw_mobile}/tabbar/mod.rs | 0 .../tabbar/tabbar-item.css | 0 .../mobile => thaw_mobile}/tabbar/tabbar.css | 0 .../tabbar/tabbar_item.rs | 0 .../mobile => thaw_mobile}/tabbar/theme.rs | 0 {thaw/src/mobile => thaw_mobile}/toast/mod.rs | 0 .../mobile => thaw_mobile}/toast/toast.css | 0 17 files changed, 35 insertions(+), 42 deletions(-) rename {thaw/src/mobile => thaw_mobile}/mod.rs (100%) rename {thaw/src/mobile => thaw_mobile}/nav_bar/mod.rs (100%) rename {thaw/src/mobile => thaw_mobile}/nav_bar/nav-bar.css (100%) rename {thaw/src/mobile => thaw_mobile}/nav_bar/theme.rs (100%) rename {thaw/src/mobile => thaw_mobile}/tabbar/mod.rs (100%) rename {thaw/src/mobile => thaw_mobile}/tabbar/tabbar-item.css (100%) rename {thaw/src/mobile => thaw_mobile}/tabbar/tabbar.css (100%) rename {thaw/src/mobile => thaw_mobile}/tabbar/tabbar_item.rs (100%) rename {thaw/src/mobile => thaw_mobile}/tabbar/theme.rs (100%) rename {thaw/src/mobile => thaw_mobile}/toast/mod.rs (100%) rename {thaw/src/mobile => thaw_mobile}/toast/toast.css (100%) diff --git a/demo/src/app.rs b/demo/src/app.rs index 01c5978..8f72401 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -43,9 +43,9 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - - - + // + // + // @@ -90,9 +90,9 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - - - + // + // + // } } diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index a2b213d..d9b1f31 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -309,22 +309,22 @@ pub(crate) fn gen_menu_data() -> Vec { }, ], }, - MenuGroupOption { - label: "Mobile Components".into(), - children: vec![ - MenuItemOption { - value: "/components/nav-bar".into(), - label: "Nav Bar".into(), - }, - MenuItemOption { - value: "/components/tabbar".into(), - label: "Tabbar".into(), - }, - MenuItemOption { - value: "/components/toast".into(), - label: "Toast".into(), - }, - ], - }, + // MenuGroupOption { + // label: "Mobile Components".into(), + // children: vec![ + // MenuItemOption { + // value: "/components/nav-bar".into(), + // label: "Nav Bar".into(), + // }, + // MenuItemOption { + // value: "/components/tabbar".into(), + // label: "Tabbar".into(), + // }, + // MenuItemOption { + // value: "/components/toast".into(), + // label: "Toast".into(), + // }, + // ], + // }, ] } diff --git a/demo/src/pages/mod.rs b/demo/src/pages/mod.rs index b90761d..763083c 100644 --- a/demo/src/pages/mod.rs +++ b/demo/src/pages/mod.rs @@ -1,15 +1,15 @@ mod components; mod home; mod markdown; -mod mobile; -mod nav_bar; -mod tabbar; -mod toast; +// mod mobile; +// mod nav_bar; +// mod tabbar; +// mod toast; pub use components::*; pub use home::*; pub use markdown::*; -pub use mobile::*; -pub use nav_bar::*; -pub use tabbar::*; -pub use toast::*; +// pub use mobile::*; +// pub use nav_bar::*; +// pub use tabbar::*; +// pub use toast::*; diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 3a29e36..91867ef 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -25,9 +25,9 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "InstallationMdPage" => "../docs/_guide/installation.md", "ServerSiderRenderingMdPage" => "../docs/_guide/server_sider_rendering.md", "UsageMdPage" => "../docs/_guide/usage.md", - "NavBarMdPage" => "../docs/_mobile/nav_bar/mod.md", - "TabbarMdPage" => "../docs/_mobile/tabbar/mod.md", - "ToastMdPage" => "../docs/_mobile/toast/mod.md", + // "NavBarMdPage" => "../docs/_mobile/nav_bar/mod.md", + // "TabbarMdPage" => "../docs/_mobile/tabbar/mod.md", + // "ToastMdPage" => "../docs/_mobile/toast/mod.md", "AccordionMdPage" => "../docs/accordion/mod.md", "AlertMdPage" => "../docs/alert/mod.md", "AnchorMdPage" => "../docs/anchor/mod.md", diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 58e5204..909b259 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -23,7 +23,6 @@ mod input; mod layout; mod loading_bar; mod message; -pub mod mobile; mod modal; mod nav; mod popover; diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 03578ed..7b51c27 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -3,7 +3,6 @@ mod common; use self::common::CommonTheme; use crate::{ - mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme, }; @@ -23,8 +22,6 @@ pub struct Theme { pub alert: AlertTheme, pub message: MessageTheme, pub select: SelectTheme, - pub nav_bar: NavBarTheme, - pub tabbar: TabbarTheme, pub progress: ProgressTheme, pub calendar: CalendarTheme, pub scrollbar: ScrollbarTheme, @@ -41,8 +38,7 @@ impl Theme { alert: AlertTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - nav_bar: NavBarTheme::light(), - tabbar: TabbarTheme::light(), + progress: ProgressTheme::light(), calendar: CalendarTheme::light(), scrollbar: ScrollbarTheme::light(), @@ -58,8 +54,6 @@ impl Theme { alert: AlertTheme::dark(), message: MessageTheme::dark(), select: SelectTheme::dark(), - nav_bar: NavBarTheme::dark(), - tabbar: TabbarTheme::dark(), progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), scrollbar: ScrollbarTheme::dark(), diff --git a/thaw/src/mobile/mod.rs b/thaw_mobile/mod.rs similarity index 100% rename from thaw/src/mobile/mod.rs rename to thaw_mobile/mod.rs diff --git a/thaw/src/mobile/nav_bar/mod.rs b/thaw_mobile/nav_bar/mod.rs similarity index 100% rename from thaw/src/mobile/nav_bar/mod.rs rename to thaw_mobile/nav_bar/mod.rs diff --git a/thaw/src/mobile/nav_bar/nav-bar.css b/thaw_mobile/nav_bar/nav-bar.css similarity index 100% rename from thaw/src/mobile/nav_bar/nav-bar.css rename to thaw_mobile/nav_bar/nav-bar.css diff --git a/thaw/src/mobile/nav_bar/theme.rs b/thaw_mobile/nav_bar/theme.rs similarity index 100% rename from thaw/src/mobile/nav_bar/theme.rs rename to thaw_mobile/nav_bar/theme.rs diff --git a/thaw/src/mobile/tabbar/mod.rs b/thaw_mobile/tabbar/mod.rs similarity index 100% rename from thaw/src/mobile/tabbar/mod.rs rename to thaw_mobile/tabbar/mod.rs diff --git a/thaw/src/mobile/tabbar/tabbar-item.css b/thaw_mobile/tabbar/tabbar-item.css similarity index 100% rename from thaw/src/mobile/tabbar/tabbar-item.css rename to thaw_mobile/tabbar/tabbar-item.css diff --git a/thaw/src/mobile/tabbar/tabbar.css b/thaw_mobile/tabbar/tabbar.css similarity index 100% rename from thaw/src/mobile/tabbar/tabbar.css rename to thaw_mobile/tabbar/tabbar.css diff --git a/thaw/src/mobile/tabbar/tabbar_item.rs b/thaw_mobile/tabbar/tabbar_item.rs similarity index 100% rename from thaw/src/mobile/tabbar/tabbar_item.rs rename to thaw_mobile/tabbar/tabbar_item.rs diff --git a/thaw/src/mobile/tabbar/theme.rs b/thaw_mobile/tabbar/theme.rs similarity index 100% rename from thaw/src/mobile/tabbar/theme.rs rename to thaw_mobile/tabbar/theme.rs diff --git a/thaw/src/mobile/toast/mod.rs b/thaw_mobile/toast/mod.rs similarity index 100% rename from thaw/src/mobile/toast/mod.rs rename to thaw_mobile/toast/mod.rs diff --git a/thaw/src/mobile/toast/toast.css b/thaw_mobile/toast/toast.css similarity index 100% rename from thaw/src/mobile/toast/toast.css rename to thaw_mobile/toast/toast.css From acf0d855393e9d8fab1c80c9b31604186bb9a1f1 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 22:53:44 +0800 Subject: [PATCH 057/143] refactor: BackTop --- thaw/src/back_top/back-top.css | 19 ++++++++---------- thaw/src/back_top/mod.rs | 36 +++++++--------------------------- thaw/src/back_top/theme.rs | 21 -------------------- thaw/src/theme/mod.rs | 7 ++----- 4 files changed, 17 insertions(+), 66 deletions(-) delete mode 100644 thaw/src/back_top/theme.rs diff --git a/thaw/src/back_top/back-top.css b/thaw/src/back_top/back-top.css index 5bbc165..c7a950d 100644 --- a/thaw/src/back_top/back-top.css +++ b/thaw/src/back_top/back-top.css @@ -1,4 +1,4 @@ -.thaw-back-top { +div.thaw-back-top { position: fixed; cursor: pointer; display: flex; @@ -10,8 +10,8 @@ border-radius: 22px; height: 44px; min-width: 44px; - box-shadow: 0 2px 8px 0px rgba(0, 0, 0, 0.12); - background-color: var(--thaw-background-color); + box-shadow: var(--shadow4); + background-color: var(--colorNeutralBackground1); } .thaw-back-top.fade-in-scale-up-transition-leave-active { @@ -43,18 +43,15 @@ transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.thaw-back-top:hover { - box-shadow: 0 2px 12px 0px #0000002e; +.thaw-back-top:hover, +.thaw-back-top:active { + box-shadow: var(--shadow16); } .thaw-back-top:hover > svg { - color: var(--thaw-icon-color-hover); -} - -.thaw-back-top:active { - box-shadow: 0 2px 12px 0px #0000002e; + color: var(--colorBrandBackgroundHover); } .thaw-back-top:active svg { - color: var(--thaw-icon-color-active); + color: var(--colorBrandBackgroundPressed); } diff --git a/thaw/src/back_top/mod.rs b/thaw/src/back_top/mod.rs index 639b880..2da90a5 100644 --- a/thaw/src/back_top/mod.rs +++ b/thaw/src/back_top/mod.rs @@ -1,12 +1,9 @@ -mod theme; - -pub use theme::BackTopTheme; - -use crate::{use_theme, Icon, Theme}; +use crate::{ConfigInjection, Icon}; use leptos::{html::ToHtmlElement, *}; use thaw_components::{CSSTransition, Fallback, OptionComp, Teleport}; use thaw_utils::{ - add_event_listener, class_list, get_scroll_parent, mount_style, EventListenerHandle, OptionalProp, + add_event_listener, class_list, get_scroll_parent, mount_style, EventListenerHandle, + OptionalProp, }; #[component] @@ -18,27 +15,7 @@ pub fn BackTop( #[prop(optional)] children: Option, ) -> impl IntoView { mount_style("back-top", include_str!("./back-top.css")); - let theme = use_theme(Theme::light); - let style = Memo::new(move |_| { - let mut style = String::new(); - style.push_str(&format!("right: {}px;", right.get_untracked())); - style.push_str(&format!("bottom: {}px;", bottom.get_untracked())); - theme.with(|theme| { - style.push_str(&format!( - "--thaw-icon-color-hover: {};", - theme.common.color_primary_hover - )); - style.push_str(&format!( - "--thaw-icon-color-active: {};", - theme.common.color_primary_active - )); - style.push_str(&format!( - "--thaw-background-color: {};", - theme.back_top.background_color - )); - }); - style - }); + let config_provider = ConfigInjection::use_(); let placeholder_ref = NodeRef::::new(); let back_top_ref = NodeRef::::new(); let is_show_back_top = RwSignal::new(false); @@ -105,10 +82,11 @@ pub fn BackTop( let:display >
    diff --git a/thaw/src/back_top/theme.rs b/thaw/src/back_top/theme.rs deleted file mode 100644 index 10cec49..0000000 --- a/thaw/src/back_top/theme.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct BackTopTheme { - pub background_color: String, - -} - -impl ThemeMethod for BackTopTheme { - fn light() -> Self { - Self { - background_color: "#fff".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#48484e".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 7b51c27..23af080 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -3,8 +3,8 @@ mod common; use self::common::CommonTheme; use crate::{ - AlertTheme, AnchorTheme, BackTopTheme, CalendarTheme, MessageTheme, ProgressTheme, - ScrollbarTheme, SelectTheme, + AlertTheme, AnchorTheme, CalendarTheme, MessageTheme, ProgressTheme, ScrollbarTheme, + SelectTheme, }; pub use color::ColorTheme; use leptos::*; @@ -25,7 +25,6 @@ pub struct Theme { pub progress: ProgressTheme, pub calendar: CalendarTheme, pub scrollbar: ScrollbarTheme, - pub back_top: BackTopTheme, pub anchor: AnchorTheme, } @@ -42,7 +41,6 @@ impl Theme { progress: ProgressTheme::light(), calendar: CalendarTheme::light(), scrollbar: ScrollbarTheme::light(), - back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), } } @@ -57,7 +55,6 @@ impl Theme { progress: ProgressTheme::dark(), calendar: CalendarTheme::dark(), scrollbar: ScrollbarTheme::dark(), - back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(), } } From e52741cf20224802f12435c99719b1ed289979e3 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 26 Jun 2024 23:24:43 +0800 Subject: [PATCH 058/143] refactor: Calendar --- thaw/src/calendar/calendar.css | 13 +++---- thaw/src/calendar/mod.rs | 66 ++++++++++------------------------ thaw/src/calendar/theme.rs | 26 -------------- thaw/src/theme/mod.rs | 9 +---- 4 files changed, 26 insertions(+), 88 deletions(-) delete mode 100644 thaw/src/calendar/theme.rs diff --git a/thaw/src/calendar/calendar.css b/thaw/src/calendar/calendar.css index 62519dd..72fa068 100644 --- a/thaw/src/calendar/calendar.css +++ b/thaw/src/calendar/calendar.css @@ -23,7 +23,8 @@ grid-auto-rows: 1fr; border-top: 1px solid; border-left: 1px solid; - border-color: var(--thaw-border-color); + border-color: var(--colorNeutralStroke2); + border-radius: var(--borderRadiusMedium); } .thaw-calendar-item { @@ -31,16 +32,16 @@ padding: 8px 12px; border-right: 1px solid; border-bottom: 1px solid; - border-color: var(--thaw-border-color); + border-color: var(--colorNeutralStroke2); cursor: pointer; } .thaw-calendar-item:hover { - background-color: var(--thaw-background-color-hover); + background-color: var(--colorNeutralBackground1Hover); } .thaw-calendar-item--other-month { - color: var(--thaw-font-color-other-month); + color: var(--colorNeutralForegroundDisabled); } .thaw-calendar-item__header { @@ -53,7 +54,7 @@ justify-content: center; align-items: center; color: white; - background-color: var(--thaw-background-color-today); + background-color: var(--colorBrandBackground); border-radius: 50%; margin-left: -0.4em; margin-top: -0.3em; @@ -66,6 +67,6 @@ left: 0; right: 0; bottom: 0; - background-color: var(--thaw-background-color-today); + background-color: var(--colorBrandBackground); height: 3px; } diff --git a/thaw/src/calendar/mod.rs b/thaw/src/calendar/mod.rs index 98efb6f..795f951 100644 --- a/thaw/src/calendar/mod.rs +++ b/thaw/src/calendar/mod.rs @@ -1,8 +1,4 @@ -mod theme; - -pub use theme::CalendarTheme; - -use crate::{use_theme, Button, ButtonGroup, Theme}; +use crate::{Button, ButtonGroup}; use chrono::{Datelike, Days, Local, Month, Months, NaiveDate}; use leptos::*; use std::ops::Deref; @@ -14,31 +10,8 @@ pub fn Calendar( #[prop(optional, into)] value: Model>, ) -> impl IntoView { mount_style("calendar", include_str!("./calendar.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color-today: {};", - theme.common.color_primary - )); - css_vars.push_str(&format!( - "--thaw-font-color-other-month: {};", - theme.calendar.other_month_font_color, - )); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.calendar.border_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-hover: {};", - theme.calendar.background_color_hover - )); - }); - css_vars - }); - let show_date = create_rw_signal(value.get_untracked().unwrap_or(now_date())); - create_effect(move |_| { + let show_date = RwSignal::new(value.get_untracked().unwrap_or(now_date())); + Effect::new(move |_| { if let Some(selected_date) = value.get() { let show_date_data = show_date.get_untracked(); if selected_date.year() != show_date_data.year() @@ -49,7 +22,7 @@ pub fn Calendar( } }); - let dates = create_memo(move |_| { + let dates = Memo::new(move |_| { let show_date = show_date.get(); let show_date_month = show_date.month(); let mut dates = vec![]; @@ -115,7 +88,6 @@ pub fn Calendar( view! {
    @@ -132,21 +104,19 @@ pub fn Calendar( }} - - - - +
    @@ -172,7 +142,7 @@ fn CalendarItem( index: usize, date: CalendarItemDate, ) -> impl IntoView { - let is_selected = create_memo({ + let is_selected = Memo::new({ let date = date.clone(); move |_| value.with(|value_date| value_date.as_ref() == Some(date.deref())) }); diff --git a/thaw/src/calendar/theme.rs b/thaw/src/calendar/theme.rs deleted file mode 100644 index c5143ae..0000000 --- a/thaw/src/calendar/theme.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct CalendarTheme { - pub border_color: String, - pub other_month_font_color: String, - pub background_color_hover: String, -} - -impl ThemeMethod for CalendarTheme { - fn light() -> Self { - Self { - border_color: "#efeff5".into(), - other_month_font_color: "#c2c2c2".into(), - background_color_hover: "#f3f3f5".into(), - } - } - - fn dark() -> Self { - Self { - border_color: "#2d2d30".into(), - other_month_font_color: "#ffffff61".into(), - background_color_hover: "#2d2d30".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 23af080..387cce0 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -2,10 +2,7 @@ mod color; mod common; use self::common::CommonTheme; -use crate::{ - AlertTheme, AnchorTheme, CalendarTheme, MessageTheme, ProgressTheme, ScrollbarTheme, - SelectTheme, -}; +use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme}; pub use color::ColorTheme; use leptos::*; @@ -23,7 +20,6 @@ pub struct Theme { pub message: MessageTheme, pub select: SelectTheme, pub progress: ProgressTheme, - pub calendar: CalendarTheme, pub scrollbar: ScrollbarTheme, pub anchor: AnchorTheme, } @@ -37,9 +33,7 @@ impl Theme { alert: AlertTheme::light(), message: MessageTheme::light(), select: SelectTheme::light(), - progress: ProgressTheme::light(), - calendar: CalendarTheme::light(), scrollbar: ScrollbarTheme::light(), anchor: AnchorTheme::light(), } @@ -53,7 +47,6 @@ impl Theme { message: MessageTheme::dark(), select: SelectTheme::dark(), progress: ProgressTheme::dark(), - calendar: CalendarTheme::dark(), scrollbar: ScrollbarTheme::dark(), anchor: AnchorTheme::dark(), } From 25b54853950d29fb36a9c374e66a98e07fbd4a62 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 00:15:45 +0800 Subject: [PATCH 059/143] refactor: Scrollbar --- thaw/src/scrollbar/mod.rs | 24 +----------------------- thaw/src/scrollbar/scrollbar.css | 14 +++++++++++--- thaw/src/scrollbar/theme.rs | 23 ----------------------- thaw/src/theme/color.rs | 3 +++ thaw/src/theme/mod.rs | 5 +---- 5 files changed, 16 insertions(+), 53 deletions(-) delete mode 100644 thaw/src/scrollbar/theme.rs diff --git a/thaw/src/scrollbar/mod.rs b/thaw/src/scrollbar/mod.rs index d51c1b2..2fe1c9c 100644 --- a/thaw/src/scrollbar/mod.rs +++ b/thaw/src/scrollbar/mod.rs @@ -1,8 +1,3 @@ -mod theme; - -pub use theme::ScrollbarTheme; - -use crate::{use_theme, Theme}; use leptos::{leptos_dom::helpers::WindowListenerHandle, *}; use thaw_utils::{class_list, mount_style, ComponentRef, OptionalProp}; @@ -17,23 +12,6 @@ pub fn Scrollbar( children: Children, ) -> impl IntoView { mount_style("scrollbar", include_str!("./scrollbar.css")); - let theme = use_theme(Theme::light); - let css_vars = Memo::new(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-scrollbar-background-color: {};", - theme.scrollbar.background_color - )); - css_vars.push_str(&format!( - "--thaw-scrollbar-background-color-hover: {};", - theme.scrollbar.background_color_hover - )); - css_vars.push_str(&format!("--thaw-scrollbar-size: {}px;", size)); - }); - css_vars - }); - let container_ref = NodeRef::::new(); let content_ref = NodeRef::::new(); let x_track_ref = NodeRef::::new(); @@ -281,7 +259,7 @@ pub fn Scrollbar(
    Self { - Self { - background_color: "#00000040".into(), - background_color_hover: "#00000066".into(), - } - } - - fn dark() -> Self { - Self { - background_color: "#ffffff33".into(), - background_color_hover: "#ffffff4d".into(), - } - } -} diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index 7455eb8..49bfa9b 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -3,6 +3,7 @@ use thaw_macro::WriteCSSVars; #[derive(Clone, WriteCSSVars)] pub struct ColorTheme { pub color_neutral_background_static: String, + pub color_neutral_background_inverted: String, pub color_neutral_background_disabled: String, pub color_neutral_background_1: String, pub color_neutral_background_1_hover: String, @@ -106,6 +107,7 @@ impl ColorTheme { pub fn light() -> Self { Self { color_neutral_background_static: "#333333".into(), + color_neutral_background_inverted: "#292929".into(), color_neutral_background_disabled: "#f0f0f0".into(), color_neutral_background_1: "#ffffff".into(), color_neutral_background_1_hover: "#f5f5f5".into(), @@ -210,6 +212,7 @@ impl ColorTheme { pub fn dark() -> Self { Self { color_neutral_background_static: "#3d3d3d".into(), + color_neutral_background_inverted: "#ffffff".into(), color_neutral_background_disabled: "#141414".into(), color_neutral_background_1: "#292929".into(), color_neutral_background_1_hover: "#3d3d3d".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 387cce0..2e75a14 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -2,7 +2,7 @@ mod color; mod common; use self::common::CommonTheme; -use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme, ScrollbarTheme, SelectTheme}; +use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme, SelectTheme}; pub use color::ColorTheme; use leptos::*; @@ -20,7 +20,6 @@ pub struct Theme { pub message: MessageTheme, pub select: SelectTheme, pub progress: ProgressTheme, - pub scrollbar: ScrollbarTheme, pub anchor: AnchorTheme, } @@ -34,7 +33,6 @@ impl Theme { message: MessageTheme::light(), select: SelectTheme::light(), progress: ProgressTheme::light(), - scrollbar: ScrollbarTheme::light(), anchor: AnchorTheme::light(), } } @@ -47,7 +45,6 @@ impl Theme { message: MessageTheme::dark(), select: SelectTheme::dark(), progress: ProgressTheme::dark(), - scrollbar: ScrollbarTheme::dark(), anchor: AnchorTheme::dark(), } } From c7be3914410cd6287547e55bbaebd077e01222e4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 14:51:36 +0800 Subject: [PATCH 060/143] feat: adds Combobox component --- demo/src/app.rs | 1 + demo/src/pages/components.rs | 4 + demo_markdown/docs/combobox/mod.md | 33 +++++ demo_markdown/src/lib.rs | 1 + thaw/src/combobox/combobox.css | 192 +++++++++++++++++++++++++++ thaw/src/combobox/combobox.rs | 112 ++++++++++++++++ thaw/src/combobox/combobox_option.rs | 49 +++++++ thaw/src/combobox/mod.rs | 5 + thaw/src/lib.rs | 2 + 9 files changed, 399 insertions(+) create mode 100644 demo_markdown/docs/combobox/mod.md create mode 100644 thaw/src/combobox/combobox.css create mode 100644 thaw/src/combobox/combobox.rs create mode 100644 thaw/src/combobox/combobox_option.rs create mode 100644 thaw/src/combobox/mod.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 8f72401..9eb5d89 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -59,6 +59,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index d9b1f31..ed7c29d 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -187,6 +187,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/color-picker".into(), label: "Color Picker".into(), }, + MenuItemOption { + value: "/components/combobox".into(), + label: "Combobox".into(), + }, MenuItemOption { value: "/components/config-provider".into(), label: "Config Provider".into(), diff --git a/demo_markdown/docs/combobox/mod.md b/demo_markdown/docs/combobox/mod.md new file mode 100644 index 0000000..cef4145 --- /dev/null +++ b/demo_markdown/docs/combobox/mod.md @@ -0,0 +1,33 @@ +# Combobox + +```rust demo +let value = RwSignal::new(vec![]); + +view! { + + + "Cat" + + + "Dog" + + +} +``` + +### Multiselect + +```rust demo +let value = RwSignal::new(vec![]); + +view! { + + + "Cat" + + + "Dog" + + +} +``` diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 91867ef..5fb6821 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -41,6 +41,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "CardMdPage" => "../docs/card/mod.md", "CheckboxMdPage" => "../docs/checkbox/mod.md", "ColorPickerMdPage" => "../docs/color_picker/mod.md", + "ComboboxMdPage" => "../docs/combobox/mod.md", "ConfigProviderMdPage" => "../docs/config_provider/mod.md", "DatePickerMdPage" => "../docs/date_picker/mod.md", "DividerMdPage" => "../docs/divider/mod.md", diff --git a/thaw/src/combobox/combobox.css b/thaw/src/combobox/combobox.css new file mode 100644 index 0000000..5801cfe --- /dev/null +++ b/thaw/src/combobox/combobox.css @@ -0,0 +1,192 @@ +.thaw-combobox { + position: relative; + display: inline-grid; + justify-content: space-between; + align-items: center; + grid-template-columns: 1fr auto; + column-gap: var(--spacingHorizontalXXS); + min-width: 250px; + height: 32px; + padding-right: var(--spacingHorizontalMNudge); + background-color: var(--colorNeutralBackground1); + border-radius: var(--borderRadiusMedium); + border: var(--strokeWidthThin) solid var(--colorNeutralStroke1); + border-bottom-color: var(--colorNeutralStrokeAccessible); + box-sizing: border-box; +} + +.thaw-combobox:hover { + border-color: var(--colorNeutralStroke1Hover); + border-bottom-color: var(--colorNeutralStrokeAccessible); +} + +.thaw-combobox:active { + border-color: var(--colorNeutralStroke1Pressed); + border-bottom-color: var(--colorNeutralStrokeAccessible); +} + +.thaw-combobox:focus-within { + outline-color: transparent; + outline-style: solid; + outline-width: 2px; +} + +.thaw-combobox::after { + content: ""; + position: absolute; + bottom: -1px; + right: -1px; + left: -1px; + + height: max(2px, var(--borderRadiusMedium)); + border-bottom-left-radius: var(--borderRadiusMedium); + border-bottom-right-radius: var(--borderRadiusMedium); + border-bottom: var(--strokeWidthThick) solid var(--colorCompoundBrandStroke); + transition-delay: var(--curveAccelerateMid); + transition-duration: var(--durationUltraFast); + transition-property: transform; + transform: scaleX(0); + clip-path: inset(calc(100% - 2px) 0px 0px); + box-sizing: border-box; +} + +.thaw-combobox:focus-within::after { + transition-delay: var(--curveDecelerateMid); + transition-duration: var(--durationNormal); + transition-property: transform; + transform: scaleX(1); +} + +.thaw-combobox:focus-within:active::after { + border-bottom-color: var(--colorCompoundBrandStrokePressed); +} + +.thaw-combobox__input { + align-self: stretch; + background-color: var(--colorTransparentBackground); + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground1); + padding: 0 0 0 + calc(var(--spacingHorizontalMNudge) + var(--spacingHorizontalXXS)); + border: none; +} + +.thaw-combobox__input:focus { + outline-style: none; +} + +.thaw-combobox__expand-icon { + display: block; + margin-left: var(--spacingHorizontalXXS); + color: var(--colorNeutralStrokeAccessible); + box-sizing: border-box; + cursor: pointer; + font-size: 20px; +} + +.thaw-combobox__listbox { + row-gap: var(--spacingHorizontalXXS); + display: flex; + flex-direction: column; + min-width: 160px; + max-height: 80vh; + background-color: var(--colorNeutralBackground1); + padding: var(--spacingHorizontalXS); + outline: 1px solid var(--colorTransparentStroke); + border-radius: var(--borderRadiusMedium); + box-shadow: var(--shadow16); + box-sizing: border-box; + overflow-y: auto; +} + +.thaw-combobox__listbox.fade-in-scale-up-transition-leave-active { + transform-origin: inherit; + transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), + transform 0.2s cubic-bezier(0.4, 0, 1, 1); +} + +.thaw-combobox__listbox.fade-in-scale-up-transition-enter-active { + transform-origin: inherit; + transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), + transform 0.2s cubic-bezier(0, 0, 0.2, 1); +} + +.thaw-combobox__listbox.fade-in-scale-up-transition-enter-from, +.thaw-combobox__listbox.fade-in-scale-up-transition-leave-to { + opacity: 0; + transform: scale(0.9); +} + +.thaw-combobox__listbox.fade-in-scale-up-transition-leave-from, +.thaw-combobox__listbox.fade-in-scale-up-transition-enter-to { + opacity: 1; + transform: scale(1); +} + +.thaw-combobox-option { + column-gap: var(--spacingHorizontalXS); + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: var(--spacingVerticalSNudge) var(--spacingHorizontalS); + line-height: var(--lineHeightBase300); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + color: var(--colorNeutralForeground1); + border-radius: var(--borderRadiusMedium); +} + +.thaw-combobox-option:hover { + color: var(--colorNeutralForeground1Hover); + background-color: var(--colorNeutralBackground1Hover); +} + +.thaw-combobox-option:active { + color: var(--colorNeutralForeground1Pressed); + background-color: var(--colorNeutralBackground1Pressed); +} + +.thaw-combobox-option__check-icon { + visibility: hidden; + + margin-left: calc(var(--spacingHorizontalXXS) * -1); + margin-right: var(--spacingHorizontalXXS); + font-size: var(--fontSizeBase400); +} + +.thaw-combobox-option--selected > .thaw-combobox-option__check-icon { + visibility: visible; +} + +.thaw-combobox-option__check-icon--multiselect > svg, +.thaw-combobox-option__check-icon > svg { + display: block; + line-height: 0; +} + +.thaw-combobox-option__check-icon--multiselect { + display: flex; + align-items: center; + justify-content: center; + visibility: visible; + margin-left: calc(var(--spacingHorizontalXXS) * -1); + margin-right: var(--spacingHorizontalXXS); + width: 16px; + height: 16px; + font-size: 12px; + border-radius: var(--borderRadiusSmall); + border: var(--strokeWidthThin) solid var(--colorNeutralStrokeAccessible); + box-sizing: border-box; + fill: currentcolor; +} + +.thaw-combobox-option--selected + > .thaw-combobox-option__check-icon--multiselect { + border-color: var(--colorCompoundBrandBackground); + color: var(--colorNeutralForegroundInverted); + background-color: var(--colorCompoundBrandBackground); +} diff --git a/thaw/src/combobox/combobox.rs b/thaw/src/combobox/combobox.rs new file mode 100644 index 0000000..e8fc16b --- /dev/null +++ b/thaw/src/combobox/combobox.rs @@ -0,0 +1,112 @@ +use crate::ConfigInjection; +use leptos::*; +use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth}; +use thaw_utils::{mount_style, Model}; + +#[component] +pub fn Combobox( + #[prop(optional, into)] value: Model>, + #[prop(optional)] multiselect: bool, + children: Children, +) -> impl IntoView { + mount_style("combobox", include_str!("./combobox.css")); + let config_provider = ConfigInjection::use_(); + let trigger_ref = NodeRef::::new(); + let listbox_ref = NodeRef::::new(); + let is_show_listbox = RwSignal::new(false); + + view! { + +
    + + + + +
    + + + +
    + {children()} +
    +
    +
    +
    +
    + } +} + +#[derive(Clone, Copy)] +pub(crate) struct ComboboxInjection { + value: Model>, + pub multiselect: bool, +} + +impl ComboboxInjection { + pub fn use_() -> Self { + expect_context() + } + + pub fn is_selected(&self, key: &String) -> bool { + self.value.with(|value| value.contains(key)) + } + + pub fn on_option_select(&self, key: &String) { + self.value.update(|value| { + if self.multiselect { + if let Some(index) = value.iter().position(|k| k == key) { + value.remove(index); + return; + } + } else { + value.clear(); + } + value.push(key.clone()); + }); + } +} diff --git a/thaw/src/combobox/combobox_option.rs b/thaw/src/combobox/combobox_option.rs new file mode 100644 index 0000000..e9cab83 --- /dev/null +++ b/thaw/src/combobox/combobox_option.rs @@ -0,0 +1,49 @@ +use crate::ComboboxInjection; +use leptos::*; +use thaw_components::{If, Then}; +use thaw_utils::class_list; + +#[component] +pub fn ComboboxOption(#[prop(into)] key: String, children: Children) -> impl IntoView { + let combobox = ComboboxInjection::use_(); + let key = StoredValue::new(key); + + view! { +
    + { + if combobox.multiselect { + view! { + + } + } else { + view! { + + } + } + } + {children()} +
    + } +} diff --git a/thaw/src/combobox/mod.rs b/thaw/src/combobox/mod.rs new file mode 100644 index 0000000..c66c24d --- /dev/null +++ b/thaw/src/combobox/mod.rs @@ -0,0 +1,5 @@ +mod combobox; +mod combobox_option; + +pub use combobox::*; +pub use combobox_option::*; diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 909b259..0125ccf 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -12,6 +12,7 @@ mod card; mod checkbox; mod code; mod color_picker; +mod combobox; mod config_provider; mod date_picker; mod divider; @@ -59,6 +60,7 @@ pub use card::*; pub use checkbox::*; pub use code::*; pub use color_picker::*; +pub use combobox::*; pub use config_provider::*; pub use date_picker::*; pub use divider::*; From f6d534220ecbefb084690c4468e62c520653bf36 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 17:31:52 +0800 Subject: [PATCH 061/143] feat: Combobox adds clearable prop --- demo_markdown/docs/combobox/mod.md | 17 ++++++ thaw/src/combobox/combobox.css | 4 +- thaw/src/combobox/combobox.rs | 88 +++++++++++++++++++++++++++--- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/demo_markdown/docs/combobox/mod.md b/demo_markdown/docs/combobox/mod.md index cef4145..1578530 100644 --- a/demo_markdown/docs/combobox/mod.md +++ b/demo_markdown/docs/combobox/mod.md @@ -15,6 +15,23 @@ view! { } ``` +### Clearable + +```rust demo +let value = RwSignal::new(vec![]); + +view! { + + + "Cat" + + + "Dog" + + +} +``` + ### Multiselect ```rust demo diff --git a/thaw/src/combobox/combobox.css b/thaw/src/combobox/combobox.css index 5801cfe..3fd11e9 100644 --- a/thaw/src/combobox/combobox.css +++ b/thaw/src/combobox/combobox.css @@ -78,6 +78,7 @@ outline-style: none; } +.thaw-combobox__clear-icon, .thaw-combobox__expand-icon { display: block; margin-left: var(--spacingHorizontalXXS); @@ -152,7 +153,6 @@ .thaw-combobox-option__check-icon { visibility: hidden; - margin-left: calc(var(--spacingHorizontalXXS) * -1); margin-right: var(--spacingHorizontalXXS); font-size: var(--fontSizeBase400); @@ -162,6 +162,8 @@ visibility: visible; } +.thaw-combobox__clear-icon > svg, +.thaw-combobox__expand-icon > svg, .thaw-combobox-option__check-icon--multiselect > svg, .thaw-combobox-option__check-icon > svg { display: block; diff --git a/thaw/src/combobox/combobox.rs b/thaw/src/combobox/combobox.rs index e8fc16b..75151e3 100644 --- a/thaw/src/combobox/combobox.rs +++ b/thaw/src/combobox/combobox.rs @@ -1,12 +1,13 @@ use crate::ConfigInjection; use leptos::*; use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth}; -use thaw_utils::{mount_style, Model}; +use thaw_utils::{add_event_listener, mount_style, Model}; #[component] pub fn Combobox( #[prop(optional, into)] value: Model>, #[prop(optional)] multiselect: bool, + #[prop(optional)] clearable: bool, children: Children, ) -> impl IntoView { mount_style("combobox", include_str!("./combobox.css")); @@ -15,13 +16,63 @@ pub fn Combobox( let listbox_ref = NodeRef::::new(); let is_show_listbox = RwSignal::new(false); + let clear_icon_ref = NodeRef::::new(); + let is_show_clear_icon = Memo::new(move |_| { + if clearable { + value.with(|value| !value.is_empty()) + } else { + false + } + }); + if clearable { + clear_icon_ref.on_load(move |clear_icon_el| { + let handler = add_event_listener(clear_icon_el.into_any(), ev::click, move |e| { + e.stop_propagation(); + value.set(vec![]); + }); + on_cleanup(move || handler.remove()); + }); + } + + #[cfg(any(feature = "csr", feature = "hydrate"))] + { + let handle = window_event_listener(ev::click, move |ev| { + use leptos::wasm_bindgen::__rt::IntoJsResult; + if !is_show_listbox.get_untracked() { + return; + } + let el = ev.target(); + let mut el: Option = + el.into_js_result().map_or(None, |el| Some(el.into())); + let body = document().body().unwrap(); + if let Some(listbox_el) = listbox_ref.get_untracked() { + if let Some(trigger_el) = trigger_ref.get_untracked() { + while let Some(current_el) = el { + if current_el == *body { + break; + }; + if current_el == ***listbox_el { + return; + } + if current_el == ***trigger_el { + return; + } + el = current_el.parent_element(); + } + } + } + is_show_listbox.set(false); + }); + on_cleanup(move || handle.remove()); + } + view! {
    + { + if clearable { + view! { + + }.into() + } else { + None + } + }
    - {(select_label.children)()} - {select_icon.children} -
    - - -
    - - {item.get_value().label} -
    - } - } - /> -
    - - -
    - } -} diff --git a/thaw/src/select/select.css b/thaw/src/select/select.css deleted file mode 100644 index 3dc6dbf..0000000 --- a/thaw/src/select/select.css +++ /dev/null @@ -1,99 +0,0 @@ -.thaw-select { - position: relative; - display: flex; - align-items: center; - flex-wrap: wrap; - padding: 0 30px 0 10px; - min-height: 34px; - background-color: var(--thaw-background-color); - font-size: 14px; - color: var(--thaw-font-color); - border: 1px solid var(--thaw-border-color); - border-radius: 3px; - transition: all 0.3s; - cursor: pointer; - box-sizing: border-box; -} - -.thaw-select.thaw-select--multiple { - padding: 3px 30px 0 3px; -} - -.thaw-select-dropdown-icon { - position: absolute; - right: 10px; - top: 50%; - transform: translateY(-50%); - font-size: 12px; - opacity: 40%; - pointer-events: none; -} - -.thaw-select-dropdown-icon--clear { - pointer-events: auto; -} - -.thaw-select.thaw-select--multiple .thaw-tag { - height: 24px; - margin: 0 3px 3px 0; -} - -.thaw-select:hover { - border-color: var(--thaw-border-color-hover); -} - -.thaw-select-menu { - font-size: 14px; - color: var(--thaw-font-color); - background-color: var(--thaw-background-color); - box-sizing: border-box; - padding: 5px; - width: 100%; - max-height: 200px; - border-radius: 3px; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); - overflow: auto; -} - -.thaw-select-menu__item { - padding: 6px 5px; - border-radius: 2px; - cursor: pointer; -} - -.thaw-select-menu__item:hover { - background-color: var(--thaw-background-color-hover); -} - -.thaw-select-menu__item-selected { - color: var(--thaw-font-color-selected); -} - -.thaw-select-menu.fade-in-scale-up-transition-leave-active { - transform-origin: inherit; - transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), - transform 0.2s cubic-bezier(0.4, 0, 1, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-select-menu.fade-in-scale-up-transition-enter-active { - transform-origin: inherit; - transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), - transform 0.2s cubic-bezier(0, 0, 0.2, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-select-menu.fade-in-scale-up-transition-enter-from, -.thaw-select-menu.fade-in-scale-up-transition-leave-to { - opacity: 0; - transform: scale(0.9); -} - -.thaw-select-menu.fade-in-scale-up-transition-leave-from, -.thaw-select-menu.fade-in-scale-up-transition-enter-to { - opacity: 1; - transform: scale(1); -} diff --git a/thaw/src/select/theme.rs b/thaw/src/select/theme.rs deleted file mode 100644 index 3e46f19..0000000 --- a/thaw/src/select/theme.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SelectTheme { - pub font_color: String, - pub border_color: String, - pub background_color: String, - pub menu_background_color: String, - pub menu_background_color_hover: String, -} - -impl ThemeMethod for SelectTheme { - fn light() -> Self { - Self { - font_color: "#333639".into(), - border_color: "#e0e0e6".into(), - background_color: "#fff".into(), - menu_background_color: "#fff".into(), - menu_background_color_hover: "#f3f5f6".into(), - } - } - - fn dark() -> Self { - Self { - font_color: "#ffffffd1".into(), - border_color: "#0000".into(), - background_color: "#ffffff1a".into(), - menu_background_color: "#48484e".into(), - menu_background_color_hover: "#ffffff17".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 2e75a14..5270a75 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -2,7 +2,7 @@ mod color; mod common; use self::common::CommonTheme; -use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme, SelectTheme}; +use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme}; pub use color::ColorTheme; use leptos::*; @@ -18,7 +18,6 @@ pub struct Theme { pub color: ColorTheme, pub alert: AlertTheme, pub message: MessageTheme, - pub select: SelectTheme, pub progress: ProgressTheme, pub anchor: AnchorTheme, } @@ -31,7 +30,6 @@ impl Theme { color: ColorTheme::light(), alert: AlertTheme::light(), message: MessageTheme::light(), - select: SelectTheme::light(), progress: ProgressTheme::light(), anchor: AnchorTheme::light(), } @@ -43,7 +41,6 @@ impl Theme { color: ColorTheme::dark(), alert: AlertTheme::dark(), message: MessageTheme::dark(), - select: SelectTheme::dark(), progress: ProgressTheme::dark(), anchor: AnchorTheme::dark(), } From 348cc76c80f4b9e3be5e0b98d49529815f80fd2f Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 22:28:10 +0800 Subject: [PATCH 063/143] feat: adds MessageBar component --- demo/src/app.rs | 8 +- demo/src/components/switch_version.rs | 18 ++-- demo/src/pages/components.rs | 12 +-- demo_markdown/docs/alert/mod.md | 26 ------ demo_markdown/docs/loading_bar/mod.md | 11 ++- demo_markdown/docs/message/mod.md | 11 ++- demo_markdown/docs/message_bar/mod.md | 67 ++++++++++++++ demo_markdown/src/lib.rs | 5 +- thaw/src/alert/alert.css | 27 ------ thaw/src/alert/mod.rs | 96 --------------------- thaw/src/alert/theme.rs | 35 -------- thaw/src/lib.rs | 6 +- thaw/src/message/mod.rs | 12 +-- thaw/src/message_bar/message-bar.css | 94 ++++++++++++++++++++ thaw/src/message_bar/message_bar.rs | 91 +++++++++++++++++++ thaw/src/message_bar/message_bar_actions.rs | 21 +++++ thaw/src/message_bar/message_bar_body.rs | 10 +++ thaw/src/message_bar/message_bar_title.rs | 10 +++ thaw/src/message_bar/mod.rs | 9 ++ thaw/src/theme/color.rs | 21 +++++ thaw/src/theme/mod.rs | 8 +- 21 files changed, 374 insertions(+), 224 deletions(-) delete mode 100644 demo_markdown/docs/alert/mod.md create mode 100644 demo_markdown/docs/message_bar/mod.md delete mode 100644 thaw/src/alert/alert.css delete mode 100644 thaw/src/alert/mod.rs delete mode 100644 thaw/src/alert/theme.rs create mode 100644 thaw/src/message_bar/message-bar.css create mode 100644 thaw/src/message_bar/message_bar.rs create mode 100644 thaw/src/message_bar/message_bar_actions.rs create mode 100644 thaw/src/message_bar/message_bar_body.rs create mode 100644 thaw/src/message_bar/message_bar_title.rs create mode 100644 thaw/src/message_bar/mod.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index d9bcb0b..41e9816 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -47,7 +47,6 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { // // - @@ -70,7 +69,8 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - + // + @@ -118,9 +118,9 @@ fn TheProvider(children: Children) -> impl IntoView { view! { - + // {children()} - + // } diff --git a/demo/src/components/switch_version.rs b/demo/src/components/switch_version.rs index 2c36d21..3a14f54 100644 --- a/demo/src/components/switch_version.rs +++ b/demo/src/components/switch_version.rs @@ -4,10 +4,10 @@ use thaw::*; #[component] pub fn SwitchVersion() -> impl IntoView { let options = vec![ - SelectOption::new("main", "https://thawui.vercel.app".into()), - SelectOption::new("0.3.0", "https://thaw-gxcwse9r5-thaw.vercel.app".into()), - SelectOption::new("0.2.6", "https://thaw-mzh1656cm-thaw.vercel.app".into()), - SelectOption::new("0.2.5", "https://thaw-8og1kv8zs-thaw.vercel.app".into()), + ("main", "https://thawui.vercel.app"), + ("0.3.0", "https://thaw-gxcwse9r5-thaw.vercel.app"), + ("0.2.6", "https://thaw-mzh1656cm-thaw.vercel.app"), + ("0.2.5", "https://thaw-8og1kv8zs-thaw.vercel.app"), ]; cfg_if::cfg_if! { @@ -28,6 +28,14 @@ pub fn SwitchVersion() -> impl IntoView { } view! { - +
    - - - {if let Some(auto_complete_prefix) = auto_complete_prefix { - Some((auto_complete_prefix.children)()) - } else { - None - }} - - - - - {if let Some(auto_complete_suffix) = auto_complete_suffix { - Some((auto_complete_suffix.children)()) - } else { - None - }} - - - -
    - - - -
    + + {if let Some(auto_complete_prefix) = auto_complete_prefix { + Some((auto_complete_prefix.children)()) + } else { + None + }} + + + + + {if let Some(auto_complete_suffix) = auto_complete_suffix { + Some((auto_complete_suffix.children)()) + } else { + None + }} + + + +
    + + + +
    - // {move || { - // options - // .get() - // .into_iter() - // .enumerate() - // .map(|(index, v)| { - // let AutoCompleteOption { value: option_value, label } = v; - // let menu_item_ref = create_node_ref::(); - // let on_click = move |_| { - // select_value(option_value.clone()); - // }; - // let on_mouseenter = move |_| { - // select_option_index.set(Some(index)); - // }; - // let on_mousedown = move |ev: ev::MouseEvent| { - // ev.prevent_default(); - // }; - // create_effect(move |_| { - // if Some(index) == select_option_index.get() { - // if !is_show_menu.get() { - // return; - // } - // if let Some(menu_item_ref) = menu_item_ref.get() { - // let menu_ref = menu_ref.get().unwrap(); - // let menu_rect = menu_ref.get_bounding_client_rect(); - // let item_rect = menu_item_ref.get_bounding_client_rect(); - // if item_rect.y() < menu_rect.y() { - // menu_item_ref.scroll_into_view_with_bool(true); - // } else if item_rect.y() + item_rect.height() - // > menu_rect.y() + menu_rect.height() - // { - // menu_item_ref.scroll_into_view_with_bool(false); - // } - // } - // } - // }); - // view! { - //
    - // {label} - //
    - // } - // }) - // .collect_view() - // }} - - {children()} - -
    -
    -
    -
    - - } + + {children()} + +
    + + + + + } } -#[derive(Clone)] -pub(crate) struct AutoCompleteInjection(pub Model); +#[derive(Clone, Copy)] +pub(crate) struct AutoCompleteInjection(pub Model, pub Callback); impl AutoCompleteInjection { pub fn use_() -> Self { @@ -282,6 +219,10 @@ impl AutoCompleteInjection { pub fn is_selected(&self, key: &String) -> bool { self.0.with(|value| value == key) } + + pub fn select_value(&self, key: String) { + self.1.call(key.clone()); + } } #[derive(Clone)] diff --git a/thaw/src/avatar/mod.rs b/thaw/src/avatar/mod.rs index ccb33ca..147b7cf 100644 --- a/thaw/src/avatar/mod.rs +++ b/thaw/src/avatar/mod.rs @@ -17,7 +17,8 @@ pub fn Avatar( #[prop(optional, into)] shape: MaybeSignal, /// Size of the avatar in pixels. - #[prop(optional, into)] size: Option>, + #[prop(optional, into)] + size: Option>, #[prop(optional, into)] class: OptionalProp>, ) -> impl IntoView { mount_style("avatar", include_str!("./avatar.css")); diff --git a/thaw/src/badge/mod.rs b/thaw/src/badge/mod.rs index 130902d..9fdfb39 100644 --- a/thaw/src/badge/mod.rs +++ b/thaw/src/badge/mod.rs @@ -1,3 +1,3 @@ mod badge; -pub use badge::*; \ No newline at end of file +pub use badge::*; diff --git a/thaw/src/checkbox/checkbox_group.rs b/thaw/src/checkbox/checkbox_group.rs index e701b9b..533b8c9 100644 --- a/thaw/src/checkbox/checkbox_group.rs +++ b/thaw/src/checkbox/checkbox_group.rs @@ -7,7 +7,7 @@ pub fn CheckboxGroup( #[prop(optional, into)] value: Model>, children: Children, ) -> impl IntoView { - view! { + view! {
    {children()} diff --git a/thaw/src/date_picker/panel/year_panel.rs b/thaw/src/date_picker/panel/year_panel.rs index 9e3fd81..18de06a 100644 --- a/thaw/src/date_picker/panel/year_panel.rs +++ b/thaw/src/date_picker/panel/year_panel.rs @@ -1,5 +1,5 @@ use super::PanelVariant; -use crate::{Button, ButtonSize, ButtonAppearance}; +use crate::{Button, ButtonAppearance, ButtonSize}; use chrono::{Datelike, NaiveDate}; use leptos::*; diff --git a/thaw/src/loading_bar/mod.rs b/thaw/src/loading_bar/mod.rs index a30d0a6..8259ff9 100644 --- a/thaw/src/loading_bar/mod.rs +++ b/thaw/src/loading_bar/mod.rs @@ -2,9 +2,9 @@ mod loading_bar_provider; pub use loading_bar_provider::{use_loading_bar, LoadingBarProvider}; +use crate::ConfigInjection; use leptos::*; use thaw_utils::{mount_style, ComponentRef}; -use crate::ConfigInjection; #[derive(Clone)] pub(crate) struct LoadingBarRef { diff --git a/thaw/src/nav/mod.rs b/thaw/src/nav/mod.rs index 33174e4..ae2500d 100644 --- a/thaw/src/nav/mod.rs +++ b/thaw/src/nav/mod.rs @@ -2,4 +2,4 @@ mod nav_drawer; mod nav_item; pub use nav_drawer::*; -pub use nav_item::*; \ No newline at end of file +pub use nav_item::*; diff --git a/thaw/src/nav/nav_drawer.rs b/thaw/src/nav/nav_drawer.rs index e82b06c..f589795 100644 --- a/thaw/src/nav/nav_drawer.rs +++ b/thaw/src/nav/nav_drawer.rs @@ -1,7 +1,7 @@ +use crate::Scrollbar; use leptos::*; use thaw_components::OptionComp; use thaw_utils::{mount_style, Model}; -use crate::Scrollbar; #[component] pub fn NavDrawer( diff --git a/thaw/src/nav/nav_item.rs b/thaw/src/nav/nav_item.rs index 4d221d7..968066b 100644 --- a/thaw/src/nav/nav_item.rs +++ b/thaw/src/nav/nav_item.rs @@ -1,5 +1,5 @@ -use leptos::*; use crate::use_nav_drawer; +use leptos::*; use thaw_utils::{class_list, StoredMaybeSignal}; #[component] diff --git a/thaw/src/textarea/mod.rs b/thaw/src/textarea/mod.rs index d114405..732f535 100644 --- a/thaw/src/textarea/mod.rs +++ b/thaw/src/textarea/mod.rs @@ -10,7 +10,8 @@ pub fn Textarea( #[prop(optional, into)] on_blur: Option>, #[prop(optional, into)] disabled: MaybeSignal, /// Which direction the Textarea is allowed to be resized. - #[prop(optional, into)] resize: MaybeSignal, + #[prop(optional, into)] + resize: MaybeSignal, #[prop(optional)] comp_ref: ComponentRef, #[prop(optional, into)] class: MaybeProp, #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>, diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index c9078e7..f34b108 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -197,7 +197,7 @@ impl ColorTheme { color_palette_yellow_foreground_1: "#817400".into(), color_palette_yellow_foreground_2: "#817400".into(), color_palette_yellow_border_1: "#fef7b2".into(), - + color_palette_dark_orange_background_1: "#fdf6f3".into(), color_palette_dark_orange_background_3: "#da3b01".into(), color_palette_dark_orange_foreground_1: "#c43501".into(), diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 2ec011b..3d8216f 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -40,3 +40,13 @@ impl Theme { expect_context::().theme } } + +impl From for Theme { + fn from(value: String) -> Self { + if value == "dark" { + Theme::dark() + } else { + Theme::light() + } + } +} From 82e6f680183cd6f834b755f464da15c30f42bc7e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 2 Jul 2024 17:20:58 +0800 Subject: [PATCH 072/143] feat: adds Toast component --- demo/src/app.rs | 1 + demo/src/pages/components.rs | 4 +++ demo_markdown/docs/toast/mod.md | 9 +++++++ demo_markdown/src/lib.rs | 1 + thaw/src/lib.rs | 2 ++ thaw/src/toast/mod.rs | 7 ++++++ thaw/src/toast/toast.rs | 8 ++++++ thaw/src/toast/toast_body.rs | 20 +++++++++++++++ thaw/src/toast/toast_footer.rs | 6 +++++ thaw/src/toast/toast_title.rs | 31 ++++++++++++++++++++++++ thaw/src/toast/toaster.css | 43 +++++++++++++++++++++++++++++++++ thaw/src/toast/toaster.rs | 10 ++++++++ 12 files changed, 142 insertions(+) create mode 100644 demo_markdown/docs/toast/mod.md create mode 100644 thaw/src/toast/mod.rs create mode 100644 thaw/src/toast/toast.rs create mode 100644 thaw/src/toast/toast_body.rs create mode 100644 thaw/src/toast/toast_footer.rs create mode 100644 thaw/src/toast/toast_title.rs create mode 100644 thaw/src/toast/toaster.css create mode 100644 thaw/src/toast/toaster.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 839fe0b..38818b1 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -93,6 +93,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + // diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 4728548..e53a6e6 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -307,6 +307,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/time-picker".into(), label: "Time Picker".into(), }, + MenuItemOption { + value: "/components/toast".into(), + label: "Toast".into(), + }, MenuItemOption { value: "/components/upload".into(), label: "Upload".into(), diff --git a/demo_markdown/docs/toast/mod.md b/demo_markdown/docs/toast/mod.md new file mode 100644 index 0000000..d77d29b --- /dev/null +++ b/demo_markdown/docs/toast/mod.md @@ -0,0 +1,9 @@ +# Toast + +```rust +view! { + + +} + +``` \ No newline at end of file diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 59fac85..f2e1252 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -72,6 +72,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "TextareaMdPage" => "../docs/textarea/mod.md", "TimePickerMdPage" => "../docs/time_picker/mod.md", "TextMdPage" => "../docs/text/mod.md", + "ToastMdPage" => "../docs/toast/mod.md", "UploadMdPage" => "../docs/upload/mod.md" }; diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 3a99e67..b146f1b 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -43,6 +43,7 @@ mod text; mod textarea; mod theme; mod time_picker; +mod toast; mod upload; pub use accordion::*; @@ -91,4 +92,5 @@ pub use textarea::*; pub use thaw_utils::{create_component_ref, ComponentRef, SignalWatch}; pub use theme::*; pub use time_picker::*; +pub use toast::*; pub use upload::*; diff --git a/thaw/src/toast/mod.rs b/thaw/src/toast/mod.rs new file mode 100644 index 0000000..4baa1df --- /dev/null +++ b/thaw/src/toast/mod.rs @@ -0,0 +1,7 @@ +mod toast; +mod toast_title; +mod toaster; +mod toast_body; +mod toast_footer; + +pub use toast_title::*; diff --git a/thaw/src/toast/toast.rs b/thaw/src/toast/toast.rs new file mode 100644 index 0000000..3bf9735 --- /dev/null +++ b/thaw/src/toast/toast.rs @@ -0,0 +1,8 @@ +use leptos::*; + +#[component] +pub fn Toast(id: String) -> impl IntoView { + view! { + + } +} diff --git a/thaw/src/toast/toast_body.rs b/thaw/src/toast/toast_body.rs new file mode 100644 index 0000000..412faf4 --- /dev/null +++ b/thaw/src/toast/toast_body.rs @@ -0,0 +1,20 @@ +use leptos::*; +use thaw_components::OptionComp; + +#[component] +pub fn ToastBody( + #[prop(optional)] toast_body_subtitle: Option, + children: Children, +) -> impl IntoView { + view! { + {children()} + + {(subtitle.children)()} + + } +} + +#[slot] +pub struct ToastBodySubtitle { + children: Children, +} diff --git a/thaw/src/toast/toast_footer.rs b/thaw/src/toast/toast_footer.rs new file mode 100644 index 0000000..076c0fd --- /dev/null +++ b/thaw/src/toast/toast_footer.rs @@ -0,0 +1,6 @@ +use leptos::*; + +#[component] +pub fn ToastFooter(children: Children) -> impl IntoView { + children() +} diff --git a/thaw/src/toast/toast_title.rs b/thaw/src/toast/toast_title.rs new file mode 100644 index 0000000..4ea3755 --- /dev/null +++ b/thaw/src/toast/toast_title.rs @@ -0,0 +1,31 @@ +use leptos::*; +use thaw_components::OptionComp; + +#[component] +pub fn ToastTitle( + #[prop(optional)] toast_title_media: Option, + children: Children, + #[prop(optional)] toast_title_action: Option, +) -> impl IntoView { + view! { +
    + +
    + {children()} + + {(action.children)()} + + } +} + +#[slot] +pub struct ToastTitleMedia { + children: Children, +} + +#[slot] +pub struct ToastTitleAction { + children: Children, +} diff --git a/thaw/src/toast/toaster.css b/thaw/src/toast/toaster.css new file mode 100644 index 0000000..972920f --- /dev/null +++ b/thaw/src/toast/toaster.css @@ -0,0 +1,43 @@ +.thaw-toast { + display: grid; + grid-template-columns: auto 1fr auto; + padding: 12px; + border-radius: var(--borderRadiusMedium); + border: 1px solid var(--colorTransparentStroke); + box-shadow: var(--shadow8); + font-size: var(--fontSizeBase300); + line-height: 20px; + font-weight: var(--fontWeightSemibold); + color: var(--colorNeutralForeground1); + background-color: var(--colorNeutralBackground1); +} + +.thaw-toast-title__media { + display: flex; + padding-top: 2px; + grid-column-end: 2; + padding-right: 8px; + font-size: 16px; + color: var(--colorNeutralForeground1); + color: var(--colorNeutralForeground2); +} + +.thaw-toast-title__media > svg { + display: inline; + line-height: 0; +} + +.thaw-toast-title { + display: flex; + grid-column-end: 3; + color: var(--colorNeutralForeground1); + word-break: break-word; +} + +.thaw-toast-title__action { + display: flex; + align-items: start; + padding-left: 12px; + grid-column-end: -1; + color: var(--colorBrandForeground1); +} diff --git a/thaw/src/toast/toaster.rs b/thaw/src/toast/toaster.rs new file mode 100644 index 0000000..b668d83 --- /dev/null +++ b/thaw/src/toast/toaster.rs @@ -0,0 +1,10 @@ +use leptos::*; +use thaw_utils::mount_style; + +#[component] +pub fn Toaster(toaster_id: String) -> impl IntoView { + mount_style("toaster", include_str!("./toaster.css")); + view! { + + } +} From c57748f9ea9cbdbe46c215df29aea1410ec65931 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 3 Jul 2024 17:27:29 +0800 Subject: [PATCH 073/143] feat: optimize Toast component --- demo/src/app.rs | 6 ++-- demo_markdown/docs/toast/mod.md | 11 ++++-- thaw/src/toast/mod.rs | 56 ++++++++++++++++++++++++++++-- thaw/src/toast/toast.rs | 45 ++++++++++++++++++++++-- thaw/src/toast/toaster.css | 24 +++++++++++++ thaw/src/toast/toaster.rs | 32 +++++++++++++++-- thaw/src/toast/toaster_provider.rs | 16 +++++++++ 7 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 thaw/src/toast/toaster_provider.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 38818b1..d120200 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -110,9 +110,9 @@ fn TheProvider(children: Children) -> impl IntoView { view! { - // - {children()} - // + + {children()} + } } diff --git a/demo_markdown/docs/toast/mod.md b/demo_markdown/docs/toast/mod.md index d77d29b..8bda118 100644 --- a/demo_markdown/docs/toast/mod.md +++ b/demo_markdown/docs/toast/mod.md @@ -1,9 +1,14 @@ # Toast -```rust +```rust demo +let toaster = ToasterInjection::use_(); + +let on_click = move |_| { + toaster.dispatch_toast(view! { "Hello" }.into_any(), Default::default()); +}; + view! { - - + } ``` \ No newline at end of file diff --git a/thaw/src/toast/mod.rs b/thaw/src/toast/mod.rs index 4baa1df..2a74025 100644 --- a/thaw/src/toast/mod.rs +++ b/thaw/src/toast/mod.rs @@ -1,7 +1,59 @@ mod toast; -mod toast_title; -mod toaster; mod toast_body; mod toast_footer; +mod toast_title; +mod toaster; +mod toaster_provider; +pub use toast::*; pub use toast_title::*; +pub use toaster_provider::*; + +use leptos::{html::AnyElement, *}; +use std::sync::mpsc::{channel, Receiver, Sender, TryIter}; + +#[derive(Clone)] +pub struct ToasterInjection { + sender: Sender<(HtmlElement, ToastOptions)>, + trigger: Trigger, +} + +impl ToasterInjection { + pub fn use_() -> Self { + expect_context() + } + + pub fn channel() -> (Self, ToasterReceiver) { + let (sender, receiver) = channel::<(HtmlElement, ToastOptions)>(); + let trigger = Trigger::new(); + + ( + Self { sender, trigger }, + ToasterReceiver::new(receiver, trigger), + ) + } + + pub fn dispatch_toast(&self, any_element: HtmlElement, options: ToastOptions) { + self.sender.send((any_element, options)).unwrap(); + self.trigger.notify(); + } +} + +pub struct ToasterReceiver { + receiver: Receiver<(HtmlElement, ToastOptions)>, + trigger: Trigger, +} + +impl ToasterReceiver { + pub fn new( + receiver: Receiver<(HtmlElement, ToastOptions)>, + trigger: Trigger, + ) -> Self { + Self { receiver, trigger } + } + + pub fn try_recv(&self) -> TryIter<'_, (HtmlElement, ToastOptions)> { + self.trigger.track(); + self.receiver.try_iter() + } +} diff --git a/thaw/src/toast/toast.rs b/thaw/src/toast/toast.rs index 3bf9735..399fd5c 100644 --- a/thaw/src/toast/toast.rs +++ b/thaw/src/toast/toast.rs @@ -1,8 +1,49 @@ use leptos::*; #[component] -pub fn Toast(id: String) -> impl IntoView { +pub fn Toast(children: Children) -> impl IntoView { view! { - +
    + {children()} +
    + } +} + +#[derive(Default, Clone)] +pub enum ToastPosition { + Top, + TopStart, + #[default] + TopEnd, + Bottom, + BottomStart, + BottomEnd, +} + +impl ToastPosition { + pub fn as_str(&self) -> &'static str { + match self { + Self::Top => "top", + Self::TopStart => "top-left", + Self::TopEnd => "top-right", + Self::Bottom => "bottom", + Self::BottomStart => "bottom-left", + Self::BottomEnd => "bottom-right", + } + } +} + +#[derive(Clone)] +pub struct ToastOptions { + pub id: uuid::Uuid, + pub postition: Option, +} + +impl Default for ToastOptions { + fn default() -> Self { + Self { + id: uuid::Uuid::new_v4(), + postition: None, + } } } diff --git a/thaw/src/toast/toaster.css b/thaw/src/toast/toaster.css index 972920f..d323a47 100644 --- a/thaw/src/toast/toaster.css +++ b/thaw/src/toast/toaster.css @@ -1,3 +1,27 @@ +div.thaw-toaster-container { + z-index: 1000000; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + line-height: var(--lineHeightBase300); + font-weight: var(--fontWeightRegular); + font-size: var(--fontSizeBase300); + font-family: var(--fontFamilyBase); + text-align: left; + background-color: var(--colorNeutralBackground1); + color: var(--colorNeutralForeground1); +} + +.thaw-toaster { + bottom: 16px; + right: 20px; + + position: fixed; + width: 292px; + pointer-events: none; +} + .thaw-toast { display: grid; grid-template-columns: auto 1fr auto; diff --git a/thaw/src/toast/toaster.rs b/thaw/src/toast/toaster.rs index b668d83..3f66118 100644 --- a/thaw/src/toast/toaster.rs +++ b/thaw/src/toast/toaster.rs @@ -1,10 +1,36 @@ +use super::{ToastPosition, ToasterReceiver}; use leptos::*; -use thaw_utils::mount_style; +use thaw_components::Teleport; +use thaw_utils::{class_list, mount_style}; #[component] -pub fn Toaster(toaster_id: String) -> impl IntoView { +pub fn Toaster( + receiver: ToasterReceiver, + #[prop(optional)] position: ToastPosition, +) -> impl IntoView { mount_style("toaster", include_str!("./toaster.css")); - view! { + let toast_list = RwSignal::new(vec![]); + Effect::new(move |_| { + for view in receiver.try_recv() { + toast_list.update(move |list| { + list.push(view); + }); + } + }); + view! { + +
    + +
    + {toast.0} +
    +
    +
    +
    } } diff --git a/thaw/src/toast/toaster_provider.rs b/thaw/src/toast/toaster_provider.rs new file mode 100644 index 0000000..504bc86 --- /dev/null +++ b/thaw/src/toast/toaster_provider.rs @@ -0,0 +1,16 @@ +use super::{toaster::Toaster, ToastPosition, ToasterInjection}; +use leptos::*; + +#[component] +pub fn ToasterProvider( + #[prop(optional)] position: ToastPosition, + children: Children, +) -> impl IntoView { + let (injection, receiver) = ToasterInjection::channel(); + view! { + + + {children()} + + } +} From 99f585440b96929c292c19bfabc51907480699e7 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 12 Jun 2024 17:36:34 +0800 Subject: [PATCH 074/143] save --- Cargo.toml | 3 +++ thaw_utils/Cargo.toml | 2 +- thaw_utils/src/event_listener.rs | 14 +++++++++----- thaw_utils/src/optional_prop.rs | 4 ++-- thaw_utils/src/throttle.rs | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5df07a6..85c6708 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,6 @@ thaw = { version = "0.3.1", path = "./thaw" } thaw_components = { version = "0.1.1", path = "./thaw_components" } thaw_macro = { version = "0.1.0", path = "./thaw_macro" } thaw_utils = { version = "0.0.3", path = "./thaw_utils" } + +leptos = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } +leptos_meta = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } \ No newline at end of file diff --git a/thaw_utils/Cargo.toml b/thaw_utils/Cargo.toml index ad14846..8a60343 100644 --- a/thaw_utils/Cargo.toml +++ b/thaw_utils/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -leptos = { version = "0.6.10" } +leptos = { workspace = true } leptos_meta = { version = "0.6.10", optional = true } web-sys = "0.3.69" wasm-bindgen = "0.2.92" diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index 965c58c..9afdc19 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,14 +1,18 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; -use leptos::{html::AnyElement, *}; +use leptos::{ + ev, + tachys::{renderer::DomRenderer, view::any_view::AnyView}, +}; use std::ops::Deref; use web_sys::EventTarget; -pub fn add_event_listener( - target: HtmlElement, +pub fn add_event_listener( + target: impl DomRenderer, event: E, cb: impl Fn(E::EventType) + 'static, ) -> EventListenerHandle where + E: ev::EventDescriptor + 'static, E::EventType: JsCast, { add_event_listener_untyped(target, &event.name(), move |e| { @@ -31,12 +35,12 @@ impl EventListenerHandle { } fn add_event_listener_untyped( - target: HtmlElement, + target: impl DomRenderer, event_name: &str, cb: impl Fn(web_sys::Event) + 'static, ) -> EventListenerHandle { fn wel( - target: HtmlElement, + target: impl DomRenderer, cb: Box, event_name: &str, ) -> EventListenerHandle { diff --git a/thaw_utils/src/optional_prop.rs b/thaw_utils/src/optional_prop.rs index eca37c6..ffb5daf 100644 --- a/thaw_utils/src/optional_prop.rs +++ b/thaw_utils/src/optional_prop.rs @@ -1,4 +1,4 @@ -use leptos::{MaybeSignal, Memo, ReadSignal, RwSignal, Signal}; +use leptos::prelude::{MaybeSignal, Memo, ReadSignal, RwSignal, Signal}; use std::ops::{Deref, DerefMut}; pub struct OptionalProp(Option); @@ -99,7 +99,7 @@ impl From> for OptionalProp { #[cfg(test)] mod test { use super::OptionalProp; - use leptos::MaybeSignal; + use leptos::prelude::MaybeSignal; #[test] fn from() { diff --git a/thaw_utils/src/throttle.rs b/thaw_utils/src/throttle.rs index 0c970ae..a71e061 100644 --- a/thaw_utils/src/throttle.rs +++ b/thaw_utils/src/throttle.rs @@ -1,4 +1,4 @@ -use leptos::{leptos_dom::helpers::TimeoutHandle, *}; +use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*}; use std::time::Duration; pub fn throttle(cb: impl Fn() + 'static, duration: Duration) -> impl Fn() -> () { From 42d76917d0392f611673b9a8653c4039e70020a4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 13 Jun 2024 16:00:14 +0800 Subject: [PATCH 075/143] thaw_utils: upgrade leptosv0.7 --- thaw_components/Cargo.toml | 2 +- thaw_utils/Cargo.toml | 1 + thaw_utils/src/class_list.rs | 148 ++++++++++++----- thaw_utils/src/dom/get_scroll_parent.rs | 98 +++++------ thaw_utils/src/dom/mod.rs | 2 +- thaw_utils/src/dom/mount_style.rs | 39 ++--- thaw_utils/src/event_listener.rs | 61 ++++--- thaw_utils/src/hooks/mod.rs | 2 +- thaw_utils/src/hooks/use_click_position.rs | 7 +- thaw_utils/src/hooks/use_lock_html_scroll.rs | 19 ++- thaw_utils/src/hooks/use_next_frame.rs | 37 +++-- thaw_utils/src/lib.rs | 12 +- thaw_utils/src/optional_prop.rs | 6 +- thaw_utils/src/signals/component_ref.rs | 23 +-- thaw_utils/src/signals/mod.rs | 2 +- thaw_utils/src/signals/model.rs | 152 +++++++----------- .../src/signals/optional_maybe_signal.rs | 35 ++-- thaw_utils/src/signals/signal_watch.rs | 6 +- thaw_utils/src/signals/stored_maybe_signal.rs | 62 ++----- thaw_utils/src/throttle.rs | 3 +- 20 files changed, 362 insertions(+), 355 deletions(-) diff --git a/thaw_components/Cargo.toml b/thaw_components/Cargo.toml index ae140ba..174974b 100644 --- a/thaw_components/Cargo.toml +++ b/thaw_components/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -leptos = { version = "0.6.10" } +leptos = { workspace = true } thaw_utils = { workspace = true } web-sys = { version = "0.3.69", features = ["DomRect"] } cfg-if = "1.0.0" diff --git a/thaw_utils/Cargo.toml b/thaw_utils/Cargo.toml index 8a60343..584f4ea 100644 --- a/thaw_utils/Cargo.toml +++ b/thaw_utils/Cargo.toml @@ -18,6 +18,7 @@ web-sys = "0.3.69" wasm-bindgen = "0.2.92" cfg-if = "1.0.0" chrono = "0.4.35" +send_wrapper = "0.6" [features] csr = ["leptos/csr"] diff --git a/thaw_utils/src/class_list.rs b/thaw_utils/src/class_list.rs index 0b24669..6f452ae 100644 --- a/thaw_utils/src/class_list.rs +++ b/thaw_utils/src/class_list.rs @@ -1,10 +1,13 @@ #[cfg(not(feature = "ssr"))] -use leptos::create_render_effect; +use leptos::prelude::RenderEffect; use leptos::{ - Attribute, IntoAttribute, MaybeProp, Memo, Oco, RwSignal, SignalGet, SignalUpdate, SignalWith, + prelude::{MaybeProp, Memo, Oco, RwSignal}, + reactive_graph::traits::{Get, Update, With, WithUntracked}, + tachys::renderer::DomRenderer, }; -use std::{collections::HashSet, rc::Rc}; +use std::collections::HashSet; +#[derive(Clone)] pub struct ClassList(RwSignal>>); impl ClassList { @@ -30,7 +33,7 @@ impl ClassList { }); } #[cfg(not(feature = "ssr"))] - create_render_effect(move |old_name| { + RenderEffect::new(move |old_name| { let name = f(); if let Some(old_name) = old_name { if old_name != name { @@ -57,7 +60,7 @@ impl ClassList { } } #[cfg(not(feature = "ssr"))] - create_render_effect(move |old_name| { + RenderEffect::new(move |old_name| { let name = f(); if let Some(old_name) = old_name { if old_name != name { @@ -96,7 +99,7 @@ impl ClassList { }); } #[cfg(not(feature = "ssr"))] - create_render_effect(move |old| { + RenderEffect::new(move |old| { let name = name.clone(); let new = f(); if old.is_none() { @@ -121,29 +124,89 @@ impl ClassList { self } + + fn to_class_string(self, class: &mut String) { + self.0.with(|set| { + set.iter().enumerate().for_each(|(index, name)| { + if name.is_empty() { + return; + } + if index != 0 { + class.push(' '); + } + class.push_str(name) + }); + }); + } } -impl IntoAttribute for ClassList { - fn into_attribute(self) -> Attribute { - Attribute::Fn(Rc::new(move || { - self.0.with(|set| { - let mut class = String::new(); - set.iter().enumerate().for_each(|(index, name)| { - if name.is_empty() { - return; - } - if index != 0 { - class.push(' '); - } - class.push_str(name) - }); - class.into_attribute() - }) - })) +impl<'a, R> leptos::tachys::html::class::IntoClass for ClassList +where + R: DomRenderer, +{ + type State = (R::ClassList, String); + type Cloneable = Self; + type CloneableOwned = Self; + + fn html_len(&self) -> usize { + self.0.with_untracked(|set| { + let mut len = 0; + set.iter().enumerate().for_each(|(index, name)| { + if name.is_empty() { + return; + } + if index != 0 { + len += 1; + } + len += name.len(); + }); + + len + }) } - fn into_attribute_boxed(self: Box) -> Attribute { - self.into_attribute() + fn to_html(self, class: &mut String) { + self.to_class_string(class); + } + + fn hydrate(self, el: &R::Element) -> Self::State { + let class_list = R::class_list(el); + let mut class = String::new(); + self.to_class_string(&mut class); + + if !FROM_SERVER { + R::add_class(&class_list, &class); + } + (class_list, class) + } + + fn build(self, el: &R::Element) -> Self::State { + let class_list = R::class_list(el); + let mut class = String::new(); + self.to_class_string(&mut class); + if !class.is_empty() { + R::add_class(&class_list, &class); + } + (class_list, class) + } + + fn rebuild(self, state: &mut Self::State) { + let mut class = String::new(); + self.to_class_string(&mut class); + let (class_list, prev_class) = state; + if class != *prev_class { + R::remove_class(class_list, prev_class); + R::add_class(class_list, &class); + } + *prev_class = class; + } + + fn into_cloneable(self) -> Self::Cloneable { + self + } + + fn into_cloneable_owned(self) -> Self::CloneableOwned { + self } } @@ -245,21 +308,22 @@ macro_rules! class_list { }; } -#[cfg(test)] -mod tests { - use leptos::{create_runtime, Attribute, IntoAttribute}; +// TODO +// #[cfg(test)] +// mod tests { +// use leptos::reactive_graph::Run; - #[test] - fn macro_class_list() { - let rt = create_runtime(); - let class_list = class_list!("aa", ("bb", || true), move || "cc"); - if let Attribute::Fn(f) = class_list.into_attribute() { - if let Attribute::String(class) = f() { - assert!(class.contains("aa")); - assert!(class.contains("bb")); - assert!(class.contains("cc")); - } - } - rt.dispose(); - } -} +// #[test] +// fn macro_class_list() { +// let rt = create_runtime(); +// let class_list = class_list!("aa", ("bb", || true), move || "cc"); +// if let Attribute::Fn(f) = class_list.into_attribute() { +// if let Attribute::String(class) = f() { +// assert!(class.contains("aa")); +// assert!(class.contains("bb")); +// assert!(class.contains("cc")); +// } +// } +// rt.dispose(); +// } +// } diff --git a/thaw_utils/src/dom/get_scroll_parent.rs b/thaw_utils/src/dom/get_scroll_parent.rs index 29dd9d6..203c4de 100644 --- a/thaw_utils/src/dom/get_scroll_parent.rs +++ b/thaw_utils/src/dom/get_scroll_parent.rs @@ -1,55 +1,55 @@ -use leptos::{ - html::{AnyElement, ToHtmlElement}, - *, -}; +// use leptos::{ +// html::{AnyElement, ToHtmlElement}, +// *, +// }; -pub fn get_scroll_parent(element: &HtmlElement) -> Option> { - let Some(parent_element) = get_parent_element(element) else { - return None; - }; +// pub fn get_scroll_parent(element: &HtmlElement) -> Option> { +// let Some(parent_element) = get_parent_element(element) else { +// return None; +// }; - if parent_element.node_type() == 9 { - return Some(parent_element); - } +// if parent_element.node_type() == 9 { +// return Some(parent_element); +// } - if parent_element.node_type() == 1 { - if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { - let overflow = format!("{overflow}{overflow_x}{overflow_y}"); - if overflow.contains("auto") { - return Some(parent_element); - } - if overflow.contains("scroll") { - return Some(parent_element); - } - if overflow.contains("overlay") { - return Some(parent_element); - } - } - } +// if parent_element.node_type() == 1 { +// if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { +// let overflow = format!("{overflow}{overflow_x}{overflow_y}"); +// if overflow.contains("auto") { +// return Some(parent_element); +// } +// if overflow.contains("scroll") { +// return Some(parent_element); +// } +// if overflow.contains("overlay") { +// return Some(parent_element); +// } +// } +// } - get_scroll_parent(&parent_element) -} +// get_scroll_parent(&parent_element) +// } -fn get_parent_element(element: &HtmlElement) -> Option> { - if element.node_type() == 9 { - None - } else { - element.parent_element().map(|ele| ele.to_leptos_element()) - } -} +// fn get_parent_element(element: &HtmlElement) -> Option> { +// if element.node_type() == 9 { +// None +// } else { +// element.parent_element().map(|ele| ele.to_leptos_element()) +// } +// } -fn get_overflow(parent_element: &HtmlElement) -> Option<(String, String, String)> { - let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) else { - return None; - }; - let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { - return None; - }; - let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { - return None; - }; - let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { - return None; - }; - Some((overflow, overflow_x, overflow_y)) -} +// fn get_overflow(parent_element: &HtmlElement) -> Option<(String, String, String)> { +// let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) else { +// return None; +// }; +// let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { +// return None; +// }; +// let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { +// return None; +// }; +// let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { +// return None; +// }; +// Some((overflow, overflow_x, overflow_y)) +// } diff --git a/thaw_utils/src/dom/mod.rs b/thaw_utils/src/dom/mod.rs index c5e3111..5bfba60 100644 --- a/thaw_utils/src/dom/mod.rs +++ b/thaw_utils/src/dom/mod.rs @@ -1,5 +1,5 @@ mod get_scroll_parent; mod mount_style; -pub use get_scroll_parent::get_scroll_parent; +// pub use get_scroll_parent::get_scroll_parent; pub use mount_style::{mount_dynamic_style, mount_style}; diff --git a/thaw_utils/src/dom/mount_style.rs b/thaw_utils/src/dom/mount_style.rs index 461b972..4a88735 100644 --- a/thaw_utils/src/dom/mount_style.rs +++ b/thaw_utils/src/dom/mount_style.rs @@ -9,7 +9,7 @@ pub fn mount_style(id: &str, content: &'static str) { let style_el = style().attr("data-thaw-id", id).child(content); meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); } else { - use leptos::document; + use leptos::prelude::document; let head = document().head().expect("head no exist"); let style = head .query_selector(&format!("style[data-thaw-id=\"{id}\"]")) @@ -32,7 +32,7 @@ pub fn mount_style(id: &str, content: &'static str) { } } -pub fn mount_dynamic_style String + 'static>(id: String, f: T) { +pub fn mount_dynamic_style String + Send + Sync + 'static>(id: String, f: T) { cfg_if! { if #[cfg(feature = "ssr")] { use leptos::html::style; @@ -42,35 +42,30 @@ pub fn mount_dynamic_style String + 'static>(id: String, f: T) { let style_el = style().attr("data-thaw-id", id).child(content); meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); } else { - use leptos::document; + use leptos::prelude::document; + use send_wrapper::SendWrapper; + let head = document().head().expect("head no exist"); let style = head .query_selector(&format!("style[data-thaw-id=\"{id}\"]")) - .expect("query style element error"); - - #[cfg(feature = "hydrate")] - let _ = leptos::leptos_dom::HydrationCtx::id(); - - - leptos::Effect::new_isomorphic(move |prev: Option>| { - let content = f(); - - if let Some(style) = style.as_ref() { - style.set_text_content(Some(&content)); - None - } else if let Some(style) = prev.flatten() { - style.set_text_content(Some(&content)); - Some(style) - } else { + .expect("query style element error").unwrap_or_else(|| { let style = document() .create_element("style") .expect("create style element error"); _ = style.set_attribute("data-thaw-id", &id); - style.set_text_content(Some(&content)); _ = head.prepend_with_node_1(&style); - Some(style) - } + style + }); + + #[cfg(feature = "hydrate")] + let _ = leptos::leptos_dom::HydrationCtx::id(); + + let style = SendWrapper::new(style); + leptos::prelude::Effect::new_isomorphic(move |_| { + let content = f(); + + style.set_text_content(Some(&content)); }); } } diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index 9afdc19..9b1d1f4 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,9 +1,5 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; -use leptos::{ - ev, - tachys::{renderer::DomRenderer, view::any_view::AnyView}, -}; -use std::ops::Deref; +use leptos::{ev, tachys::renderer::DomRenderer}; use web_sys::EventTarget; pub fn add_event_listener( @@ -15,9 +11,10 @@ where E: ev::EventDescriptor + 'static, E::EventType: JsCast, { - add_event_listener_untyped(target, &event.name(), move |e| { - cb(e.unchecked_into::()) - }) + todo!() + // add_event_listener_untyped(target, &event.name(), move |e| { + // cb(e.unchecked_into::()) + // }) } pub struct EventListenerHandle(Box); @@ -34,26 +31,26 @@ impl EventListenerHandle { } } -fn add_event_listener_untyped( - target: impl DomRenderer, - event_name: &str, - cb: impl Fn(web_sys::Event) + 'static, -) -> EventListenerHandle { - fn wel( - target: impl DomRenderer, - cb: Box, - event_name: &str, - ) -> EventListenerHandle { - let cb = Closure::wrap(cb).into_js_value(); - _ = target.add_event_listener_with_callback(event_name, cb.unchecked_ref()); - let event_name = event_name.to_string(); - EventListenerHandle(Box::new(move || { - _ = target.remove_event_listener_with_callback(&event_name, cb.unchecked_ref()); - })) - } +// fn add_event_listener_untyped( +// target: impl DomRenderer, +// event_name: &str, +// cb: impl Fn(web_sys::Event) + 'static, +// ) -> EventListenerHandle { +// fn wel( +// target: impl DomRenderer, +// cb: Box, +// event_name: &str, +// ) -> EventListenerHandle { +// let cb = Closure::wrap(cb).into_js_value(); +// _ = target.add_event_listener_with_callback(event_name, cb.unchecked_ref()); +// let event_name = event_name.to_string(); +// EventListenerHandle(Box::new(move || { +// _ = target.remove_event_listener_with_callback(&event_name, cb.unchecked_ref()); +// })) +// } - wel(target, Box::new(cb), event_name) -} +// wel(target, Box::new(cb), event_name) +// } pub fn add_event_listener_with_bool( target: impl IntoEventTarget, @@ -119,8 +116,8 @@ impl IntoEventTarget for web_sys::Document { } } -impl IntoEventTarget for HtmlElement { - fn into_event_target(self) -> EventTarget { - self.deref().deref().deref().deref().clone() - } -} +// impl IntoEventTarget for HtmlElement { +// fn into_event_target(self) -> EventTarget { +// self.deref().deref().deref().deref().clone() +// } +// } diff --git a/thaw_utils/src/hooks/mod.rs b/thaw_utils/src/hooks/mod.rs index 315230d..64db224 100644 --- a/thaw_utils/src/hooks/mod.rs +++ b/thaw_utils/src/hooks/mod.rs @@ -4,4 +4,4 @@ mod use_next_frame; pub use use_click_position::use_click_position; pub use use_lock_html_scroll::use_lock_html_scroll; -pub use use_next_frame::{use_next_frame, NextFrame}; +pub use use_next_frame::NextFrame; diff --git a/thaw_utils/src/hooks/use_click_position.rs b/thaw_utils/src/hooks/use_click_position.rs index 49df597..29130fc 100644 --- a/thaw_utils/src/hooks/use_click_position.rs +++ b/thaw_utils/src/hooks/use_click_position.rs @@ -1,10 +1,13 @@ -use leptos::{ReadSignal, RwSignal}; +use leptos::reactive_graph::signal::{ReadSignal, RwSignal}; pub fn use_click_position() -> ReadSignal> { let mouse_position = RwSignal::new(None); #[cfg(any(feature = "csr", feature = "hydrate"))] { - use leptos::{ev, on_cleanup, window_event_listener, SignalSet}; + use leptos::{ + ev, + prelude::{on_cleanup, window_event_listener, Set}, + }; use wasm_bindgen::JsCast; use web_sys::MouseEvent; diff --git a/thaw_utils/src/hooks/use_lock_html_scroll.rs b/thaw_utils/src/hooks/use_lock_html_scroll.rs index 091178c..cd67f7e 100644 --- a/thaw_utils/src/hooks/use_lock_html_scroll.rs +++ b/thaw_utils/src/hooks/use_lock_html_scroll.rs @@ -1,20 +1,25 @@ -use leptos::MaybeSignal; +use leptos::reactive_graph::wrappers::read::MaybeSignal; pub fn use_lock_html_scroll(is_lock: MaybeSignal) { #[cfg(any(feature = "csr", feature = "hydrate"))] { - use leptos::{create_render_effect, document, on_cleanup, SignalGet, StoredValue}; - let style_el = StoredValue::new(None::); + // use leptos::{create_render_effect, document, on_cleanup, SignalGet, StoredValue}; + use leptos::prelude::{ + document, effect::RenderEffect, on_cleanup, traits::Get, StoredValue, + }; + use send_wrapper::SendWrapper; + + let style_el = StoredValue::new(SendWrapper::new(None::)); let remove_style_el = move || { style_el.update_value(move |el| { - if let Some(el) = el.take() { + if let Some(el) = Option::take(el) { let head = document().head().expect("head no exist"); _ = head.remove_child(&el); } }); }; - create_render_effect(move |_| { + RenderEffect::new(move |_| { if is_lock.get() { let head = document().head().expect("head no exist"); let style = document() @@ -23,7 +28,9 @@ pub fn use_lock_html_scroll(is_lock: MaybeSignal) { _ = style.set_attribute("data-id", &format!("thaw-lock-html-scroll")); style.set_text_content(Some("html { overflow: hidden; }")); _ = head.append_child(&style); - style_el.set_value(Some(style)); + style_el.update_value(move |el| { + *el = SendWrapper::new(Some(style)); + }); } else { remove_style_el(); } diff --git a/thaw_utils/src/hooks/use_next_frame.rs b/thaw_utils/src/hooks/use_next_frame.rs index 7b1a60b..c2af79d 100644 --- a/thaw_utils/src/hooks/use_next_frame.rs +++ b/thaw_utils/src/hooks/use_next_frame.rs @@ -1,24 +1,35 @@ +// use leptos::{ +// leptos_dom::helpers::AnimationFrameRequestHandle, on_cleanup, +// request_animation_frame_with_handle, StoredValue, +// }; + use leptos::{ - leptos_dom::helpers::AnimationFrameRequestHandle, on_cleanup, - request_animation_frame_with_handle, StoredValue, + prelude::{request_animation_frame_with_handle, AnimationFrameRequestHandle}, + reactive_graph::owner::{on_cleanup, StoredValue}, }; -pub fn use_next_frame() -> NextFrame { - let next_frame = NextFrame::default(); - - on_cleanup(move || { - next_frame.cancel(); - }); - - next_frame -} - -#[derive(Default, Clone)] +#[derive(Clone)] pub struct NextFrame(StoredValue>); +impl Default for NextFrame { + fn default() -> Self { + Self(StoredValue::new(None)) + } +} + impl Copy for NextFrame {} impl NextFrame { + pub fn use_() -> Self { + let next_frame = NextFrame::default(); + + on_cleanup(move || { + next_frame.cancel(); + }); + + next_frame + } + pub fn run(&self, cb: impl FnOnce() + 'static) { self.cancel(); diff --git a/thaw_utils/src/lib.rs b/thaw_utils/src/lib.rs index 3a80f60..2bdd211 100644 --- a/thaw_utils/src/lib.rs +++ b/thaw_utils/src/lib.rs @@ -7,15 +7,11 @@ mod signals; mod throttle; mod time; -pub use dom::{get_scroll_parent, mount_dynamic_style, mount_style}; -pub use event_listener::{ - add_event_listener, add_event_listener_with_bool, EventListenerHandle, IntoEventTarget, -}; -pub use hooks::{use_click_position, use_lock_html_scroll, use_next_frame, NextFrame}; +pub use dom::{mount_dynamic_style, mount_style}; +pub use event_listener::{add_event_listener, add_event_listener_with_bool, EventListenerHandle}; +pub use hooks::{use_click_position, use_lock_html_scroll, NextFrame}; pub use optional_prop::OptionalProp; -pub use signals::{ - create_component_ref, ComponentRef, Model, OptionalMaybeSignal, SignalWatch, StoredMaybeSignal, -}; +pub use signals::{ComponentRef, Model, OptionalMaybeSignal, SignalWatch, StoredMaybeSignal}; pub use throttle::throttle; pub use time::now_date; diff --git a/thaw_utils/src/optional_prop.rs b/thaw_utils/src/optional_prop.rs index ffb5daf..78c0007 100644 --- a/thaw_utils/src/optional_prop.rs +++ b/thaw_utils/src/optional_prop.rs @@ -66,19 +66,19 @@ impl From for OptionalProp> { } } -impl From> for OptionalProp> { +impl From> for OptionalProp> { fn from(value: ReadSignal) -> Self { Self(Some(MaybeSignal::from(value))) } } -impl From> for OptionalProp> { +impl From> for OptionalProp> { fn from(value: RwSignal) -> Self { Self(Some(MaybeSignal::from(value))) } } -impl From> for OptionalProp> { +impl From> for OptionalProp> { fn from(value: Memo) -> Self { Self(Some(MaybeSignal::from(value))) } diff --git a/thaw_utils/src/signals/component_ref.rs b/thaw_utils/src/signals/component_ref.rs index 8baf1c1..e371617 100644 --- a/thaw_utils/src/signals/component_ref.rs +++ b/thaw_utils/src/signals/component_ref.rs @@ -1,14 +1,18 @@ use leptos::{ - create_render_effect, create_rw_signal, logging::debug_warn, RwSignal, SignalGet, - SignalGetUntracked, SignalUpdate, + logging::debug_warn, + reactive_graph::{ + effect::RenderEffect, + signal::RwSignal, + traits::{Get, GetUntracked, Update}, + }, }; use std::cell::Cell; pub struct ComponentRef(RwSignal>); -impl Default for ComponentRef { +impl Default for ComponentRef { fn default() -> Self { - Self(create_rw_signal(None)) + Self(RwSignal::new(None)) } } @@ -20,11 +24,14 @@ impl Clone for ComponentRef { impl Copy for ComponentRef {} -impl ComponentRef { +// TODO +impl ComponentRef { pub fn new() -> Self { Self::default() } +} +impl ComponentRef { pub fn get(&self) -> Option where T: Clone, @@ -58,14 +65,10 @@ impl ComponentRef { { let f = Cell::new(Some(f)); - create_render_effect(move |_| { + RenderEffect::new(move |_| { if let Some(comp) = self.get() { f.take().unwrap()(comp); } }); } } - -pub fn create_component_ref() -> ComponentRef { - ComponentRef::default() -} diff --git a/thaw_utils/src/signals/mod.rs b/thaw_utils/src/signals/mod.rs index d1f6fc5..a491aee 100644 --- a/thaw_utils/src/signals/mod.rs +++ b/thaw_utils/src/signals/mod.rs @@ -4,7 +4,7 @@ mod optional_maybe_signal; mod signal_watch; mod stored_maybe_signal; -pub use component_ref::{create_component_ref, ComponentRef}; +pub use component_ref::ComponentRef; pub use model::Model; pub use optional_maybe_signal::OptionalMaybeSignal; pub use signal_watch::SignalWatch; diff --git a/thaw_utils/src/signals/model.rs b/thaw_utils/src/signals/model.rs index 87f6356..6d072c3 100644 --- a/thaw_utils/src/signals/model.rs +++ b/thaw_utils/src/signals/model.rs @@ -1,6 +1,8 @@ -use leptos::{ - Memo, ReadSignal, RwSignal, Signal, SignalGet, SignalGetUntracked, SignalSet, SignalUpdate, - SignalWith, SignalWithUntracked, WriteSignal, +use leptos::reactive_graph::{ + computed::Memo, + signal::{ReadSignal, RwSignal, WriteSignal}, + traits::{DefinedAt, IsDisposed, Set, Update, With, WithUntracked}, + wrappers::read::Signal, }; pub struct Model @@ -12,7 +14,7 @@ where on_write: Option>, } -impl Default for Model { +impl Default for Model { fn default() -> Self { RwSignal::new(Default::default()).into() } @@ -26,7 +28,7 @@ impl Clone for Model { impl Copy for Model {} -impl Model { +impl Model { fn new(value: T) -> Self { let rw_signal = RwSignal::new(value); rw_signal.into() @@ -37,91 +39,56 @@ impl Model { } } -impl SignalGet for Model { - type Value = T; - - fn get(&self) -> Self::Value { - self.read.get() - } - - fn try_get(&self) -> Option { - self.read.try_get() +impl DefinedAt for Model { + fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> { + todo!() } } -impl SignalGetUntracked for Model { +impl With for Model { type Value = T; - fn get_untracked(&self) -> Self::Value { - self.read.get_untracked() - } - - fn try_get_untracked(&self) -> Option { - self.read.try_get_untracked() - } -} - -impl SignalSet for Model { - type Value = T; - - fn set(&self, new_value: Self::Value) { - if let Some(on_write) = self.on_write.as_ref() { - on_write.set(new_value.clone()); - } - self.write.set(new_value); - } - - fn try_set(&self, new_value: Self::Value) -> Option { - if let Some(on_write) = self.on_write.as_ref() { - on_write.try_set(new_value.clone()); - } - self.write.try_set(new_value) - } -} - -impl SignalWith for Model { - type Value = T; - - fn with(&self, f: impl FnOnce(&Self::Value) -> O) -> O { - self.read.with(f) - } - fn try_with(&self, f: impl FnOnce(&Self::Value) -> O) -> Option { self.read.try_with(f) } } -impl SignalWithUntracked for Model { +impl WithUntracked for Model { type Value = T; - fn with_untracked(&self, f: impl FnOnce(&Self::Value) -> O) -> O { - self.read.with_untracked(f) - } - fn try_with_untracked(&self, f: impl FnOnce(&Self::Value) -> O) -> Option { self.read.try_with_untracked(f) } } -impl SignalUpdate for Model { +// TODO +impl Update for Model { type Value = T; - fn update(&self, f: impl FnOnce(&mut Self::Value)) { - self.write.update(f); - } + fn try_maybe_update(&self, fun: impl FnOnce(&mut Self::Value) -> (bool, U)) -> Option { + let value = self.write.try_maybe_update(fun); - fn try_update(&self, f: impl FnOnce(&mut Self::Value) -> O) -> Option { - self.write.try_update(f) + if let Some(on_write) = self.on_write.as_ref() { + on_write.set(self.read.with_untracked(|read| read.clone())); + } + + value } } -impl From for Model { +impl IsDisposed for Model { + fn is_disposed(&self) -> bool { + self.write.is_disposed() + } +} + +impl From for Model { fn from(value: T) -> Self { Self::new(value) } } -impl From> for Model { +impl From> for Model { fn from(rw_signal: RwSignal) -> Self { let (read, write) = rw_signal.split(); Self { @@ -142,7 +109,7 @@ impl From<(Signal, WriteSignal)> for Model { } } -impl From<(ReadSignal, WriteSignal)> for Model { +impl From<(ReadSignal, WriteSignal)> for Model { fn from((read, write): (ReadSignal, WriteSignal)) -> Self { Self { read: read.into(), @@ -152,7 +119,7 @@ impl From<(ReadSignal, WriteSignal)> for Model { } } -impl From<(Memo, WriteSignal)> for Model { +impl From<(Memo, WriteSignal)> for Model { fn from((read, write): (Memo, WriteSignal)) -> Self { Self { read: read.into(), @@ -162,7 +129,7 @@ impl From<(Memo, WriteSignal)> for Model { } } -impl From<(Option, WriteSignal)> for Model { +impl From<(Option, WriteSignal)> for Model { fn from((read, write): (Option, WriteSignal)) -> Self { let mut model = Self::new(read.unwrap_or_default()); model.on_write = Some(write); @@ -170,35 +137,36 @@ impl From<(Option, WriteSignal)> for Model { } } -#[cfg(test)] -mod test { - use super::Model; - use leptos::*; +// TODO +// #[cfg(test)] +// mod test { +// use super::Model; +// use leptos::*; - #[test] - fn from() { - let runtime = create_runtime(); +// #[test] +// fn from() { +// let runtime = create_runtime(); - // T - let model: Model = 0.into(); - assert_eq!(model.get_untracked(), 0); - model.set(1); - assert_eq!(model.get_untracked(), 1); +// // T +// let model: Model = 0.into(); +// assert_eq!(model.get_untracked(), 0); +// model.set(1); +// assert_eq!(model.get_untracked(), 1); - // RwSignal - let rw_signal = RwSignal::new(0); - let model: Model = rw_signal.into(); - assert_eq!(model.get_untracked(), 0); - model.set(1); - assert_eq!(model.get_untracked(), 1); +// // RwSignal +// let rw_signal = RwSignal::new(0); +// let model: Model = rw_signal.into(); +// assert_eq!(model.get_untracked(), 0); +// model.set(1); +// assert_eq!(model.get_untracked(), 1); - // Read Write - let (read, write) = create_signal(0); - let model: Model = (read, write).into(); - assert_eq!(model.get_untracked(), 0); - model.set(1); - assert_eq!(model.get_untracked(), 1); +// // Read Write +// let (read, write) = create_signal(0); +// let model: Model = (read, write).into(); +// assert_eq!(model.get_untracked(), 0); +// model.set(1); +// assert_eq!(model.get_untracked(), 1); - runtime.dispose(); - } -} +// runtime.dispose(); +// } +// } diff --git a/thaw_utils/src/signals/optional_maybe_signal.rs b/thaw_utils/src/signals/optional_maybe_signal.rs index 70b782f..d43b3be 100644 --- a/thaw_utils/src/signals/optional_maybe_signal.rs +++ b/thaw_utils/src/signals/optional_maybe_signal.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::prelude::*; use std::ops::Deref; pub struct OptionalMaybeSignal(MaybeSignal>); @@ -37,19 +37,19 @@ impl From> for OptionalMaybeSignal { } } -impl From>> for OptionalMaybeSignal { +impl From>> for OptionalMaybeSignal { fn from(value: ReadSignal>) -> Self { Self(MaybeSignal::Dynamic(value.into())) } } -impl From>> for OptionalMaybeSignal { +impl From>> for OptionalMaybeSignal { fn from(value: RwSignal>) -> Self { Self(MaybeSignal::Dynamic(value.into())) } } -impl From>> for OptionalMaybeSignal { +impl From>> for OptionalMaybeSignal { fn from(value: Memo>) -> Self { Self(MaybeSignal::Dynamic(value.into())) } @@ -67,19 +67,20 @@ impl From>> for OptionalMaybeSignal { } } -#[cfg(test)] -mod test { - use super::OptionalMaybeSignal; - use leptos::{create_runtime, MaybeSignal}; +// TODO +// #[cfg(test)] +// mod test { +// use super::OptionalMaybeSignal; +// use leptos::{create_runtime, MaybeSignal}; - #[test] - fn into() { - let runtime = create_runtime(); +// #[test] +// fn into() { +// let runtime = create_runtime(); - let _: MaybeSignal = 12.into(); - let _: OptionalMaybeSignal = Some(12).into(); - let _: OptionalMaybeSignal = MaybeSignal::Static(Some(12)).into(); +// let _: MaybeSignal = 12.into(); +// let _: OptionalMaybeSignal = Some(12).into(); +// let _: OptionalMaybeSignal = MaybeSignal::Static(Some(12)).into(); - runtime.dispose(); - } -} +// runtime.dispose(); +// } +// } diff --git a/thaw_utils/src/signals/signal_watch.rs b/thaw_utils/src/signals/signal_watch.rs index 51f37fd..0da02e8 100644 --- a/thaw_utils/src/signals/signal_watch.rs +++ b/thaw_utils/src/signals/signal_watch.rs @@ -1,4 +1,4 @@ -use leptos::{create_effect, untrack, RwSignal, SignalDispose, SignalWith}; +use leptos::reactive_graph::{effect::Effect, signal::RwSignal, traits::{Dispose, With}, untrack}; pub trait SignalWatch { type Value; @@ -6,7 +6,7 @@ pub trait SignalWatch { fn watch(&self, f: impl Fn(&Self::Value) + 'static) -> Box; } -impl SignalWatch for RwSignal { +impl SignalWatch for RwSignal { type Value = T; /// Listens for RwSignal changes and is not executed immediately @@ -31,7 +31,7 @@ impl SignalWatch for RwSignal { fn watch(&self, f: impl Fn(&Self::Value) + 'static) -> Box { let signal = *self; - let effect = create_effect(move |prev| { + let effect = Effect::new(move |prev| { signal.with(|value| { if prev.is_some() { untrack(|| f(value)); diff --git a/thaw_utils/src/signals/stored_maybe_signal.rs b/thaw_utils/src/signals/stored_maybe_signal.rs index fedbe40..b191509 100644 --- a/thaw_utils/src/signals/stored_maybe_signal.rs +++ b/thaw_utils/src/signals/stored_maybe_signal.rs @@ -1,6 +1,7 @@ -use leptos::{ - MaybeSignal, Signal, SignalGet, SignalGetUntracked, SignalWith, SignalWithUntracked, - StoredValue, +use leptos::reactive_graph::{ + owner::StoredValue, + traits::{DefinedAt, With, WithUntracked}, + wrappers::read::{MaybeSignal, Signal}, }; #[derive(Clone)] @@ -14,52 +15,18 @@ where impl Copy for StoredMaybeSignal {} -impl SignalGet for StoredMaybeSignal { - type Value = T; - - fn get(&self) -> Self::Value { +impl DefinedAt for StoredMaybeSignal { + fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> { match self { - StoredMaybeSignal::StoredValue(value) => value.get_value(), - StoredMaybeSignal::Signal(signal) => signal.get(), - } - } - - fn try_get(&self) -> Option { - match self { - StoredMaybeSignal::StoredValue(value) => value.try_get_value(), - StoredMaybeSignal::Signal(signal) => signal.try_get(), + StoredMaybeSignal::StoredValue(value) => value.defined_at(), + StoredMaybeSignal::Signal(signal) => signal.defined_at(), } } } -impl SignalGetUntracked for StoredMaybeSignal { +impl With for StoredMaybeSignal { type Value = T; - fn get_untracked(&self) -> Self::Value { - match self { - StoredMaybeSignal::StoredValue(value) => value.get_value(), - StoredMaybeSignal::Signal(signal) => signal.get_untracked(), - } - } - - fn try_get_untracked(&self) -> Option { - match self { - StoredMaybeSignal::StoredValue(value) => value.try_get_value(), - StoredMaybeSignal::Signal(signal) => signal.try_get_untracked(), - } - } -} - -impl SignalWith for StoredMaybeSignal { - type Value = T; - - fn with(&self, f: impl FnOnce(&Self::Value) -> O) -> O { - match self { - StoredMaybeSignal::StoredValue(value) => value.with_value(f), - StoredMaybeSignal::Signal(signal) => signal.with(f), - } - } - fn try_with(&self, f: impl FnOnce(&Self::Value) -> O) -> Option { match self { StoredMaybeSignal::StoredValue(value) => value.try_with_value(f), @@ -68,16 +35,9 @@ impl SignalWith for StoredMaybeSignal { } } -impl SignalWithUntracked for StoredMaybeSignal { +impl WithUntracked for StoredMaybeSignal { type Value = T; - fn with_untracked(&self, f: impl FnOnce(&Self::Value) -> O) -> O { - match self { - StoredMaybeSignal::StoredValue(value) => value.with_value(f), - StoredMaybeSignal::Signal(signal) => signal.with_untracked(f), - } - } - fn try_with_untracked(&self, f: impl FnOnce(&Self::Value) -> O) -> Option { match self { StoredMaybeSignal::StoredValue(value) => value.try_with_value(f), @@ -86,7 +46,7 @@ impl SignalWithUntracked for StoredMaybeSignal { } } -impl From> for StoredMaybeSignal { +impl From> for StoredMaybeSignal { fn from(value: MaybeSignal) -> Self { match value { MaybeSignal::Static(value) => Self::StoredValue(StoredValue::new(value)), diff --git a/thaw_utils/src/throttle.rs b/thaw_utils/src/throttle.rs index a71e061..a637b35 100644 --- a/thaw_utils/src/throttle.rs +++ b/thaw_utils/src/throttle.rs @@ -1,7 +1,7 @@ use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*}; use std::time::Duration; -pub fn throttle(cb: impl Fn() + 'static, duration: Duration) -> impl Fn() -> () { +pub fn throttle(cb: impl Fn() + Send + Sync + 'static, duration: Duration) -> impl Fn() -> () { let cb = Callback::new(move |_| cb()); let timeout_handle = StoredValue::new(None::); on_cleanup(move || { @@ -16,6 +16,7 @@ pub fn throttle(cb: impl Fn() + 'static, duration: Duration) -> impl Fn() -> () if timeout_handle.with_value(|handle| handle.is_some()) { return; } + let cb = cb.clone(); let handle = set_timeout_with_handle( move || { cb.call(()); From f152a19322418f5b5517e1bb91f0558c8abdc0b4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 14 Jun 2024 09:55:49 +0800 Subject: [PATCH 076/143] thaw_components: upgrade leptosv0.7 --- thaw_components/src/binder/mod.rs | 16 +++++++++------- thaw_components/src/css_transition/mod.rs | 17 +++++++++-------- thaw_components/src/focus_trap/mod.rs | 2 +- thaw_components/src/if_comp.rs | 2 +- thaw_components/src/lib.rs | 2 +- thaw_components/src/teleport/mod.rs | 3 ++- thaw_components/src/wave/mod.rs | 8 ++++---- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/thaw_components/src/binder/mod.rs b/thaw_components/src/binder/mod.rs index d63e805..583488b 100644 --- a/thaw_components/src/binder/mod.rs +++ b/thaw_components/src/binder/mod.rs @@ -4,7 +4,9 @@ pub use get_placement_style::FollowerPlacement; use crate::Teleport; use get_placement_style::{get_follower_placement_offset, FollowerPlacementOffset}; -use leptos::{html::ElementDescriptor, leptos_dom::helpers::WindowListenerHandle, *}; +use leptos::{ + ev, html, html::ElementDescriptor, leptos_dom::helpers::WindowListenerHandle, prelude::*, +}; use thaw_utils::{ add_event_listener, get_scroll_parent, mount_style, with_hydration_off, EventListenerHandle, }; @@ -69,9 +71,9 @@ pub fn Binder( children: follower_children, } = follower; - let scroll_listener = store_value(None::>); - let scrollable_element_handle_vec = store_value::>(vec![]); - let resize_handle = store_value(None::); + let scroll_listener = StoredValue::new(None::>); + let scrollable_element_handle_vec = StoredValue::new::>(vec![]); + let resize_handle = StoredValue::new(None::); let ensure_scroll_listener = move || { let Some(el) = target_ref.get_untracked().map(|target| target.into_any()) else { @@ -167,9 +169,9 @@ fn FollowerContainer( #[prop(into)] remove_resize_listener: Callback<()>, children: Children, ) -> impl IntoView { - let content_ref = create_node_ref::(); - let content_style = create_rw_signal(String::new()); - let placement_str = create_rw_signal(placement.as_str()); + let content_ref = NodeRef::::new(); + let content_style = RwSignal::new(String::new()); + let placement_str = RwSignal::new(placement.as_str()); let sync_position: Callback<()> = Callback::new(move |_| { let Some(content_ref) = content_ref.get_untracked() else { return; diff --git a/thaw_components/src/css_transition/mod.rs b/thaw_components/src/css_transition/mod.rs index 1e199d7..5e1a0be 100644 --- a/thaw_components/src/css_transition/mod.rs +++ b/thaw_components/src/css_transition/mod.rs @@ -1,13 +1,13 @@ -use leptos::{html::ElementDescriptor, *}; +use leptos::{ev, html::ElementType, prelude::*}; use std::{ops::Deref, time::Duration}; -use thaw_utils::{add_event_listener, use_next_frame, EventListenerHandle}; +use thaw_utils::{add_event_listener, EventListenerHandle, NextFrame}; /// # CSS Transition /// /// Reference to https://vuejs.org/guide/built-ins/transition.html #[component] -pub fn CSSTransition( - node_ref: NodeRef, +pub fn CSSTransition( + node_ref: NodeRef, #[prop(into)] show: MaybeSignal, #[prop(into)] name: MaybeSignal, #[prop(optional)] appear: bool, @@ -20,17 +20,18 @@ pub fn CSSTransition( children: CF, ) -> impl IntoView where - T: ElementDescriptor + Clone + 'static, + E: ElementType, + E::Output: 'static, CF: FnOnce(ReadSignal>) -> IV + 'static, IV: IntoView, { - let display = create_rw_signal((!show.get_untracked()).then_some("display: none;")); + let display = RwSignal::new((!show.get_untracked()).then_some("display: none;")); node_ref.on_load(move |node_el| { let any_el = node_el.clone().into_any(); let el = any_el.deref().clone(); let class_list = el.class_list(); - let next_frame = use_next_frame(); + let next_frame = NextFrame::use_(); let end_handle = StoredValue::new(None::); let end_count = StoredValue::new(None::); let finish = StoredValue::new(None::>); @@ -166,7 +167,7 @@ where }) }; - create_render_effect(move |prev: Option| { + RenderEffect::new(move |prev: Option| { let show = show.get(); let prev = if let Some(prev) = prev { prev diff --git a/thaw_components/src/focus_trap/mod.rs b/thaw_components/src/focus_trap/mod.rs index 4dfab3a..31c1f8e 100644 --- a/thaw_components/src/focus_trap/mod.rs +++ b/thaw_components/src/focus_trap/mod.rs @@ -1,4 +1,4 @@ -use leptos::*; +use leptos::{ev, prelude::*}; #[cfg(any(feature = "csr", feature = "hydrate"))] thread_local! { diff --git a/thaw_components/src/if_comp.rs b/thaw_components/src/if_comp.rs index 708da33..e253323 100644 --- a/thaw_components/src/if_comp.rs +++ b/thaw_components/src/if_comp.rs @@ -1,5 +1,5 @@ use super::Fallback; -use leptos::*; +use leptos::prelude::*; #[slot] pub struct Then { diff --git a/thaw_components/src/lib.rs b/thaw_components/src/lib.rs index 4901296..cf1c3cf 100644 --- a/thaw_components/src/lib.rs +++ b/thaw_components/src/lib.rs @@ -14,7 +14,7 @@ pub use option_comp::OptionComp; pub use teleport::Teleport; pub use wave::{Wave, WaveRef}; -use leptos::*; +use leptos::prelude::{slot, ChildrenFn}; #[slot] pub struct Fallback { diff --git a/thaw_components/src/teleport/mod.rs b/thaw_components/src/teleport/mod.rs index 5c2b653..f24f096 100644 --- a/thaw_components/src/teleport/mod.rs +++ b/thaw_components/src/teleport/mod.rs @@ -1,5 +1,6 @@ use cfg_if::cfg_if; -use leptos::{html::AnyElement, *}; +use leptos::{html::{AnyElement, HtmlElement}, prelude::*}; +use tachys::view::any_view::AnyView; /// https://github.com/solidjs/solid/blob/main/packages/solid/web/src/index.ts#L56 #[component] diff --git a/thaw_components/src/wave/mod.rs b/thaw_components/src/wave/mod.rs index b5ee7dc..d2c9640 100644 --- a/thaw_components/src/wave/mod.rs +++ b/thaw_components/src/wave/mod.rs @@ -1,4 +1,4 @@ -use leptos::{leptos_dom::helpers::TimeoutHandle, *}; +use leptos::{html, leptos_dom::helpers::TimeoutHandle, prelude::*}; use std::time::Duration; use thaw_utils::{mount_style, ComponentRef}; @@ -16,8 +16,8 @@ impl WaveRef { #[component] pub fn Wave(#[prop(optional)] comp_ref: ComponentRef) -> impl IntoView { mount_style("wave", include_str!("./wave.css")); - let wave_ref = create_node_ref::(); - let animation_timeout_handle = create_rw_signal(None::); + let wave_ref = NodeRef::::new(); + let animation_timeout_handle = RwSignal::new(None::); let play = Callback::new(move |_: ()| { if let Some(handle) = animation_timeout_handle.get() { handle.clear(); @@ -51,7 +51,7 @@ pub fn Wave(#[prop(optional)] comp_ref: ComponentRef) -> impl IntoView move || animation_timeout_handle.with(|handle| handle.is_some()), ) - ref=wave_ref + node_ref=wave_ref >
    } } From 51c2d2424206e6d423d7eaa4568218dadd2e0ade Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 12 Jun 2024 17:36:34 +0800 Subject: [PATCH 077/143] save --- thaw_utils/src/event_listener.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index 9b1d1f4..a3ceccb 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,5 +1,9 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; -use leptos::{ev, tachys::renderer::DomRenderer}; +use leptos::{ + ev, + tachys::{renderer::DomRenderer, view::any_view::AnyView}, +}; +use std::ops::Deref; use web_sys::EventTarget; pub fn add_event_listener( From 6b7f689b87a876cbac8063899224afa2858193f5 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 13 Jun 2024 16:00:14 +0800 Subject: [PATCH 078/143] thaw_utils: upgrade leptosv0.7 --- thaw_utils/src/event_listener.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index a3ceccb..9b1d1f4 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,9 +1,5 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; -use leptos::{ - ev, - tachys::{renderer::DomRenderer, view::any_view::AnyView}, -}; -use std::ops::Deref; +use leptos::{ev, tachys::renderer::DomRenderer}; use web_sys::EventTarget; pub fn add_event_listener( From 3bfdac9e448b2e2f03df65cd2b996b4101e7bf8d Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 1 Jul 2024 10:52:57 +0800 Subject: [PATCH 079/143] refactor(leptos-v0.7): thaw_components --- thaw_components/Cargo.toml | 1 + .../src/binder/get_placement_style.rs | 2 +- thaw_components/src/binder/mod.rs | 57 ++++--- thaw_components/src/css_transition/mod.rs | 154 +++++++++++------- thaw_components/src/if_comp.rs | 8 +- thaw_components/src/option_comp.rs | 12 +- thaw_utils/src/dom/get_scroll_parent.rs | 96 ++++++----- thaw_utils/src/dom/mod.rs | 2 +- thaw_utils/src/event_listener.rs | 82 ++++++---- thaw_utils/src/lib.rs | 2 +- 10 files changed, 236 insertions(+), 180 deletions(-) diff --git a/thaw_components/Cargo.toml b/thaw_components/Cargo.toml index 174974b..636076a 100644 --- a/thaw_components/Cargo.toml +++ b/thaw_components/Cargo.toml @@ -17,6 +17,7 @@ thaw_utils = { workspace = true } web-sys = { version = "0.3.69", features = ["DomRect"] } cfg-if = "1.0.0" uuid = { version = "1.7.0", features = ["v4"] } +send_wrapper = "0.6" [features] csr = ["leptos/csr"] diff --git a/thaw_components/src/binder/get_placement_style.rs b/thaw_components/src/binder/get_placement_style.rs index c5ba749..5b45b2e 100644 --- a/thaw_components/src/binder/get_placement_style.rs +++ b/thaw_components/src/binder/get_placement_style.rs @@ -1,4 +1,4 @@ -use leptos::window; +use leptos::prelude::window; use web_sys::DomRect; #[derive(Clone)] diff --git a/thaw_components/src/binder/mod.rs b/thaw_components/src/binder/mod.rs index 583488b..069dbfd 100644 --- a/thaw_components/src/binder/mod.rs +++ b/thaw_components/src/binder/mod.rs @@ -1,11 +1,17 @@ mod get_placement_style; +use std::ops::Deref; + pub use get_placement_style::FollowerPlacement; +use web_sys::wasm_bindgen::JsCast; use crate::Teleport; use get_placement_style::{get_follower_placement_offset, FollowerPlacementOffset}; use leptos::{ - ev, html, html::ElementDescriptor, leptos_dom::helpers::WindowListenerHandle, prelude::*, + ev, + html::{self, ElementType}, + leptos_dom::helpers::WindowListenerHandle, + prelude::*, }; use thaw_utils::{ add_event_listener, get_scroll_parent, mount_style, with_hydration_off, EventListenerHandle, @@ -55,14 +61,18 @@ impl Copy for FollowerWidth {} /// } /// ``` #[component] -pub fn Binder( +pub fn Binder( /// Used to track DOM locations #[prop(into)] - target_ref: NodeRef, + target_ref: NodeRef, /// Content for pop-up display follower: Follower, children: Children, -) -> impl IntoView { +) -> impl IntoView +where + E: ElementType + 'static, + E::Output: JsCast + Clone + Deref + 'static, +{ mount_style("binder", include_str!("./binder.css")); let Follower { show: follower_show, @@ -72,11 +82,12 @@ pub fn Binder( } = follower; let scroll_listener = StoredValue::new(None::>); - let scrollable_element_handle_vec = StoredValue::new::>(vec![]); + let scrollable_element_handle_vec = StoredValue::>::new(vec![]); let resize_handle = StoredValue::new(None::); - let ensure_scroll_listener = move || { - let Some(el) = target_ref.get_untracked().map(|target| target.into_any()) else { + let ensure_scroll_listener = Callback::new(move |_: ()| { + let target_ref = target_ref.get_untracked(); + let Some(el) = target_ref.as_deref() else { return; }; @@ -97,12 +108,12 @@ pub fn Binder( } } scrollable_element_handle_vec.set_value(handle_vec); - }; + }); let add_scroll_listener = Callback::new(move |listener: Callback<()>| { scroll_listener.update_value(|scroll_listener| { if scroll_listener.is_none() { - ensure_scroll_listener(); + ensure_scroll_listener.call(()); } *scroll_listener = Some(listener); }) @@ -136,9 +147,13 @@ pub fn Binder( }); }); - on_cleanup(move || { - remove_scroll_listener.call(()); - remove_resize_listener.call(()); + on_cleanup({ + let remove_scroll_listener = remove_scroll_listener.clone(); + let remove_resize_listener = remove_resize_listener.clone(); + move || { + remove_scroll_listener.call(()); + remove_resize_listener.call(()); + } }); view! { {children()} @@ -158,9 +173,9 @@ pub fn Binder( } #[component] -fn FollowerContainer( +fn FollowerContainer( show: MaybeSignal, - target_ref: NodeRef, + target_ref: NodeRef, width: Option, placement: FollowerPlacement, #[prop(into)] add_scroll_listener: Callback>, @@ -168,7 +183,11 @@ fn FollowerContainer( #[prop(into)] add_resize_listener: Callback>, #[prop(into)] remove_resize_listener: Callback<()>, children: Children, -) -> impl IntoView { +) -> impl IntoView +where + E: ElementType, + E::Output: JsCast + Clone + Deref + 'static, +{ let content_ref = NodeRef::::new(); let content_style = RwSignal::new(String::new()); let placement_str = RwSignal::new(placement.as_str()); @@ -176,7 +195,7 @@ fn FollowerContainer( let Some(content_ref) = content_ref.get_untracked() else { return; }; - let Some(target_ref) = target_ref.get_untracked().map(|target| target.into_any()) else { + let Some(target_ref) = target_ref.get_untracked() else { return; }; let target_rect = target_ref.get_bounding_client_rect(); @@ -206,7 +225,7 @@ fn FollowerContainer( "transform: translateX({left}px) translateY({top}px) {transform};" )); } else { - logging::error!("Thaw-Binder: get_follower_placement_style return None"); + error!("Thaw-Binder: get_follower_placement_style return None"); } content_style.set(style); @@ -232,9 +251,9 @@ fn FollowerContainer( }); let children = with_hydration_off(|| { - html::div().classes("thaw-binder-follower-container").child( + html::div().class("thaw-binder-follower-container").child( html::div() - .classes("thaw-binder-follower-content") + .class("thaw-binder-follower-content") .attr("data-thaw-placement", move || placement_str.get()) .node_ref(content_ref) .attr("style", move || content_style.get()) diff --git a/thaw_components/src/css_transition/mod.rs b/thaw_components/src/css_transition/mod.rs index 5e1a0be..003e464 100644 --- a/thaw_components/src/css_transition/mod.rs +++ b/thaw_components/src/css_transition/mod.rs @@ -1,6 +1,7 @@ use leptos::{ev, html::ElementType, prelude::*}; use std::{ops::Deref, time::Duration}; use thaw_utils::{add_event_listener, EventListenerHandle, NextFrame}; +use web_sys::wasm_bindgen::JsCast; /// # CSS Transition /// @@ -20,80 +21,90 @@ pub fn CSSTransition( children: CF, ) -> impl IntoView where - E: ElementType, - E::Output: 'static, + E: ElementType + 'static, + E::Output: JsCast + Clone + Deref + 'static, CF: FnOnce(ReadSignal>) -> IV + 'static, IV: IntoView, { let display = RwSignal::new((!show.get_untracked()).then_some("display: none;")); - node_ref.on_load(move |node_el| { - let any_el = node_el.clone().into_any(); - let el = any_el.deref().clone(); + Effect::new(move |_| { + let target_ref = node_ref.get(); + let Some(el) = target_ref.as_deref() else { + return; + }; + let class_list = el.class_list(); let next_frame = NextFrame::use_(); let end_handle = StoredValue::new(None::); let end_count = StoredValue::new(None::); let finish = StoredValue::new(None::>); - let on_end = Callback::new(move |remove: Callback<()>| { - let Some(CSSTransitionInfo { - types, - prop_count, - timeout, - }) = get_transition_info(&el) - else { - remove.call(()); - return; - }; + let on_end = Callback::new({ + let el = send_wrapper::SendWrapper::new(el.clone()); + move |remove: Callback<()>| { + let Some(CSSTransitionInfo { + types, + prop_count, + timeout, + }) = get_transition_info(&el) + else { + remove.call(()); + return; + }; - finish.set_value(Some(Callback::new(move |_| { - end_count.set_value(None); - remove.call(()); - end_handle.update_value(|h| { - h.take().map(|h| { - h.remove(); + finish.set_value(Some(Callback::new(move |_| { + end_count.set_value(None); + remove.call(()); + end_handle.update_value(|h| { + h.take().map(|h| { + h.remove(); + }); }); - }); - }))); + }))); - set_timeout( - move || { - finish.try_update_value(|v| { - v.take().map(|f| f.call(())); - }); - }, - Duration::from_millis(timeout + 1), - ); + set_timeout( + move || { + finish.try_update_value(|v| { + v.take().map(|f| f.call(())); + }); + }, + Duration::from_millis(timeout + 1), + ); - end_count.set_value(Some(0)); - let event_listener = move || { - end_count.update_value(|v| { - let Some(v) = v else { - return; - }; - *v += 1; - }); - if end_count.with_value(|v| { - let Some(v) = v else { - return false; - }; - *v >= prop_count - }) { - finish.update_value(|v| { - v.take().map(|f| f.call(())); + end_count.set_value(Some(0)); + let event_listener = move || { + end_count.update_value(|v| { + let Some(v) = v else { + return; + }; + *v += 1; }); - } - }; - let handle = match types { - AnimationTypes::Transition => { - add_event_listener(any_el.clone(), ev::transitionend, move |_| event_listener()) - } - AnimationTypes::Animation => { - add_event_listener(any_el.clone(), ev::animationend, move |_| event_listener()) - } - }; - end_handle.set_value(Some(handle)); + if end_count.with_value(|v| { + let Some(v) = v else { + return false; + }; + *v >= prop_count + }) { + finish.update_value(|v| { + v.take().map(|f| f.call(())); + }); + } + }; + let handle = match types { + AnimationTypes::Transition => { + add_event_listener(el.deref().clone(), ev::transitionend, move |_| { + event_listener() + }) + } + AnimationTypes::Animation => { + add_event_listener(el.deref().clone(), ev::animationend, move |_| { + event_listener() + }) + } + }; + end_handle.set_value(Some(handle)); + } }); let on_finish = move || { @@ -104,8 +115,13 @@ where let on_enter_fn = { let class_list = class_list.clone(); + let class_list = send_wrapper::SendWrapper::new(class_list); + let on_before_enter = on_before_enter.clone(); + let on_after_enter = on_after_enter.clone(); + let on_enter = on_enter.clone(); + let on_end = on_end.clone(); Callback::new(move |name: String| { - if let Some(on_before_enter) = on_before_enter { + if let Some(on_before_enter) = on_before_enter.as_ref() { on_before_enter.call(()); } let enter_from = format!("{name}-enter-from"); @@ -116,13 +132,16 @@ where display.set(None); let class_list = class_list.clone(); + let on_after_enter = on_after_enter.clone(); + let on_end = on_end.clone(); + let on_enter = on_enter.clone(); next_frame.run(move || { let _ = class_list.remove_1(&enter_from); let _ = class_list.add_1(&enter_to); let remove = Callback::new(move |_| { let _ = class_list.remove_2(&enter_active, &enter_to); - if let Some(on_after_enter) = on_after_enter { + if let Some(on_after_enter) = on_after_enter.as_ref() { on_after_enter.call(()); } }); @@ -137,8 +156,13 @@ where let on_leave_fn = { let class_list = class_list.clone(); + let class_list = send_wrapper::SendWrapper::new(class_list); + let on_before_leave = on_before_leave.clone(); + let on_after_leave = on_after_leave.clone(); + let on_leave = on_leave.clone(); + let on_end = on_end.clone(); Callback::new(move |name: String| { - if let Some(on_before_leave) = on_before_leave { + if let Some(on_before_leave) = on_before_leave.as_ref() { on_before_leave.call(()); } let leave_from = format!("{name}-leave-from"); @@ -148,6 +172,9 @@ where let _ = class_list.add_2(&leave_from, &leave_active); let class_list = class_list.clone(); + let on_after_leave = on_after_leave.clone(); + let on_end = on_end.clone(); + let on_leave = on_leave.clone(); next_frame.run(move || { let _ = class_list.remove_1(&leave_from); let _ = class_list.add_1(&leave_to); @@ -155,7 +182,7 @@ where let remove = Callback::new(move |_| { let _ = class_list.remove_2(&leave_active, &leave_to); display.set(Some("display: none;")); - if let Some(on_after_leave) = on_after_leave { + if let Some(on_after_leave) = on_after_leave.as_ref() { on_after_leave.call(()); } }); @@ -167,6 +194,7 @@ where }) }; + let name = name.clone(); RenderEffect::new(move |prev: Option| { let show = show.get(); let prev = if let Some(prev) = prev { @@ -214,7 +242,7 @@ struct CSSTransitionInfo { timeout: u64, } -fn get_transition_info(el: &web_sys::HtmlElement) -> Option { +fn get_transition_info(el: &web_sys::Element) -> Option { let styles = window().get_computed_style(el).ok().flatten()?; let get_style_properties = |property: &str| { diff --git a/thaw_components/src/if_comp.rs b/thaw_components/src/if_comp.rs index e253323..e124d62 100644 --- a/thaw_components/src/if_comp.rs +++ b/thaw_components/src/if_comp.rs @@ -21,13 +21,13 @@ pub fn If( ) -> impl IntoView { move || { if cond.get() { - (then.children)().into_view() + (then.children)().into_any() } else if let Some(else_if) = else_if.iter().find(|i| i.cond.get()) { - (else_if.children)().into_view() + (else_if.children)().into_any() } else if let Some(fallback) = &fallback { - (fallback.children)().into_view() + (fallback.children)().into_any() } else { - ().into_view() + ().into_any() } } } diff --git a/thaw_components/src/option_comp.rs b/thaw_components/src/option_comp.rs index 52e2206..34b73eb 100644 --- a/thaw_components/src/option_comp.rs +++ b/thaw_components/src/option_comp.rs @@ -1,5 +1,5 @@ use super::Fallback; -use leptos::*; +use leptos::{prelude::*, tachys::view::any_view::IntoAny}; #[component] pub fn OptionComp( @@ -9,13 +9,13 @@ pub fn OptionComp( ) -> impl IntoView where CF: FnOnce(T) -> IV + 'static, - IV: IntoView, + IV: IntoView + 'static, { if let Some(value) = value { - children(value).into_view() + children(value).into_any() } else if let Some(fallback) = fallback { - (fallback.children)().into_view() + (fallback.children)().into_any() } else { - ().into_view() - } + ().into_any() + }; } diff --git a/thaw_utils/src/dom/get_scroll_parent.rs b/thaw_utils/src/dom/get_scroll_parent.rs index 203c4de..9b977c8 100644 --- a/thaw_utils/src/dom/get_scroll_parent.rs +++ b/thaw_utils/src/dom/get_scroll_parent.rs @@ -1,55 +1,53 @@ -// use leptos::{ -// html::{AnyElement, ToHtmlElement}, -// *, -// }; +use leptos::prelude::*; +use web_sys::Element; -// pub fn get_scroll_parent(element: &HtmlElement) -> Option> { -// let Some(parent_element) = get_parent_element(element) else { -// return None; -// }; +pub fn get_scroll_parent(element: &Element) -> Option { + let Some(parent_element) = get_parent_element(element) else { + return None; + }; -// if parent_element.node_type() == 9 { -// return Some(parent_element); -// } + if parent_element.node_type() == 9 { + return Some(parent_element); + } -// if parent_element.node_type() == 1 { -// if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { -// let overflow = format!("{overflow}{overflow_x}{overflow_y}"); -// if overflow.contains("auto") { -// return Some(parent_element); -// } -// if overflow.contains("scroll") { -// return Some(parent_element); -// } -// if overflow.contains("overlay") { -// return Some(parent_element); -// } -// } -// } + if parent_element.node_type() == 1 { + if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { + let overflow = format!("{overflow}{overflow_x}{overflow_y}"); + if overflow.contains("auto") { + return Some(parent_element); + } + if overflow.contains("scroll") { + return Some(parent_element); + } + if overflow.contains("overlay") { + return Some(parent_element); + } + } + } -// get_scroll_parent(&parent_element) -// } + get_scroll_parent(&parent_element) +} -// fn get_parent_element(element: &HtmlElement) -> Option> { -// if element.node_type() == 9 { -// None -// } else { -// element.parent_element().map(|ele| ele.to_leptos_element()) -// } -// } +fn get_parent_element(element: &Element) -> Option { + if element.node_type() == 9 { + None + } else { + element.parent_element() + } +} -// fn get_overflow(parent_element: &HtmlElement) -> Option<(String, String, String)> { -// let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) else { -// return None; -// }; -// let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { -// return None; -// }; -// let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { -// return None; -// }; -// let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { -// return None; -// }; -// Some((overflow, overflow_x, overflow_y)) -// } +fn get_overflow(parent_element: &Element) -> Option<(String, String, String)> { + let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) else { + return None; + }; + let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { + return None; + }; + let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { + return None; + }; + let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { + return None; + }; + Some((overflow, overflow_x, overflow_y)) +} diff --git a/thaw_utils/src/dom/mod.rs b/thaw_utils/src/dom/mod.rs index 5bfba60..c5e3111 100644 --- a/thaw_utils/src/dom/mod.rs +++ b/thaw_utils/src/dom/mod.rs @@ -1,5 +1,5 @@ mod get_scroll_parent; mod mount_style; -// pub use get_scroll_parent::get_scroll_parent; +pub use get_scroll_parent::get_scroll_parent; pub use mount_style::{mount_dynamic_style, mount_style}; diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index 9b1d1f4..485d2d0 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,9 +1,9 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; -use leptos::{ev, tachys::renderer::DomRenderer}; -use web_sys::EventTarget; +use leptos::ev; +use web_sys::{Element, EventTarget}; pub fn add_event_listener( - target: impl DomRenderer, + target: Element, event: E, cb: impl Fn(E::EventType) + 'static, ) -> EventListenerHandle @@ -11,13 +11,12 @@ where E: ev::EventDescriptor + 'static, E::EventType: JsCast, { - todo!() - // add_event_listener_untyped(target, &event.name(), move |e| { - // cb(e.unchecked_into::()) - // }) + add_event_listener_untyped(target, &event.name(), move |e| { + cb(e.unchecked_into::()) + }) } -pub struct EventListenerHandle(Box); +pub struct EventListenerHandle(Box); impl std::fmt::Debug for EventListenerHandle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -27,30 +26,36 @@ impl std::fmt::Debug for EventListenerHandle { impl EventListenerHandle { pub fn remove(self) { - (self.0)() + (self.0)(); } } -// fn add_event_listener_untyped( -// target: impl DomRenderer, -// event_name: &str, -// cb: impl Fn(web_sys::Event) + 'static, -// ) -> EventListenerHandle { -// fn wel( -// target: impl DomRenderer, -// cb: Box, -// event_name: &str, -// ) -> EventListenerHandle { -// let cb = Closure::wrap(cb).into_js_value(); -// _ = target.add_event_listener_with_callback(event_name, cb.unchecked_ref()); -// let event_name = event_name.to_string(); -// EventListenerHandle(Box::new(move || { -// _ = target.remove_event_listener_with_callback(&event_name, cb.unchecked_ref()); -// })) -// } +fn add_event_listener_untyped( + target: Element, + event_name: &str, + cb: impl Fn(web_sys::Event) + 'static, +) -> EventListenerHandle { + fn wel( + target: Element, + cb: Box, + event_name: &str, + ) -> EventListenerHandle { + let cb = Closure::wrap(cb); + _ = target.add_event_listener_with_callback(event_name, cb.as_ref().unchecked_ref()); -// wel(target, Box::new(cb), event_name) -// } + EventListenerHandle({ + let event_name = event_name.to_string(); + let cb = send_wrapper::SendWrapper::new(cb); + let target = send_wrapper::SendWrapper::new(target); + Box::new(move || { + let _ = target + .remove_event_listener_with_callback(&event_name, cb.as_ref().unchecked_ref()); + }) + }) + } + + wel(target, Box::new(cb), event_name) +} pub fn add_event_listener_with_bool( target: impl IntoEventTarget, @@ -87,14 +92,19 @@ fn add_event_listener_untyped_with_bool( cb.unchecked_ref(), use_capture, ); - let event_name = event_name.to_string(); - EventListenerHandle(Box::new(move || { - _ = target.remove_event_listener_with_callback_and_bool( - &event_name, - cb.unchecked_ref(), - use_capture, - ); - })) + + EventListenerHandle({ + let event_name = event_name.to_string(); + let cb = send_wrapper::SendWrapper::new(cb); + let target = send_wrapper::SendWrapper::new(target); + Box::new(move || { + let _ = target.remove_event_listener_with_callback_and_bool( + &event_name, + cb.unchecked_ref(), + use_capture, + ); + }) + }) } wel(target, Box::new(cb), event_name, use_capture) diff --git a/thaw_utils/src/lib.rs b/thaw_utils/src/lib.rs index 2bdd211..fe39c01 100644 --- a/thaw_utils/src/lib.rs +++ b/thaw_utils/src/lib.rs @@ -7,7 +7,7 @@ mod signals; mod throttle; mod time; -pub use dom::{mount_dynamic_style, mount_style}; +pub use dom::*; pub use event_listener::{add_event_listener, add_event_listener_with_bool, EventListenerHandle}; pub use hooks::{use_click_position, use_lock_html_scroll, NextFrame}; pub use optional_prop::OptionalProp; From 5f74f5914eec07e972d96dcedb6a9d1f9b18cc30 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 3 Jul 2024 23:01:57 +0800 Subject: [PATCH 080/143] feat(lepots-v0.7): thaw_components --- thaw/Cargo.toml | 2 +- thaw/src/accordion/accordion_item.rs | 8 ++++---- thaw/src/accordion/mod.rs | 2 +- thaw_components/src/binder/mod.rs | 15 +++++++++------ thaw_components/src/css_transition/mod.rs | 19 ++++++++++--------- thaw_components/src/focus_trap/mod.rs | 1 + thaw_components/src/teleport/mod.rs | 4 ++-- 7 files changed, 28 insertions(+), 23 deletions(-) diff --git a/thaw/Cargo.toml b/thaw/Cargo.toml index 6f96b64..03a522c 100644 --- a/thaw/Cargo.toml +++ b/thaw/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -leptos = { version = "0.6.10" } +leptos = { workspace = true } thaw_components = { workspace = true } thaw_macro = { workspace = true } thaw_utils = { workspace = true } diff --git a/thaw/src/accordion/accordion_item.rs b/thaw/src/accordion/accordion_item.rs index 58ac2ce..b490d2a 100644 --- a/thaw/src/accordion/accordion_item.rs +++ b/thaw/src/accordion/accordion_item.rs @@ -1,5 +1,5 @@ use crate::AccordionInjection; -use leptos::*; +use leptos::{prelude::*, html}; use thaw_components::CSSTransition; use thaw_utils::{mount_style, StoredMaybeSignal}; @@ -43,7 +43,7 @@ pub fn AccordionItem(
    } } diff --git a/thaw/src/layout/layout_header.rs b/thaw/src/layout/layout_header.rs index 075bb3f..1c75ace 100644 --- a/thaw/src/layout/layout_header.rs +++ b/thaw/src/layout/layout_header.rs @@ -1,15 +1,9 @@ use leptos::prelude::*; -use thaw_utils::{class_list, OptionalProp}; #[component] -pub fn LayoutHeader( - #[prop(optional, into)] class: OptionalProp>, - children: Children, -) -> impl IntoView { +pub fn LayoutHeader(children: Children) -> impl IntoView { view! { -
    +
    {children()}
    } diff --git a/thaw/src/layout/layout_sider.rs b/thaw/src/layout/layout_sider.rs index 20ebbcf..744fc11 100644 --- a/thaw/src/layout/layout_sider.rs +++ b/thaw/src/layout/layout_sider.rs @@ -1,19 +1,16 @@ use crate::Scrollbar; use leptos::prelude::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_utils::{mount_style, OptionalProp}; #[component] pub fn LayoutSider( - #[prop(optional, into)] class: OptionalProp>, #[prop(optional, into)] content_class: OptionalProp>, #[prop(optional, into)] content_style: OptionalProp>, children: Children, ) -> impl IntoView { mount_style("layout-sider", include_str!("./layout-sider.css")); view! { -
    +
    {children()} diff --git a/thaw/src/layout/mod.rs b/thaw/src/layout/mod.rs index 1d2043e..c1a6ce8 100644 --- a/thaw/src/layout/mod.rs +++ b/thaw/src/layout/mod.rs @@ -6,7 +6,7 @@ pub use layout_sider::*; use crate::Scrollbar; use leptos::prelude::*; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use thaw_utils::{mount_style, OptionalProp}; #[derive(Default, PartialEq)] pub enum LayoutPosition { @@ -26,7 +26,6 @@ impl LayoutPosition { #[component] pub fn Layout( - #[prop(optional, into)] class: OptionalProp>, #[prop(optional, into)] content_class: OptionalProp>, #[prop(optional, into)] content_style: OptionalProp>, #[prop(optional)] position: LayoutPosition, @@ -43,9 +42,7 @@ pub fn Layout( } }); view! { -
    +
    Self::State { - let class_list = R::class_list(el); let mut class = String::new(); self.to_class_string(&mut class); if !class.is_empty() { - R::add_class(&class_list, &class); + R::set_attribute(el, "class", &class); } - (class_list, class) + (el.clone(), class) } fn rebuild(self, state: &mut Self::State) { let mut class = String::new(); self.to_class_string(&mut class); - let (class_list, prev_class) = state; + let (el, prev_class) = state; if class != *prev_class { - R::remove_class(class_list, prev_class); - R::add_class(class_list, &class); + R::set_attribute(el, "class", &class); } *prev_class = class; } From 5188f95704cc331be52fa3f80e233e4eaffcc8ef Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 8 Jul 2024 00:04:07 +0800 Subject: [PATCH 087/143] feat(lepots-v0.7): demo Guide page --- demo/src/app.rs | 132 +++++++++---------- demo/src/components/site_header.rs | 195 ++++++++++++++-------------- demo/src/lib.rs | 2 +- demo/src/main.rs | 2 +- demo/src/pages/components.rs | 4 +- demo/src/pages/mod.rs | 8 +- demo_markdown/docs/space/mod.md | 12 +- demo_markdown/src/lib.rs | 40 +++--- thaw/src/tag/mod.rs | 5 +- thaw/src/text/mod.rs | 36 ++--- thaw_components/src/teleport/mod.rs | 15 ++- 11 files changed, 230 insertions(+), 221 deletions(-) diff --git a/demo/src/app.rs b/demo/src/app.rs index cc411cd..21e78bf 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -2,7 +2,7 @@ use crate::pages::*; use leptos::{prelude::*, reactive_graph::wrappers::write::SignalSetter}; use leptos_meta::provide_meta_context; use leptos_router::{ - components::{Route, Router, Routes}, + components::{ParentRoute, Route, Router, Routes}, StaticSegment, }; // use leptos_use::{ @@ -20,7 +20,7 @@ pub fn App() -> impl IntoView { provide_meta_context(); view! { - + @@ -30,75 +30,75 @@ pub fn App() -> impl IntoView { #[component] fn TheRouter(is_routing: RwSignal) -> impl IntoView { - // let loading_bar = use_loading_bar(); - // _ = is_routing.watch(move |is_routing| { - // if *is_routing { - // loading_bar.start(); - // } else { - // loading_bar.finish(); - // } - // }); + let loading_bar = use_loading_bar(); + _ = is_routing.watch(move |is_routing| { + if *is_routing { + loading_bar.start(); + } else { + loading_bar.finish(); + } + }); view! { - // - // - // - // - // - // - // - // + + + + + + + + // // // // // // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // // - // - // - // - // - // - // // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // + // + // + // + // + // + // + // + + + + + + + + + + + + + // + // + // + // + // + // + // + // + // + // + // + // // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // // // @@ -114,9 +114,9 @@ fn TheProvider(children: Children) -> impl IntoView { view! { // - // + {children()} - // + // } diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index e53e721..28e69a0 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -7,26 +7,26 @@ use thaw::*; #[component] pub fn SiteHeader() -> impl IntoView { - let theme = Theme::use_rw_theme(); - let theme_name = Memo::new(move |_| { - theme.with(|theme| { - if theme.name == *"light" { - "Dark".to_string() - } else { - "Light".to_string() - } - }) - }); - // let (_, write_theme, _) = use_local_storage::("theme"); - let change_theme = Callback::new(move |_| { - if theme_name.get_untracked() == "Light" { - theme.set(Theme::light()); - // write_theme.set("light".to_string()); - } else { - theme.set(Theme::dark()); - // write_theme.set("dark".to_string()); - } - }); + // let theme = Theme::use_rw_theme(); + // let theme_name = Memo::new(move |_| { + // theme.with(|theme| { + // if theme.name == *"light" { + // "Dark".to_string() + // } else { + // "Light".to_string() + // } + // }) + // }); + // // let (_, write_theme, _) = use_local_storage::("theme"); + // let change_theme = Callback::new(move |_| { + // if theme_name.get_untracked() == "Light" { + // theme.set(Theme::light()); + // // write_theme.set("light".to_string()); + // } else { + // theme.set(Theme::dark()); + // // write_theme.set("dark".to_string()); + // } + // }); let search_value = RwSignal::new(String::new()); let search_all_options = StoredValue::new(gen_search_all_options()); @@ -130,85 +130,86 @@ pub fn SiteHeader() -> impl IntoView { } " - - - -
    "Thaw UI"
    -
    - - - - {option.label} - - - - - - - - - - + // + //
    - + diff --git a/demo/src/pages/mod.rs b/demo/src/pages/mod.rs index 64ee266..763083c 100644 --- a/demo/src/pages/mod.rs +++ b/demo/src/pages/mod.rs @@ -1,14 +1,14 @@ -// mod components; +mod components; mod home; -// mod markdown; +mod markdown; // mod mobile; // mod nav_bar; // mod tabbar; // mod toast; -// pub use components::*; +pub use components::*; pub use home::*; -// pub use markdown::*; +pub use markdown::*; // pub use mobile::*; // pub use nav_bar::*; // pub use tabbar::*; diff --git a/demo_markdown/docs/space/mod.md b/demo_markdown/docs/space/mod.md index 0749b60..84b0756 100644 --- a/demo_markdown/docs/space/mod.md +++ b/demo_markdown/docs/space/mod.md @@ -45,18 +45,18 @@ view! { view! { - - + + - - + + - - + + diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index f2e1252..8c303fe 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -54,26 +54,26 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "LayoutMdPage" => "../docs/layout/mod.md", "LoadingBarMdPage" => "../docs/loading_bar/mod.md", // "MessageMdPage" => "../docs/message/mod.md", - "MessageBarMdPage" => "../docs/message_bar/mod.md", - "PopoverMdPage" => "../docs/popover/mod.md", - "ProgressBarMdPage" => "../docs/progress_bar/mod.md", - "RadioMdPage" => "../docs/radio/mod.md", - "ScrollbarMdPage" => "../docs/scrollbar/mod.md", - // "SelectMdPage" => "../docs/select/mod.md", - "SkeletonMdPage" => "../docs/skeleton/mod.md", - "SliderMdPage" => "../docs/slider/mod.md", - "SpaceMdPage" => "../docs/space/mod.md", - "SpinButtonMdPage" => "../docs/spin_button/mod.md", - "SpinnerMdPage" => "../docs/spinner/mod.md", - "SwitchMdPage" => "../docs/switch/mod.md", - "TabListMdPage" => "../docs/tab_list/mod.md", - "TableMdPage" => "../docs/table/mod.md", - "TagMdPage" => "../docs/tag/mod.md", - "TextareaMdPage" => "../docs/textarea/mod.md", - "TimePickerMdPage" => "../docs/time_picker/mod.md", - "TextMdPage" => "../docs/text/mod.md", - "ToastMdPage" => "../docs/toast/mod.md", - "UploadMdPage" => "../docs/upload/mod.md" + "MessageBarMdPage" => "../docs/message_bar/mod.md" + // "PopoverMdPage" => "../docs/popover/mod.md", + // "ProgressBarMdPage" => "../docs/progress_bar/mod.md", + // "RadioMdPage" => "../docs/radio/mod.md", + // "ScrollbarMdPage" => "../docs/scrollbar/mod.md", + // // "SelectMdPage" => "../docs/select/mod.md", + // "SkeletonMdPage" => "../docs/skeleton/mod.md", + // "SliderMdPage" => "../docs/slider/mod.md", + // "SpaceMdPage" => "../docs/space/mod.md", + // "SpinButtonMdPage" => "../docs/spin_button/mod.md", + // "SpinnerMdPage" => "../docs/spinner/mod.md", + // "SwitchMdPage" => "../docs/switch/mod.md", + // "TabListMdPage" => "../docs/tab_list/mod.md", + // "TableMdPage" => "../docs/table/mod.md", + // "TagMdPage" => "../docs/tag/mod.md", + // "TextareaMdPage" => "../docs/textarea/mod.md", + // "TimePickerMdPage" => "../docs/time_picker/mod.md", + // "TextMdPage" => "../docs/text/mod.md", + // "ToastMdPage" => "../docs/toast/mod.md", + // "UploadMdPage" => "../docs/upload/mod.md" }; let mut fn_list = vec![]; diff --git a/thaw/src/tag/mod.rs b/thaw/src/tag/mod.rs index add69dd..dc98f64 100644 --- a/thaw/src/tag/mod.rs +++ b/thaw/src/tag/mod.rs @@ -1,6 +1,7 @@ use crate::Icon; use leptos::{ev, prelude::*}; use thaw_utils::{class_list, mount_style, OptionalProp}; +use send_wrapper::SendWrapper; #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] pub enum TagVariant { @@ -16,7 +17,7 @@ pub fn Tag( #[prop(optional, into)] variant: MaybeSignal, #[prop(optional, into)] class: OptionalProp>, #[prop(optional, into)] closable: MaybeSignal, - #[prop(optional, into)] on_close: Option>, + #[prop(optional, into)] on_close: Option>>, children: Children, ) -> impl IntoView { mount_style("tag", include_str!("./tag.css")); @@ -25,7 +26,7 @@ pub fn Tag( let Some(callback) = on_close.as_ref() else { return; }; - callback.call(event); + callback.call(SendWrapper::new(event)); }; view! { diff --git a/thaw/src/text/mod.rs b/thaw/src/text/mod.rs index 9bb6ef3..0293446 100644 --- a/thaw/src/text/mod.rs +++ b/thaw/src/text/mod.rs @@ -4,6 +4,7 @@ use thaw_utils::{class_list, mount_style}; #[component] pub fn Caption1( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { @@ -11,13 +12,14 @@ pub fn Caption1( Signal::derive(move || format!("thaw-caption-1 {}", class.get().unwrap_or_default())); view! { - + } } #[component] pub fn Caption1Strong( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { @@ -26,26 +28,28 @@ pub fn Caption1Strong( }); view! { - + } } #[component] pub fn Body1( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, children: Children, ) -> impl IntoView { let class = Signal::derive(move || format!("thaw-body-1 {}", class.get().unwrap_or_default())); view! { - + } } #[component] pub fn Text( #[prop(optional, into)] class: MaybeProp, + #[prop(optional, into)] style: MaybeProp, #[prop(optional)] tag: TextTag, #[prop(optional)] code: bool, children: Children, @@ -54,79 +58,79 @@ pub fn Text( match tag { TextTag::B => view! { - + {children()} } .into_any(), TextTag::Em => view! { - + {children()} } .into_any(), TextTag::H1 => view! { -

    +

    {children()}

    } .into_any(), TextTag::H2 => view! { -

    +

    {children()}

    } .into_any(), TextTag::H3 => view! { -

    +

    {children()}

    } .into_any(), TextTag::H4 => view! { -

    +

    {children()}

    } .into_any(), TextTag::H5 => view! { -
    +
    {children()}
    } .into_any(), TextTag::H6 => view! { -
    +
    {children()}
    } .into_any(), TextTag::I => view! { - + {children()} } .into_any(), TextTag::P => view! { -

    +

    {children()}

    } .into_any(), TextTag::Pre => view! { -
    +            
                     {children()}
                 
    } .into_any(), TextTag::Span => view! { - + {children()} } .into_any(), TextTag::Strong => view! { - + {children()} } diff --git a/thaw_components/src/teleport/mod.rs b/thaw_components/src/teleport/mod.rs index dcf6862..06dacdd 100644 --- a/thaw_components/src/teleport/mod.rs +++ b/thaw_components/src/teleport/mod.rs @@ -58,12 +58,15 @@ pub fn Teleport( let owner = Owner::current().unwrap(); Effect::new(move |_| { if immediate.get() { - mount_fn.update_value(|mount_fn| { - if let Some(f) = mount_fn.take() { - owner.with(|| { - f(); - }); - } + let Some(f) = mount_fn + .try_update_value(|mount_fn| mount_fn.take()) + .flatten() + else { + return; + }; + + owner.with(|| { + f(); }); } }); From 9557637496d3725c05901e98496c42c71b18572f Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 8 Jul 2024 00:29:04 +0800 Subject: [PATCH 088/143] feat(lepots-v0.7): demo component --- demo/Cargo.toml | 1 + demo/src/app.rs | 87 ++++++++++++++++++-------------- demo_markdown/docs/upload/mod.md | 8 ++- demo_markdown/src/lib.rs | 28 +++++----- thaw/src/upload/mod.rs | 2 +- 5 files changed, 72 insertions(+), 54 deletions(-) diff --git a/demo/Cargo.toml b/demo/Cargo.toml index 2dab5ad..c0d5382 100644 --- a/demo/Cargo.toml +++ b/demo/Cargo.toml @@ -17,6 +17,7 @@ palette = "0.7.4" chrono = "0.4.33" cfg-if = "1.0.0" leptos-use = "0.10.10" +send_wrapper = "0.6" [features] default = ["csr"] diff --git a/demo/src/app.rs b/demo/src/app.rs index 21e78bf..16e3485 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -50,46 +50,59 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + // // // // // // - // - // - // - // - // - // - // - - - - - - - - - - - - - // - // - // - // - // - // - // - // - // - // - // - // // - // - // - // - // - // - // + { + view! { + + + + + + + + + + + + + + + } + } + { + view! { + + + + + + + + + + + // + + + + + } + } + { + view! { + + // + + + + + + + } + } // // // diff --git a/demo_markdown/docs/upload/mod.md b/demo_markdown/docs/upload/mod.md index b334827..15351f9 100644 --- a/demo_markdown/docs/upload/mod.md +++ b/demo_markdown/docs/upload/mod.md @@ -1,8 +1,10 @@ # Upload ```rust demo +use send_wrapper::SendWrapper; + let message = use_message(); -let custom_request = move |file_list| { +let custom_request = move |file_list: SendWrapper| { message.create( format!("Number of uploaded files: {}", file_list.length()), MessageVariant::Success, @@ -22,8 +24,10 @@ view!{ ### Drag to upload ```rust demo +use send_wrapper::SendWrapper; + let message = use_message(); -let custom_request = move |file_list| { +let custom_request = move |file_list: SendWrapper| { message.create( format!("Number of uploaded files: {}", file_list.length()), MessageVariant::Success, diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 8c303fe..4c55683 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -54,26 +54,26 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "LayoutMdPage" => "../docs/layout/mod.md", "LoadingBarMdPage" => "../docs/loading_bar/mod.md", // "MessageMdPage" => "../docs/message/mod.md", - "MessageBarMdPage" => "../docs/message_bar/mod.md" - // "PopoverMdPage" => "../docs/popover/mod.md", - // "ProgressBarMdPage" => "../docs/progress_bar/mod.md", - // "RadioMdPage" => "../docs/radio/mod.md", - // "ScrollbarMdPage" => "../docs/scrollbar/mod.md", - // // "SelectMdPage" => "../docs/select/mod.md", - // "SkeletonMdPage" => "../docs/skeleton/mod.md", - // "SliderMdPage" => "../docs/slider/mod.md", - // "SpaceMdPage" => "../docs/space/mod.md", - // "SpinButtonMdPage" => "../docs/spin_button/mod.md", - // "SpinnerMdPage" => "../docs/spinner/mod.md", - // "SwitchMdPage" => "../docs/switch/mod.md", + "MessageBarMdPage" => "../docs/message_bar/mod.md", + "PopoverMdPage" => "../docs/popover/mod.md", + "ProgressBarMdPage" => "../docs/progress_bar/mod.md", + "RadioMdPage" => "../docs/radio/mod.md", + "ScrollbarMdPage" => "../docs/scrollbar/mod.md", + // "SelectMdPage" => "../docs/select/mod.md", + "SkeletonMdPage" => "../docs/skeleton/mod.md", + "SliderMdPage" => "../docs/slider/mod.md", + "SpaceMdPage" => "../docs/space/mod.md", + "SpinButtonMdPage" => "../docs/spin_button/mod.md", + "SpinnerMdPage" => "../docs/spinner/mod.md", + "SwitchMdPage" => "../docs/switch/mod.md" // "TabListMdPage" => "../docs/tab_list/mod.md", // "TableMdPage" => "../docs/table/mod.md", // "TagMdPage" => "../docs/tag/mod.md", // "TextareaMdPage" => "../docs/textarea/mod.md", // "TimePickerMdPage" => "../docs/time_picker/mod.md", // "TextMdPage" => "../docs/text/mod.md", - // "ToastMdPage" => "../docs/toast/mod.md", - // "UploadMdPage" => "../docs/upload/mod.md" + // // "ToastMdPage" => "../docs/toast/mod.md", + // // "UploadMdPage" => "../docs/upload/mod.md" }; let mut fn_list = vec![]; diff --git a/thaw/src/upload/mod.rs b/thaw/src/upload/mod.rs index 145a586..3cdcc8f 100644 --- a/thaw/src/upload/mod.rs +++ b/thaw/src/upload/mod.rs @@ -11,7 +11,7 @@ use thaw_utils::{add_event_listener, mount_style}; pub fn Upload( #[prop(optional, into)] accept: MaybeSignal, #[prop(optional, into)] multiple: MaybeSignal, - #[prop(optional, into)] custom_request: Option, ()>>, + #[prop(optional, into)] custom_request: Option>>, children: Children, ) -> impl IntoView { mount_style("upload", include_str!("./upload.css")); From 27e4e7ebfd763195ed2fa7475966607be615561a Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 8 Jul 2024 12:01:05 +0800 Subject: [PATCH 089/143] feat(leptos-v0.7): demo --- demo/Cargo.toml | 8 ++++---- demo/src/app.rs | 16 ++++++++-------- demo/src/pages/markdown.rs | 2 +- demo_markdown/docs/tag/mod.md | 15 ++++++++------- demo_markdown/docs/upload/mod.md | 12 ++++++------ demo_markdown/src/lib.rs | 18 +++++++++--------- thaw/src/tag/mod.rs | 11 +++++------ 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/demo/Cargo.toml b/demo/Cargo.toml index c0d5382..7c357c5 100644 --- a/demo/Cargo.toml +++ b/demo/Cargo.toml @@ -32,8 +32,8 @@ nightly = ["leptos/nightly", "leptos_router/nightly"] # https://benw.is/posts/how-i-improved-my-rust-compile-times-by-seventy-five-percent#optimization-level -[profile.dev] -opt-level = 1 +# [profile.dev] +# opt-level = 1 -[profile.dev.package."*"] -opt-level = 3 +# [profile.dev.package."*"] +# opt-level = 3 diff --git a/demo/src/app.rs b/demo/src/app.rs index 16e3485..1b483a7 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -103,14 +103,14 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { } } - // - // - // - // - // - // - // - // + + + + + + + + // // diff --git a/demo/src/pages/markdown.rs b/demo/src/pages/markdown.rs index 56088e9..6d4235c 100644 --- a/demo/src/pages/markdown.rs +++ b/demo/src/pages/markdown.rs @@ -1,5 +1,5 @@ use crate::components::{Demo, DemoCode}; -use leptos::prelude::*; +use leptos::{ev, prelude::*}; use thaw::*; demo_markdown::include_md! {} diff --git a/demo_markdown/docs/tag/mod.md b/demo_markdown/docs/tag/mod.md index 6d539c0..b1416ea 100644 --- a/demo_markdown/docs/tag/mod.md +++ b/demo_markdown/docs/tag/mod.md @@ -14,13 +14,14 @@ view! { ### Closable ```rust demo -let message = use_message(); -let success = move |_| { - message.create( - "tag close".into(), - MessageVariant::Success, - Default::default(), - ); +use send_wrapper::SendWrapper; +// let message = use_message(); +let success = move |_: SendWrapper| { + // message.create( + // "tag close".into(), + // MessageVariant::Success, + // Default::default(), + // ); }; view! { diff --git a/demo_markdown/docs/upload/mod.md b/demo_markdown/docs/upload/mod.md index 15351f9..ad4ef07 100644 --- a/demo_markdown/docs/upload/mod.md +++ b/demo_markdown/docs/upload/mod.md @@ -3,13 +3,13 @@ ```rust demo use send_wrapper::SendWrapper; -let message = use_message(); +// let message = use_message(); let custom_request = move |file_list: SendWrapper| { - message.create( - format!("Number of uploaded files: {}", file_list.length()), - MessageVariant::Success, - Default::default(), - ); + // message.create( + // format!("Number of uploaded files: {}", file_list.length()), + // MessageVariant::Success, + // Default::default(), + // ); }; view!{ diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 4c55683..55a7757 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -65,15 +65,15 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "SpaceMdPage" => "../docs/space/mod.md", "SpinButtonMdPage" => "../docs/spin_button/mod.md", "SpinnerMdPage" => "../docs/spinner/mod.md", - "SwitchMdPage" => "../docs/switch/mod.md" - // "TabListMdPage" => "../docs/tab_list/mod.md", - // "TableMdPage" => "../docs/table/mod.md", - // "TagMdPage" => "../docs/tag/mod.md", - // "TextareaMdPage" => "../docs/textarea/mod.md", - // "TimePickerMdPage" => "../docs/time_picker/mod.md", - // "TextMdPage" => "../docs/text/mod.md", - // // "ToastMdPage" => "../docs/toast/mod.md", - // // "UploadMdPage" => "../docs/upload/mod.md" + "SwitchMdPage" => "../docs/switch/mod.md", + "TabListMdPage" => "../docs/tab_list/mod.md", + "TableMdPage" => "../docs/table/mod.md", + "TagMdPage" => "../docs/tag/mod.md", + "TextMdPage" => "../docs/text/mod.md", + "TextareaMdPage" => "../docs/textarea/mod.md", + "TimePickerMdPage" => "../docs/time_picker/mod.md", + "ToastMdPage" => "../docs/toast/mod.md", + "UploadMdPage" => "../docs/upload/mod.md" }; let mut fn_list = vec![]; diff --git a/thaw/src/tag/mod.rs b/thaw/src/tag/mod.rs index dc98f64..e273cd2 100644 --- a/thaw/src/tag/mod.rs +++ b/thaw/src/tag/mod.rs @@ -1,7 +1,7 @@ use crate::Icon; -use leptos::{ev, prelude::*}; -use thaw_utils::{class_list, mount_style, OptionalProp}; +use leptos::{either::Either, ev, prelude::*}; use send_wrapper::SendWrapper; +use thaw_utils::{class_list, mount_style, OptionalProp}; #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] pub enum TagVariant { @@ -38,16 +38,15 @@ pub fn Tag( {move || { if closable.get() { - view! { + Either::Left(view! { - } - .into() + }) } else { - None + Either::Right(()) } }} From d1909554c42daa09d89a4d0cb98c3ebb1a863411 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 8 Jul 2024 14:40:17 +0800 Subject: [PATCH 090/143] feat(leptos-v0.7): demo --- demo/Trunk.toml | 2 +- demo/src/components/site_header.rs | 195 +++++++++--------- demo/src/pages/components.rs | 2 +- demo_markdown/docs/button/mod.md | 4 +- demo_markdown/docs/input/mod.md | 8 +- demo_markdown/docs/textarea/mod.md | 8 +- demo_markdown/docs/upload/mod.md | 12 +- .../src/auto_complete/auto_complete_option.rs | 2 +- thaw/src/lib.rs | 2 - thaw/src/space/mod.rs | 57 +++-- thaw/src/tag/mod.rs | 1 - thaw_components/src/css_transition/mod.rs | 3 +- thaw_utils/src/class_list.rs | 6 +- thaw_utils/src/hooks/use_lock_html_scroll.rs | 2 +- 14 files changed, 151 insertions(+), 153 deletions(-) diff --git a/demo/Trunk.toml b/demo/Trunk.toml index 3b9db18..acbe41f 100644 --- a/demo/Trunk.toml +++ b/demo/Trunk.toml @@ -1,7 +1,7 @@ [build] target = "index.html" # public_url = "/thaw/" -# release = true +release = true # filehash = false [watch] diff --git a/demo/src/components/site_header.rs b/demo/src/components/site_header.rs index 28e69a0..1b285a7 100644 --- a/demo/src/components/site_header.rs +++ b/demo/src/components/site_header.rs @@ -7,26 +7,26 @@ use thaw::*; #[component] pub fn SiteHeader() -> impl IntoView { - // let theme = Theme::use_rw_theme(); - // let theme_name = Memo::new(move |_| { - // theme.with(|theme| { - // if theme.name == *"light" { - // "Dark".to_string() - // } else { - // "Light".to_string() - // } - // }) - // }); - // // let (_, write_theme, _) = use_local_storage::("theme"); - // let change_theme = Callback::new(move |_| { - // if theme_name.get_untracked() == "Light" { - // theme.set(Theme::light()); - // // write_theme.set("light".to_string()); - // } else { - // theme.set(Theme::dark()); - // // write_theme.set("dark".to_string()); - // } - // }); + let theme = Theme::use_rw_theme(); + let theme_name = Memo::new(move |_| { + theme.with(|theme| { + if theme.name == *"light" { + "Dark".to_string() + } else { + "Light".to_string() + } + }) + }); + // let (_, write_theme, _) = use_local_storage::("theme"); + let change_theme = Callback::new(move |_| { + if theme_name.get_untracked() == "Light" { + theme.set(Theme::light()); + // write_theme.set("light".to_string()); + } else { + theme.set(Theme::dark()); + // write_theme.set("dark".to_string()); + } + }); let search_value = RwSignal::new(String::new()); let search_all_options = StoredValue::new(gen_search_all_options()); @@ -130,86 +130,85 @@ pub fn SiteHeader() -> impl IntoView { } " - - "123" - // - // - //
    "Thaw UI"
    - //
    - // - // - // - // {option.label} - // - // - // - // - // - // - // - // - // - // + +
    - + diff --git a/demo_markdown/docs/button/mod.md b/demo_markdown/docs/button/mod.md index 1075b52..23d4fe5 100644 --- a/demo_markdown/docs/button/mod.md +++ b/demo_markdown/docs/button/mod.md @@ -138,9 +138,7 @@ view! { ```rust demo view! { - - - + } ``` diff --git a/demo_markdown/docs/input/mod.md b/demo_markdown/docs/input/mod.md index abc7586..63793a9 100644 --- a/demo_markdown/docs/input/mod.md +++ b/demo_markdown/docs/input/mod.md @@ -42,9 +42,7 @@ view! { let value = RwSignal::new(String::from("o")); view! { - - - + } ``` @@ -62,9 +60,7 @@ view! { let value = RwSignal::new(String::from("o")); view! { - - - + } ``` diff --git a/demo_markdown/docs/textarea/mod.md b/demo_markdown/docs/textarea/mod.md index bf8160f..b2a880f 100644 --- a/demo_markdown/docs/textarea/mod.md +++ b/demo_markdown/docs/textarea/mod.md @@ -4,9 +4,7 @@ let value = RwSignal::new(String::from("o")); view! { - -