refactor: card

This commit is contained in:
luoxiao 2024-05-13 17:32:45 +08:00
parent d45f7b908e
commit 246c509b29
11 changed files with 155 additions and 55 deletions

View file

@ -23,9 +23,7 @@ pub fn SiteHeader() -> impl IntoView {
theme.set(Theme::dark()); 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_value = create_rw_signal(String::new());
let search_all_options = store_value(gen_search_all_options()); let search_all_options = store_value(gen_search_all_options());
let search_options = create_memo(move |_| { let search_options = create_memo(move |_| {
@ -88,6 +86,9 @@ pub fn SiteHeader() -> impl IntoView {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 20px; padding: 0 20px;
z-index: 1000;
position: relative;
border-bottom: 1px solid var(--colorNeutralStroke2);
} }
.demo-name { .demo-name {
cursor: pointer; cursor: pointer;
@ -124,7 +125,7 @@ pub fn SiteHeader() -> impl IntoView {
} }
" "
</Style> </Style>
<LayoutHeader class="demo-header" style> <LayoutHeader class="demo-header">
<Space <Space
on:click=move |_| { on:click=move |_| {
let navigate = use_navigate(); let navigate = use_navigate();

View file

@ -62,16 +62,7 @@ pub fn ComponentsPage() -> impl IntoView {
<NavDrawer selected_value=select_name> <NavDrawer selected_value=select_name>
{gen_menu_data().into_view()} {gen_menu_data().into_view()}
<NavDrawerFooter slot>
<Button
appearance=ButtonAppearance::Subtle
icon=icondata::AiGithubOutlined
style="font-size: 22px; padding: 0px 6px;"
on_click=move |_| {
_ = window().open_with_url("http://github.com/thaw-ui/thaw");
}
/>
</NavDrawerFooter>
</NavDrawer> </NavDrawer>
</div> </div>
<Layout content_style="padding: 8px 12px 28px; display: flex;" class="doc-content"> <Layout content_style="padding: 8px 12px 28px; display: flex;" class="doc-content">

View file

@ -18,10 +18,15 @@ pub fn Home() -> impl IntoView {
<h1 style="font-size: 80px; line-height: 1;margin: 0 0 18px;">"Thaw UI"</h1> <h1 style="font-size: 80px; line-height: 1;margin: 0 0 18px;">"Thaw UI"</h1>
<p>"An easy to use leptos component library"</p> <p>"An easy to use leptos component library"</p>
<Space> <Space>
<Button on_click=move |_| { <Button
appearance=ButtonAppearance::Primary
on_click=move |_| {
let navigate = use_navigate(); let navigate = use_navigate();
navigate("/components/button", Default::default()); navigate("/components/button", Default::default());
}>"Read the docs"</Button> }
>
"Read the docs"
</Button>
<Button <Button
appearance=ButtonAppearance::Subtle appearance=ButtonAppearance::Subtle
on_click=move |_| { on_click=move |_| {

View file

@ -9,7 +9,17 @@ view! {
"content" "content"
</Card> </Card>
<Card title="title"> <Card title="title">
<CardHeader slot>"header"</CardHeader> <CardHeader>
"Header"
<CardHeaderDescription slot>
"Description"
</CardHeaderDescription>
<CardHeaderAction slot>
<Button appearance=ButtonAppearance::Transparent>
"..."
</Button>
</CardHeaderAction>
</CardHeader>
"content" "content"
</Card> </Card>
<Card title="title"> <Card title="title">

View file

@ -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);
}

View file

@ -1,11 +1,24 @@
.thaw-card { .thaw-card {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: 1px solid var(--thaw-border-color);
border-radius: 3px;
overflow: hidden; 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 { .thaw-card__header {
font-weight: 600; font-weight: 600;
display: flex; display: flex;
@ -29,4 +42,4 @@
.thaw-card__header + .thaw-card__content, .thaw-card__header + .thaw-card__content,
.thaw-card__footer { .thaw-card__footer {
padding: 0 28px 20px; padding: 0 28px 20px;
} }

View file

@ -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<CardHeaderDescription>,
#[prop(optional)] card_header_action: Option<CardHeaderAction>,
children: Children,
) -> impl IntoView {
mount_style("card-header", include_str!("./card-header.css"));
view! {
<div class="thaw-card-header">
<div class="thaw-card-header__header">
{children()}
</div>
<OptionComp value=card_header_description let:description>
<div class="thaw-card-header__description">
{(description.children)()}
</div>
</OptionComp>
<OptionComp value=card_header_action let:action>
<div class="thaw-card-header__action">
{(action.children)()}
</div>
</OptionComp>
</div>
}
}
#[slot]
pub struct CardHeaderDescription {
children: Children,
}
#[slot]
pub struct CardHeaderAction {
children: Children,
}

View file

@ -1,12 +1,15 @@
mod card_header;
pub use card_header::*;
use crate::{use_theme, Theme}; use crate::{use_theme, Theme};
use leptos::*; use leptos::*;
use thaw_components::*; use thaw_components::*;
use thaw_utils::{class_list, mount_style, OptionalProp}; use thaw_utils::{class_list, mount_style, OptionalProp};
// #[slot]
#[slot] // pub struct CardHeader {
pub struct CardHeader { // children: Children,
children: Children, // }
}
#[slot] #[slot]
pub struct CardHeaderExtra { pub struct CardHeaderExtra {
@ -23,7 +26,7 @@ pub struct CardFooter {
#[component] #[component]
pub fn Card( pub fn Card(
#[prop(optional, into)] title: OptionalProp<MaybeSignal<String>>, #[prop(optional, into)] title: OptionalProp<MaybeSignal<String>>,
#[prop(optional)] card_header: Option<CardHeader>, // #[prop(optional)] card_header: Option<CardHeader>,
#[prop(optional)] card_header_extra: Option<CardHeaderExtra>, #[prop(optional)] card_header_extra: Option<CardHeaderExtra>,
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>, #[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
children: Children, children: Children,
@ -51,31 +54,32 @@ pub fn Card(
<div <div
class=class_list!["thaw-card", class.map(| c | move || c.get())] class=class_list!["thaw-card", class.map(| c | move || c.get())]
style=move || css_vars.get() style=move || css_vars.get()
role="group"
> >
{if card_header.is_some() || title.is_some() { // {if card_header.is_some() || title.is_some() {
view! { // view! {
<div class="thaw-card__header"> // <div class="thaw-card__header">
<div class="thaw-card__header-content"> // <div class="thaw-card__header-content">
{if let Some(header) = card_header { // {if let Some(header) = card_header {
(header.children)().into_view() // (header.children)().into_view()
} else if let Some(title) = title.into_option() { // } else if let Some(title) = title.into_option() {
(move || title.get()).into_view() // (move || title.get()).into_view()
} else { // } else {
unreachable!() // unreachable!()
}} // }}
</div> // </div>
<OptionComp value=card_header_extra let:header_extra> // <OptionComp value=card_header_extra let:header_extra>
<div class="thaw-card__header-extra">{(header_extra.children)()}</div> // <div class="thaw-card__header-extra">{(header_extra.children)()}</div>
</OptionComp> // </OptionComp>
</div> // </div>
} // }
.into() // .into()
} else { // } else {
None // None
}} // }}
<div class="thaw-card__content">{children()}</div> <div class="thaw-card__content">{children()}</div>
<OptionComp value=card_footer let:footer> <OptionComp value=card_footer let:footer>

View file

@ -113,7 +113,7 @@ pub fn Modal(
style=move || display.get() style=move || display.get()
> >
<Card> <Card>
<CardHeader slot> <CardHeader>
<span class="thaw-model-title">{move || title.get()}</span> <span class="thaw-model-title">{move || title.get()}</span>
</CardHeader> </CardHeader>
<CardHeaderExtra slot> <CardHeaderExtra slot>

View file

@ -2,7 +2,7 @@
overflow: hidden; overflow: hidden;
width: 260px; width: 260px;
max-width: 100vw; max-width: 100vw;
height: auto; height: 100%;
/* max-height: 100vh; */ /* max-height: 100vh; */
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
@ -15,12 +15,18 @@
} }
.thaw-nav-drawer__body { .thaw-nav-drawer__body {
padding: 0 var(--spacingVerticalMNudge); flex: 1;
flex: 1 1 0%;
align-self: stretch; align-self: stretch;
position: relative; position: relative;
z-index: 1; 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 { .thaw-nav-drawer__footer {
@ -67,4 +73,4 @@
background-color: var(--colorNeutralForeground2BrandSelected); background-color: var(--colorNeutralForeground2BrandSelected);
border-radius: var(--borderRadiusCircular); border-radius: var(--borderRadiusCircular);
margin-inline-start: -18px; margin-inline-start: -18px;
} }

View file

@ -45,6 +45,8 @@ pub struct ColorTheme {
pub color_transparent_background: String, pub color_transparent_background: String,
pub color_transparent_background_hover: String, pub color_transparent_background_hover: String,
pub color_transparent_background_pressed: String, pub color_transparent_background_pressed: String,
pub shadow4: String,
} }
impl ColorTheme { impl ColorTheme {
@ -93,6 +95,8 @@ impl ColorTheme {
color_transparent_background: "transparent".into(), color_transparent_background: "transparent".into(),
color_transparent_background_hover: "transparent".into(), color_transparent_background_hover: "transparent".into(),
color_transparent_background_pressed: "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: "transparent".into(),
color_transparent_background_hover: "transparent".into(), color_transparent_background_hover: "transparent".into(),
color_transparent_background_pressed: "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(),
} }
} }
} }