Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ Building styled and more featured component libraries on top of Dioxus Primitive

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

28/29
31/31

- [x] Accordion
- [x] Alert Dialog
- [x] Aspect Ratio
- [x] Avatar
- [x] Calendar
- [x] Card
- [x] Checkbox
- [x] Collapsible
- [x] Context Menu
Expand All @@ -59,6 +60,7 @@ We're still in the early days - Many components are still being created and stab
- [x] Slider
- [x] Switch
- [x] Tabs
- [x] Textarea
- [x] Toast
- [x] Toggle
- [x] Toggle Group
Expand Down
4 changes: 3 additions & 1 deletion component.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"preview/src/components/context_menu",
"preview/src/components/aspect_ratio",
"preview/src/components/scroll_area",
"preview/src/components/date_picker"
"preview/src/components/date_picker",
"preview/src/components/card",
"preview/src/components/textarea"
]
}
44 changes: 44 additions & 0 deletions playwright/card.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { test, expect } from "@playwright/test";

test("card component structure", async ({ page }) => {
await page.goto("http://127.0.0.1:8080/component/?name=card&", {
timeout: 20 * 60 * 1000,
});

// Find the card element
const card = page.locator(".card").nth(0);

// Assert the card is visible with correct data-slot
await expect(card).toBeVisible();
await expect(card).toHaveAttribute("data-slot", "card");

// Assert card-header structure
const cardHeader = card.locator(".card-header");
await expect(cardHeader).toBeVisible();
await expect(cardHeader).toHaveAttribute("data-slot", "card-header");

// Assert card-title structure
const cardTitle = card.locator(".card-title");
await expect(cardTitle).toBeVisible();
await expect(cardTitle).toHaveAttribute("data-slot", "card-title");

// Assert card-description structure
const cardDescription = card.locator(".card-description");
await expect(cardDescription).toBeVisible();
await expect(cardDescription).toHaveAttribute("data-slot", "card-description");

// Assert card-action structure
const cardAction = card.locator(".card-action");
await expect(cardAction).toBeVisible();
await expect(cardAction).toHaveAttribute("data-slot", "card-action");

// Assert card-content structure
const cardContent = card.locator(".card-content");
await expect(cardContent).toBeVisible();
await expect(cardContent).toHaveAttribute("data-slot", "card-content");

// Assert card-footer structure
const cardFooter = card.locator(".card-footer");
await expect(cardFooter).toBeVisible();
await expect(cardFooter).toHaveAttribute("data-slot", "card-footer");
});
10 changes: 10 additions & 0 deletions playwright/textarea.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, expect } from "@playwright/test";

test("test", async ({ page }) => {
await page.goto("http://127.0.0.1:8080/component/?name=textarea&", {
timeout: 20 * 60 * 1000,
}); // Increase timeout to 20 minutes

await page.getByPlaceholder('Enter your description').first().fill('This is my description');
await expect(page.locator('#textarea-message')).toContainText('Description here: This is my description');
});
21 changes: 21 additions & 0 deletions preview/src/components/card/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "card",
"description": "A simple card component",
"authors": [
"zhiyanzhaijie"
],
"exclude": [
"variants",
"docs.md",
"component.json"
],
"cargoDependencies": [
{
"name": "dioxus-primitives",
"git": "https://github.com/DioxusLabs/components"
}
],
"globalAssets": [
"../../../assets/dx-components-theme.css"
]
}
107 changes: 107 additions & 0 deletions preview/src/components/card/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use dioxus::prelude::*;

#[component]
pub fn Card(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
document::Link { rel: "stylesheet", href: asset!("./style.css") }
div {
class: "card",
"data-slot": "card",
..attributes,
{children}
}
}
}

#[component]
pub fn CardHeader(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-header",
"data-slot": "card-header",
..attributes,
{children}
}
}
}

#[component]
pub fn CardTitle(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-title",
"data-slot": "card-title",
..attributes,
{children}
}
}
}

#[component]
pub fn CardDescription(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-description",
"data-slot": "card-description",
..attributes,
{children}
}
}
}

#[component]
pub fn CardAction(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-action",
"data-slot": "card-action",
..attributes,
{children}
}
}
}

#[component]
pub fn CardContent(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-content",
"data-slot": "card-content",
..attributes,
{children}
}
}
}

#[component]
pub fn CardFooter(
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
div {
class: "card-footer",
"data-slot": "card-footer",
..attributes,
{children}
}
}
}
32 changes: 32 additions & 0 deletions preview/src/components/card/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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.

## Component Structure

```rust
// The Card component must wrap all card elements.
Card {
// CardHeader contains the title, description, and optional action.
CardHeader {
// CardTitle displays the main heading.
CardTitle { "Card Title" }
// CardDescription provides supporting text.
CardDescription { "Card description goes here." }
// CardAction positions action elements (e.g., buttons) in the header.
CardAction {
Button { "Action" }
}
}
// CardContent holds the main body content.
CardContent {
p { "Main content of the card." }
}
// CardFooter contains footer actions or information.
CardFooter {
Button { "Submit" }
}
}
```

## Layout Notes

- When `CardAction` is present inside `CardHeader`, the header automatically switches to a two-column grid layout.
3 changes: 3 additions & 0 deletions preview/src/components/card/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod component;
pub use component::*;

54 changes: 54 additions & 0 deletions preview/src/components/card/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.card {
display: flex;
flex-direction: column;

gap: 1.5rem;
padding: 1.5rem 0;
color: var(--secondary-color-4);
border: 1px solid var(--primary-color-6);
border-radius: 8px;
background-color: var(--primary-color-2);
box-shadow: 0 2px 10px rgb(0 0 0 / 10%);
}

.card-header {
display: grid;
grid-template-rows: auto auto;
grid-auto-rows: min-content;
align-items: start;
gap: 0.5rem;
padding: 0 1.5rem;
}

.card-header:has([data-slot="card-action"]) {
grid-template-columns: 1fr auto;
}

.card-title {
line-height: 1;
font-weight: 600;
font-size: 1rem;
}

.card-description {
color: var(--secondary-color-5);
font-size: 0.875rem;
line-height: 1.25rem;
}

.card-action {
grid-column-start: 2;
grid-row: 1 / span 2;
align-self: start;
justify-self: end;
}

.card-content {
padding: 0 1.5rem;
}

.card-footer {
display: flex;
align-items: center;
padding: 0 1.5rem;
}
49 changes: 49 additions & 0 deletions preview/src/components/card/variants/main/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use super::super::component::*;
use crate::components::button::{Button, ButtonVariant};
use crate::components::input::Input;
use crate::components::label::Label;
use dioxus::prelude::*;

#[component]
pub fn Demo() -> Element {
rsx! {
Card { style: "width: 100%; max-width: 24rem;",
CardHeader {
CardTitle { "Login to your account" }
CardDescription { "Enter your email below to login to your account" }
CardAction {
Button { variant: ButtonVariant::Ghost, "Sign Up" }
}
}
CardContent {
form {
div { style: "display: flex; flex-direction: column; gap: 1.5rem;",
div { style: "display: grid; gap: 0.5rem;",
Label { html_for: "email", "Email" }
Input {
id: "email",
r#type: "email",
placeholder: "[email protected]",
}
}
div { style: "display: grid; gap: 0.5rem;",
div { style: "display: flex; align-items: center;",
Label { html_for: "password", "Password" }
a {
href: "#",
style: "margin-left: auto; font-size: 0.875rem; color: var(--secondary-color-5); text-decoration: underline; text-underline-offset: 4px;",
"Forgot your password?"
}
}
Input { id: "password", r#type: "password" }
}
}
}
}
CardFooter { style: "flex-direction: column; gap: 0.5rem;",
Button { r#type: "submit", style: "width: 100%;", "Login" }
Button { variant: ButtonVariant::Outline, style: "width: 100%;", "Login with Google" }
}
}
}
}
2 changes: 2 additions & 0 deletions preview/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ examples!(
avatar,
button,
calendar[simple, internationalized, range, unavailable_dates],
card,
checkbox,
collapsible,
context_menu,
Expand All @@ -83,6 +84,7 @@ examples!(
slider,
switch,
tabs,
textarea,
toast,
toggle_group,
toggle,
Expand Down
21 changes: 21 additions & 0 deletions preview/src/components/textarea/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "textarea",
"description": "a textarea component used to allow users to enter multi-line text input",
"authors": [
"zhiyanzhaijie"
],
"exclude": [
"variants",
"docs.md",
"component.json"
],
"cargoDependencies": [
{
"name": "dioxus-primitives",
"git": "https://github.com/DioxusLabs/components"
}
],
"globalAssets": [
"../../../assets/dx-components-theme.css"
]
}
Loading
Loading