Skip to content

Commit 923facd

Browse files
Add component Card (#155)
* Add Component Card * tweak dark mode card styling * remove card playwright test --------- Co-authored-by: Evan Almloff <[email protected]>
1 parent 2484385 commit 923facd

File tree

10 files changed

+273
-5
lines changed

10 files changed

+273
-5
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ Building styled and more featured component libraries on top of Dioxus Primitive
3333

3434
We're still in the early days - Many components are still being created and stabilized.
3535

36-
28/29
36+
30/30
3737

3838
- [x] Accordion
3939
- [x] Alert Dialog
4040
- [x] Aspect Ratio
4141
- [x] Avatar
4242
- [x] Calendar
43+
- [x] Card
4344
- [x] Checkbox
4445
- [x] Collapsible
4546
- [x] Context Menu

component.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"preview/src/components/context_menu",
3434
"preview/src/components/aspect_ratio",
3535
"preview/src/components/scroll_area",
36-
"preview/src/components/date_picker"
36+
"preview/src/components/date_picker",
37+
"preview/src/components/card"
3738
]
3839
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "card",
3+
"description": "A simple card component",
4+
"authors": [
5+
"zhiyanzhaijie"
6+
],
7+
"exclude": [
8+
"variants",
9+
"docs.md",
10+
"component.json"
11+
],
12+
"cargoDependencies": [
13+
{
14+
"name": "dioxus-primitives",
15+
"git": "https://github.com/DioxusLabs/components"
16+
}
17+
],
18+
"globalAssets": [
19+
"../../../assets/dx-components-theme.css"
20+
]
21+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use dioxus::prelude::*;
2+
3+
#[component]
4+
pub fn Card(
5+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
6+
children: Element,
7+
) -> Element {
8+
rsx! {
9+
document::Link { rel: "stylesheet", href: asset!("./style.css") }
10+
div {
11+
class: "card",
12+
"data-slot": "card",
13+
..attributes,
14+
{children}
15+
}
16+
}
17+
}
18+
19+
#[component]
20+
pub fn CardHeader(
21+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
22+
children: Element,
23+
) -> Element {
24+
rsx! {
25+
div {
26+
class: "card-header",
27+
"data-slot": "card-header",
28+
..attributes,
29+
{children}
30+
}
31+
}
32+
}
33+
34+
#[component]
35+
pub fn CardTitle(
36+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
37+
children: Element,
38+
) -> Element {
39+
rsx! {
40+
div {
41+
class: "card-title",
42+
"data-slot": "card-title",
43+
..attributes,
44+
{children}
45+
}
46+
}
47+
}
48+
49+
#[component]
50+
pub fn CardDescription(
51+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
52+
children: Element,
53+
) -> Element {
54+
rsx! {
55+
div {
56+
class: "card-description",
57+
"data-slot": "card-description",
58+
..attributes,
59+
{children}
60+
}
61+
}
62+
}
63+
64+
#[component]
65+
pub fn CardAction(
66+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
67+
children: Element,
68+
) -> Element {
69+
rsx! {
70+
div {
71+
class: "card-action",
72+
"data-slot": "card-action",
73+
..attributes,
74+
{children}
75+
}
76+
}
77+
}
78+
79+
#[component]
80+
pub fn CardContent(
81+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
82+
children: Element,
83+
) -> Element {
84+
rsx! {
85+
div {
86+
class: "card-content",
87+
"data-slot": "card-content",
88+
..attributes,
89+
{children}
90+
}
91+
}
92+
}
93+
94+
#[component]
95+
pub fn CardFooter(
96+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
97+
children: Element,
98+
) -> Element {
99+
rsx! {
100+
div {
101+
class: "card-footer",
102+
"data-slot": "card-footer",
103+
..attributes,
104+
{children}
105+
}
106+
}
107+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
The card component is a flexible container for grouping related content and actions. It provides a structured layout with optional header, content, and footer sections.
2+
3+
## Component Structure
4+
5+
```rust
6+
// The Card component must wrap all card elements.
7+
Card {
8+
// CardHeader contains the title, description, and optional action.
9+
CardHeader {
10+
// CardTitle displays the main heading.
11+
CardTitle { "Card Title" }
12+
// CardDescription provides supporting text.
13+
CardDescription { "Card description goes here." }
14+
// CardAction positions action elements (e.g., buttons) in the header.
15+
CardAction {
16+
Button { "Action" }
17+
}
18+
}
19+
// CardContent holds the main body content.
20+
CardContent {
21+
p { "Main content of the card." }
22+
}
23+
// CardFooter contains footer actions or information.
24+
CardFooter {
25+
Button { "Submit" }
26+
}
27+
}
28+
```
29+
30+
## Layout Notes
31+
32+
- When `CardAction` is present inside `CardHeader`, the header automatically switches to a two-column grid layout.

preview/src/components/card/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod component;
2+
pub use component::*;
3+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
.card {
2+
display: flex;
3+
flex-direction: column;
4+
5+
gap: 1.5rem;
6+
padding: 1.5rem 0;
7+
color: var(--secondary-color-4);
8+
border: 1px solid var(--light, var(--primary-color-6)) var(--dark, var(--primary-color-5));
9+
border-radius: 1rem;
10+
background-color: var(--light, var(--secondary-color-2)) var(--dark, var(--primary-color-3));
11+
box-shadow: 0 2px 10px rgb(0 0 0 / 10%);
12+
}
13+
14+
.card-header {
15+
display: grid;
16+
grid-template-rows: auto auto;
17+
grid-auto-rows: min-content;
18+
align-items: start;
19+
gap: 0.5rem;
20+
padding: 0 1.5rem;
21+
}
22+
23+
.card-header:has([data-slot="card-action"]) {
24+
grid-template-columns: 1fr auto;
25+
}
26+
27+
.card-title {
28+
line-height: 1;
29+
font-weight: 600;
30+
font-size: 1rem;
31+
}
32+
33+
.card-description {
34+
color: var(--secondary-color-5);
35+
font-size: 0.875rem;
36+
line-height: 1.25rem;
37+
}
38+
39+
.card-action {
40+
grid-column-start: 2;
41+
grid-row: 1 / span 2;
42+
align-self: start;
43+
justify-self: end;
44+
}
45+
46+
.card-content {
47+
padding: 0 1.5rem;
48+
}
49+
50+
.card-footer {
51+
display: flex;
52+
align-items: center;
53+
padding: 0 1.5rem;
54+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use super::super::component::*;
2+
use crate::components::button::{Button, ButtonVariant};
3+
use crate::components::input::Input;
4+
use crate::components::label::Label;
5+
use dioxus::prelude::*;
6+
7+
#[component]
8+
pub fn Demo() -> Element {
9+
rsx! {
10+
Card { style: "width: 100%; max-width: 24rem;",
11+
CardHeader {
12+
CardTitle { "Login to your account" }
13+
CardDescription { "Enter your email below to login to your account" }
14+
CardAction {
15+
Button { variant: ButtonVariant::Ghost, "Sign Up" }
16+
}
17+
}
18+
CardContent {
19+
form {
20+
div { style: "display: flex; flex-direction: column; gap: 1.5rem;",
21+
div { style: "display: grid; gap: 0.5rem;",
22+
Label { html_for: "email", "Email" }
23+
Input {
24+
id: "email",
25+
r#type: "email",
26+
placeholder: "[email protected]",
27+
}
28+
}
29+
div { style: "display: grid; gap: 0.5rem;",
30+
div { style: "display: flex; align-items: center;",
31+
Label { html_for: "password", "Password" }
32+
a {
33+
href: "#",
34+
style: "margin-left: auto; font-size: 0.875rem; color: var(--secondary-color-5); text-decoration: underline; text-underline-offset: 4px;",
35+
"Forgot your password?"
36+
}
37+
}
38+
Input { id: "password", r#type: "password" }
39+
}
40+
}
41+
}
42+
}
43+
CardFooter { style: "flex-direction: column; gap: 0.5rem;",
44+
Button { r#type: "submit", style: "width: 100%;", "Login" }
45+
Button { variant: ButtonVariant::Outline, style: "width: 100%;", "Login with Google" }
46+
}
47+
}
48+
}
49+
}

preview/src/components/input/style.css

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
border-radius: 0.5rem;
1313
border-radius: calc(0.5rem);
1414
background: none;
15-
background: var(--light, var(--primary-color))
16-
var(--dark, var(--primary-color-3));
15+
background-color: var(--light, var(--primary-color)) var(--dark, color-mix(in oklab, #FFFFFF26 30%, transparent));
1716
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6))
1817
var(--dark, var(--primary-color-7));
1918
color: var(--secondary-color-4);
@@ -34,7 +33,7 @@
3433
.input:hover:not(:disabled),
3534
.input:focus-visible {
3635
background: var(--light, var(--primary-color-4))
37-
var(--dark, var(--primary-color-5));
36+
var(--dark, color-mix(in oklab, #FFFFFF26 50%, transparent));
3837
color: var(--secondary-color-1);
3938
outline: none;
4039
}

preview/src/components/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ examples!(
6363
avatar,
6464
button,
6565
calendar[simple, internationalized, range, unavailable_dates],
66+
card,
6667
checkbox,
6768
collapsible,
6869
context_menu,

0 commit comments

Comments
 (0)