Skip to content
Open
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
167 changes: 167 additions & 0 deletions src/collections/sistent/components/card/code.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Card Code
component: card
description: A card is a contained surface that groups related information and actions about a single subject, making content easy to scan and interact with.
---

import { Card, Button } from "@sistent/sistent";

The Card component wraps MUI's Card and works with Sistent's theming out of the box. Here are the most common usage patterns.

<a id="Basic Card">
<h2>Basic Card</h2>
</a>

A basic card with some content inside. By default it uses the elevated style with a subtle shadow.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', padding: '16px' }}>
<Card style={{ width: 300, padding: '16px' }}>
Simple card content
</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="basic-card" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card style={{ width: 300, padding: "16px" }}>
Simple card content
</Card>
</SistentThemeProvider>`} />
</div>

<a id="Outlined Card">
<h2>Outlined Card</h2>
</a>

Use `variant="outlined"` to get a card with a border instead of a shadow. Useful when the background is already elevated or when you want a lighter visual style.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', padding: '16px' }}>
<Card variant="outlined" style={{ width: 300, padding: '16px' }}>
Outlined card content
</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="outlined-card" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card variant="outlined" style={{ width: 300, padding: "16px" }}>
Outlined card content
</Card>
</SistentThemeProvider>`} />
</div>

<a id="Elevation">
<h2>Elevation</h2>
</a>

The `elevation` prop controls shadow depth. Values go from 0 (flat) to 24 (maximum depth). Most cards in practice sit between 1 and 8.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', padding: '16px' }}>
<Card elevation={1} style={{ padding: '16px' }}>Elevation 1</Card>
<Card elevation={4} style={{ padding: '16px' }}>Elevation 4</Card>
<Card elevation={8} style={{ padding: '16px' }}>Elevation 8</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="card-elevation" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card elevation={1} style={{ padding: "16px" }}>Elevation 1</Card>
<Card elevation={4} style={{ padding: "16px" }}>Elevation 4</Card>
<Card elevation={8} style={{ padding: "16px" }}>Elevation 8</Card>
</SistentThemeProvider>`} />
</div>

<a id="Square Corners">
<h2>Square Corners</h2>
</a>

Cards have rounded corners by default. Set `square` to `true` to remove the rounding for a more geometric look.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', gap: '16px', justifyContent: 'center', padding: '16px' }}>
<Card style={{ width: 200, padding: '16px' }}>Rounded</Card>
<Card square style={{ width: 200, padding: '16px' }}>Square</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="card-corners" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card style={{ width: 200, padding: "16px" }}>Rounded</Card>
<Card square style={{ width: 200, padding: "16px" }}>Square</Card>
</SistentThemeProvider>`} />
</div>

<a id="Clickable Card">
<h2>Clickable Card</h2>
</a>

To make the entire card interactive, add an `onClick` handler and update the cursor style. This pattern is common in grid layouts where each card is a navigation target.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', padding: '16px' }}>
<Card
style={{ width: 300, padding: '16px', cursor: 'pointer' }}
onClick={() => alert('Card clicked')}
>
Click anywhere on this card
</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="clickable-card" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card
style={{ width: 300, padding: "16px", cursor: "pointer" }}
onClick={() => console.log("Card clicked")}
>
Click anywhere on this card
</Card>
</SistentThemeProvider>`} />
</div>

<a id="Card with Header and Actions">
<h2>Card with Header and Actions</h2>
</a>

A common real-world pattern — a card with a title, a short description, and action buttons at the bottom.

<div className="showcase">
<div className="items">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', padding: '16px' }}>
<Card style={{ width: 300 }}>
<div style={{ padding: '16px' }}>
<h3 style={{ margin: '0 0 8px' }}>Card Title</h3>
<p style={{ margin: 0, color: 'gray' }}>A short description about what this card represents and why it matters.</p>
</div>
<div style={{ padding: '8px 16px 16px', display: 'flex', gap: '8px' }}>
<Button variant="contained" size="small">Action</Button>
<Button variant="outlined" size="small">Cancel</Button>
</div>
</Card>
</div>
</ThemeWrapper>
</div>
<CodeBlock name="card-with-actions" collapsible code={`<SistentThemeProvider initialMode={isDark ? "dark" : "light"}>
<Card style={{ width: 300 }}>
<div style={{ padding: "16px" }}>
<h3 style={{ margin: "0 0 8px" }}>Card Title</h3>
<p style={{ margin: 0, color: "gray" }}>
A short description about what this card represents.
</p>
</div>
<div style={{ padding: "8px 16px 16px", display: "flex", gap: "8px" }}>
<Button variant="contained" size="small">Action</Button>
<Button variant="outlined" size="small">Cancel</Button>
</div>
</Card>
</SistentThemeProvider>`} />
</div>
90 changes: 90 additions & 0 deletions src/collections/sistent/components/card/guidance.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
title: Card Guidance
component: card
description: A card is a contained surface that groups related information and actions about a single subject, making content easy to scan and interact with.
---

import { Card } from "@sistent/sistent";

Cards work best when they follow a consistent structure and are used intentionally. Here's how to get the most out of them.

<a id="When to Use">
<h2>When to Use</h2>
</a>

Cards are a great fit when you're presenting a collection of items that are related but independent — things like search results, product listings, user profiles, or dashboard widgets. The contained surface makes it easy for users to scan many items at once without losing track of where one ends and another begins.

<h3>Use cards when</h3>

- You have multiple items of the same type to display side by side
- Each item has its own set of actions (like "Edit", "Delete", or "View")
- The content can be summarized — cards are not meant to show full detail
- You want to let users quickly identify which item they want before drilling in

<h3>Avoid cards when</h3>

- You only have a single piece of content — a card adds unnecessary structure here
- The content is tabular — a table will do a better job showing relationships between rows
- The layout is purely linear — a list or a stack of sections is simpler and more readable

<a id="Content Structure">
<h2>Content Structure</h2>
</a>

Cards work best with a predictable internal layout. When every card in a set follows the same structure, users can scan faster and actions are easier to find.

<h3>Keep it focused</h3>

A card should cover one subject. If you find yourself fitting two unrelated things into a single card, split them into two. A focused card is easier to scan and less likely to confuse.

<h3>Prioritize the header</h3>

The most important information — the title, name, or main identifier — should be at the top. Users scan in F-patterns; if the key info is buried, they'll miss it. Secondary details like descriptions or metadata can follow below.

<h3>Limit the number of actions</h3>

Cards shouldn't try to do too many things at once. One to two actions per card is a good rule of thumb. If you have more, consider whether some of those actions belong on a detail page instead.

<a id="Hierarchy">
<h2>Hierarchy</h2>
</a>

When multiple card types appear in the same layout, their visual weight should reflect their importance. Use elevation and variant choices deliberately to guide the user's eye.

<h3>Elevated cards for primary content</h3>

If cards are the main content on a page, use the default elevated style. The shadow helps them stand out from the background and from each other.

<h3>Outlined cards for secondary content</h3>

Outlined cards are a better fit for supplementary content, sidebars, or contexts where the background is already elevated. They're visually lighter and won't compete with the primary content.

<a id="Interactivity">
<h2>Interactivity</h2>
</a>

Whether or not a card is clickable should be clear from the visual treatment alone — don't make users guess.

<h3>Clickable cards</h3>

If the entire card is a navigation target, make sure there's a visible hover state. A subtle background color change or shadow shift is enough. The cursor should switch to a pointer on hover.

<h3>Cards with actions</h3>

If a card has specific action buttons (rather than a full-card click), those should be visually distinct and located in a consistent spot — usually the bottom of the card. Don't mix full-card clicks with inline buttons, as this creates conflicting affordances.

<h3>Non-interactive cards</h3>

Remove any hover effects from purely informational cards. No pointer cursor, no shadow change on hover. This keeps the visual language consistent and prevents users from clicking on things that don't go anywhere.

<a id="Accessibility">
<h2>Accessibility</h2>
</a>

Cards should be accessible without requiring visual context to understand their purpose.

- If a card is clickable, make sure it has a meaningful `aria-label` or that the visible text is descriptive enough to serve as the accessible name
- Avoid using only color or icons to convey the card's purpose — pair them with a visible text label
- Ensure sufficient color contrast between the card surface and its contents
- Focus outlines should be visible on all interactive elements within a card
- If cards reorder or update dynamically, use appropriate ARIA live regions so screen reader users are notified of changes
107 changes: 107 additions & 0 deletions src/collections/sistent/components/card/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: "Card"
title: Card
published: true
component: card
description: A card is a contained surface that groups related information and actions about a single subject, making content easy to scan and interact with.
---

import { Card } from "@sistent/sistent";

Cards are versatile containers that bring together content and actions around a single topic. They give users a clean, scannable way to browse and interact with information — whether that's a product, a profile, a post, or anything in between. Cards can live in grids, lists, or standalone layouts, and they scale well across screen sizes.

<a id="Types">
<h2>Types</h2>
</a>

Cards come in a few configurations depending on how much visual weight and interactivity you need. Choosing the right one helps keep the interface consistent and easy to navigate.

<h3>Elevated</h3>

The default card type. It uses a drop shadow to sit above the background, creating a sense of depth. This is the most common type and works well for content-heavy layouts where you need clear separation between items.

<Row className="image-container">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', width: '100%', padding: '16px' }}>
<Card style={{ width: 280, padding: '16px' }}>
<p style={{ margin: 0 }}>Elevated Card</p>
</Card>
</div>
</ThemeWrapper>
</Row>

<h3>Outlined</h3>

An outlined card drops the shadow and uses a border instead. It's a good pick when you want a lighter look, or when the background is already elevated and adding more depth would feel cluttered.

<Row className="image-container">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', width: '100%', padding: '16px' }}>
<Card variant="outlined" style={{ width: 280, padding: '16px' }}>
<p style={{ margin: 0 }}>Outlined Card</p>
</Card>
</div>
</ThemeWrapper>
</Row>

<a id="Elevation">
<h2>Elevation</h2>
</a>

The `elevation` prop lets you control how prominent a card feels. Values range from 0 (flat, no shadow) all the way up to 24 (maximum depth). Most cards in practice sit between 1 and 8 — high enough to stand out without feeling heavy.

<Row className="image-container">
<ThemeWrapper>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', padding: '16px', width: '100%' }}>
<Card elevation={1} style={{ padding: '16px' }}>Elevation 1 — subtle</Card>
<Card elevation={4} style={{ padding: '16px' }}>Elevation 4 — moderate</Card>
<Card elevation={8} style={{ padding: '16px' }}>Elevation 8 — prominent</Card>
</div>
</ThemeWrapper>
</Row>

<a id="Interactivity">
<h2>Interactivity</h2>
</a>

Cards can be made clickable by wrapping them in an action area or by setting the `onClick` handler directly. When a card is interactive, it should have a clear hover and focus state so users know it's actionable.

<h3>Clickable Card</h3>

Use a clickable card when the entire surface should trigger a navigation or action. This is common in grids where each card represents a destination — like a product page or a settings section.

<Row className="image-container">
<ThemeWrapper>
<div style={{ display: 'flex', justifyContent: 'center', width: '100%', padding: '16px' }}>
<Card
style={{ width: 280, padding: '16px', cursor: 'pointer' }}
onClick={() => {}}
>
<p style={{ margin: 0 }}>Click me</p>
</Card>
</div>
</ThemeWrapper>
</Row>

<h3>Non-interactive Card</h3>

Not every card needs to be clickable. When a card is purely informational — like a stats panel or a summary block — it should not have hover effects or pointer cursors, since those signal interactivity that doesn't exist.

<a id="Raised Corners">
<h2>Corners</h2>
</a>

By default, cards have rounded corners. If you need a more geometric, grid-aligned look, you can use the `square` prop to remove the rounding entirely.

<Row className="image-container">
<ThemeWrapper>
<div style={{ display: 'flex', gap: '16px', justifyContent: 'center', padding: '16px' }}>
<Card style={{ width: 200, padding: '16px' }}>
<p style={{ margin: 0 }}>Rounded (default)</p>
</Card>
<Card square style={{ width: 200, padding: '16px' }}>
<p style={{ margin: 0 }}>Square corners</p>
</Card>
</div>
</ThemeWrapper>
</Row>
Loading
Loading