mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(card): stories added and tests passing
This commit is contained in:
parent
0eaf34994a
commit
d7dfa1995e
@ -1,6 +1,5 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import {act, render} from "@testing-library/react";
|
||||
|
||||
import {Card} from "../src";
|
||||
|
||||
@ -26,10 +25,13 @@ describe("Card", () => {
|
||||
|
||||
it("should be clicked when is pressable", () => {
|
||||
const onPress = jest.fn();
|
||||
const {container} = render(<Card isPressable onPress={onPress} />);
|
||||
const {getByRole} = render(<Card isPressable onPress={onPress} />);
|
||||
|
||||
userEvent.click(container.firstChild as HTMLElement);
|
||||
expect(onPress).toBeCalledTimes(1);
|
||||
act(() => {
|
||||
getByRole("button").click();
|
||||
});
|
||||
|
||||
expect(onPress).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should render correctly when nested", () => {
|
||||
|
||||
@ -52,6 +52,8 @@
|
||||
"@react-types/shared": "^3.17.0",
|
||||
"@nextui-org/code": "workspace:*",
|
||||
"@nextui-org/link": "workspace:*",
|
||||
"@nextui-org/button": "workspace:*",
|
||||
"@nextui-org/avatar": "workspace:*",
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0"
|
||||
},
|
||||
|
||||
@ -17,7 +17,7 @@ const CardFooter = forwardRef<CardFooterProps, "div">((props, ref) => {
|
||||
const {slots, styles} = useCardContext();
|
||||
|
||||
const footerStyles = clsx(styles?.body, className, {
|
||||
"backdrop-blur-md backdrop-saturate-[1.8]": isBlurred,
|
||||
"backdrop-blur-xl backdrop-saturate-200": isBlurred,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@ -52,7 +52,6 @@ export type ContextType = {
|
||||
slots: CardReturnType;
|
||||
styles?: SlotsToClasses<CardSlots>;
|
||||
isDisabled?: CardVariantProps["isDisabled"];
|
||||
isBordered?: CardVariantProps["isBordered"];
|
||||
isFooterBlurred?: CardVariantProps["isFooterBlurred"];
|
||||
disableAnimation?: CardVariantProps["disableAnimation"];
|
||||
fullWidth?: CardVariantProps["fullWidth"];
|
||||
@ -120,7 +119,6 @@ export function useCard(originalProps: UseCardProps) {
|
||||
|
||||
const context = useMemo<ContextType>(
|
||||
() => ({
|
||||
isBordered: originalProps.isBordered,
|
||||
isDisabled: originalProps.isDisabled,
|
||||
isFooterBlurred: originalProps.isFooterBlurred,
|
||||
disableAnimation: originalProps.disableAnimation,
|
||||
@ -131,7 +129,6 @@ export function useCard(originalProps: UseCardProps) {
|
||||
[
|
||||
slots,
|
||||
styles,
|
||||
originalProps.isBordered,
|
||||
originalProps.isDisabled,
|
||||
originalProps.isFooterBlurred,
|
||||
originalProps.disableAnimation,
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import React from "react";
|
||||
import {ComponentStory, ComponentMeta} from "@storybook/react";
|
||||
import {card} from "@nextui-org/theme";
|
||||
import {Link} from "@nextui-org/link";
|
||||
import {Button} from "@nextui-org/button";
|
||||
import {Code} from "@nextui-org/code";
|
||||
|
||||
import {Card, CardBody, CardProps} from "../src";
|
||||
import {Card, CardBody, CardHeader, CardFooter, CardProps} from "../src";
|
||||
|
||||
export default {
|
||||
title: "Components/Card",
|
||||
@ -20,11 +23,6 @@ export default {
|
||||
options: ["none", "base", "sm", "md", "lg", "xl", "2xl", "3xl", "full"],
|
||||
},
|
||||
},
|
||||
isBordered: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
fullWidth: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
@ -64,9 +62,7 @@ export default {
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="flex items-center justify-center w-screen h-screen">
|
||||
<div className="max-w-md w-full">
|
||||
<Story />
|
||||
</div>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
@ -78,12 +74,348 @@ const defaultProps = {
|
||||
};
|
||||
|
||||
const Template: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card {...args}>
|
||||
<CardBody>A basic card</CardBody>
|
||||
<Card {...args} className="max-w-md">
|
||||
<CardBody>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const WithDividerTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card {...args} isBordered className="max-w-md">
|
||||
<CardHeader className="border-b border-border dark:border-border-dark">
|
||||
<strong>Description</strong>
|
||||
</CardHeader>
|
||||
<CardBody className="py-8">
|
||||
<p>The Object constructor creates an object wrapper for the given value.</p>
|
||||
</CardBody>
|
||||
<CardFooter className="border-t border-border dark:border-border-dark">
|
||||
<p>
|
||||
When called in a non-constructor context, Object behaves identically to{" "}
|
||||
<Code color="primary">new Object()</Code>.
|
||||
</p>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const WithFooterTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card {...args} className="p-4 max-w-md">
|
||||
<CardHeader className="flex gap-3">
|
||||
<img
|
||||
alt="nextui logo"
|
||||
height="34px"
|
||||
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
|
||||
width="34px"
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<b className="text-lg">NextUI</b>
|
||||
<p className="text-neutral-500">nextui.org</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardBody className="py-2">
|
||||
<p>Make beautiful websites regardless of your design experience.</p>
|
||||
</CardBody>
|
||||
<CardFooter>
|
||||
<Link isExternal showAnchorIcon href="https://github.com/nextui-org/nextui">
|
||||
Visit source code on GitHub.
|
||||
</Link>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const WithAbsImageHeaderTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card {...args} className="max-w-[330px]">
|
||||
<CardHeader className="absolute top-2 z-10">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-white/60 text-xs uppercase font-bold">What to watch</p>
|
||||
<p className="text-white text-2xl">Stream the Apple event</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Apple event background"
|
||||
className="w-full h-[440px] object-cover"
|
||||
src={require("./assets/apple-event.jpeg")}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const WithAbsImgHeaderFooterTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card className="w-[330px] bg-zinc-100 dark:bg-zinc-100" {...args}>
|
||||
<CardHeader className="absolute top-2 z-10">
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-xs text-black/40 uppercase font-bold">New</p>
|
||||
<h4 className="text-3xl font-medium text-black">HomePod mini</h4>
|
||||
<p className="text-sm text-black/80 pr-1.5">
|
||||
Room-filling sound, Intelligent assistant. Smart home control. Works seamlessly with
|
||||
iPhone. Check it out
|
||||
</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Apple homepods background"
|
||||
className="w-full h-[440px] pt-10 object-contain"
|
||||
src={require("./assets/homepod.jpeg")}
|
||||
/>
|
||||
<CardFooter className="justify-between absolute bottom-0">
|
||||
<div>
|
||||
<p className="text-xs text-black/80">Available soon.</p>
|
||||
<p className="text-xs text-black/80">Get notified.</p>
|
||||
</div>
|
||||
<Button radius="full">Notify Me</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const CoverImgTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<div className="max-w-[900px] gap-2 grid grid-cols-12 grid-rows-2 px-8">
|
||||
<Card {...args} className="col-span-12 sm:col-span-4">
|
||||
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/60 uppercase font-bold">What to watch</p>
|
||||
<h4 className="text-white font-medium text-lg">Stream the Acme event</h4>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Card background"
|
||||
className="w-full h-full object-cover"
|
||||
src="https://nextui.org/images/card-example-4.jpeg"
|
||||
/>
|
||||
</Card>
|
||||
<Card {...args} className="col-span-12 sm:col-span-4">
|
||||
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/60 uppercase font-bold">Plant a tree</p>
|
||||
<h4 className="text-white font-medium text-lg">Contribute to the planet</h4>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Card background"
|
||||
className="w-full h-full object-cover"
|
||||
src="https://nextui.org/images/card-example-3.jpeg"
|
||||
/>
|
||||
</Card>
|
||||
<Card {...args} className="col-span-12 sm:col-span-4">
|
||||
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/60 uppercase font-bold">Supercharged</p>
|
||||
<h4 className="text-white font-medium text-lg">Creates beauty like a beast</h4>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Card background"
|
||||
className="w-full h-full object-cover"
|
||||
src="https://nextui.org/images/card-example-2.jpeg"
|
||||
/>
|
||||
</Card>
|
||||
<Card {...args} isFooterBlurred className="w-full h-[400px] col-span-12 sm:col-span-5">
|
||||
<CardHeader className="absolute z-10 top-1 flex-col items-start">
|
||||
<p className="text-xs text-white/60 uppercase font-bold">New</p>
|
||||
<h4 className="text-black font-medium text-2xl">Acme camera</h4>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Card example background"
|
||||
className="w-full h-full scale-125 -translate-y-10 object-cover"
|
||||
src="https://nextui.org/images/card-example-6.jpeg"
|
||||
/>
|
||||
<CardFooter className="absolute bg-white/30 bottom-0 border-t border-slate-300 z-10 justify-between">
|
||||
<div>
|
||||
<p className="text-black text-xs">Available soon.</p>
|
||||
<p className="text-black text-xs">Get notified.</p>
|
||||
</div>
|
||||
<Button color="secondary" radius="full" size="sm" variant="flat">
|
||||
Notify Me
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card {...args} isFooterBlurred className="w-full h-[400px] col-span-12 sm:col-span-7">
|
||||
<CardHeader className="absolute z-10 top-1 flex-col items-start">
|
||||
<p className="text-xs text-white/60 uppercase font-bold">Your day your way</p>
|
||||
<h4 className="text-white/90 font-medium text-2xl">Your checklist for better sleep</h4>
|
||||
</CardHeader>
|
||||
<img
|
||||
alt="Relaxing app background"
|
||||
className="w-full h-full object-cover"
|
||||
src="https://nextui.org/images/card-example-5.jpeg"
|
||||
/>
|
||||
<CardFooter className="absolute bg-black/40 bottom-0 z-10 border-t border-neutral-600 dark:border-neutral-100">
|
||||
<div className="flex flex-grow gap-2 items-center">
|
||||
<img
|
||||
alt="Breathing app icon"
|
||||
className="rounded-full w-10 h-11 bg-black"
|
||||
src={require("./assets/breathing-app-icon.jpeg")}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-xs text-white/60">Breathing App</p>
|
||||
<p className="text-xs text-white/60">Get a good night's sleep.</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button radius="full">Get App</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
const PrimaryActionTemplate: ComponentStory<typeof Card> = (args: CardProps) => {
|
||||
const list = [
|
||||
{
|
||||
title: "Orange",
|
||||
img: "/images/fruit-1.jpeg",
|
||||
price: "$5.50",
|
||||
},
|
||||
{
|
||||
title: "Tangerine",
|
||||
img: "/images/fruit-2.jpeg",
|
||||
price: "$3.00",
|
||||
},
|
||||
{
|
||||
title: "Raspberry",
|
||||
img: "/images/fruit-3.jpeg",
|
||||
price: "$10.00",
|
||||
},
|
||||
{
|
||||
title: "Lemon",
|
||||
img: "/images/fruit-4.jpeg",
|
||||
price: "$5.30",
|
||||
},
|
||||
{
|
||||
title: "Avocado",
|
||||
img: "/images/fruit-5.jpeg",
|
||||
price: "$15.70",
|
||||
},
|
||||
{
|
||||
title: "Lemon 2",
|
||||
img: "/images/fruit-6.jpeg",
|
||||
price: "$8.00",
|
||||
},
|
||||
{
|
||||
title: "Banana",
|
||||
img: "/images/fruit-7.jpeg",
|
||||
price: "$7.50",
|
||||
},
|
||||
{
|
||||
title: "Watermelon",
|
||||
img: "/images/fruit-8.jpeg",
|
||||
price: "$12.20",
|
||||
},
|
||||
];
|
||||
|
||||
type ListItem = (typeof list)[number];
|
||||
|
||||
const handlePress = (item: ListItem) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("item pressed", item);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="gap-2 grid grid-cols-2 sm:grid-cols-4">
|
||||
{list.map((item, index) => (
|
||||
// eslint-disable-next-line no-console
|
||||
<Card {...args} key={index} isPressable onPress={() => handlePress(item)}>
|
||||
<CardBody className="p-0">
|
||||
<img
|
||||
alt={item.title}
|
||||
className="w-full h-[140px] object-cover"
|
||||
src={"https://nextui.org" + item.img}
|
||||
/>
|
||||
</CardBody>
|
||||
<CardFooter className="justify-between">
|
||||
<b>{item.title}</b>
|
||||
<p className="text-neutral-500">{item.price}</p>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const CenterImgWithHeaderTemplate: ComponentStory<typeof Card> = (args: CardProps) => {
|
||||
const list = [
|
||||
{
|
||||
title: "Mac",
|
||||
img: require("./assets/mac.png"),
|
||||
},
|
||||
{
|
||||
title: "iPhone",
|
||||
img: require("./assets/iphone.png"),
|
||||
},
|
||||
{
|
||||
title: "iPad",
|
||||
img: require("./assets/ipad.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple Watch",
|
||||
img: require("./assets/apple-watch.png"),
|
||||
},
|
||||
{
|
||||
title: "AirPods",
|
||||
img: require("./assets/airpods.png"),
|
||||
},
|
||||
{
|
||||
title: "AirTag",
|
||||
img: require("./assets/airtag.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple TV",
|
||||
img: require("./assets/appletv.png"),
|
||||
},
|
||||
{
|
||||
title: "HomePod mini",
|
||||
img: require("./assets/homepod-mini.png"),
|
||||
},
|
||||
{
|
||||
title: "Accessories",
|
||||
img: require("./assets/accessories.png"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 justify-center flex-wrap">
|
||||
{list.map((item, index) => (
|
||||
<div key={index}>
|
||||
<Card {...args} isPressable className="w-[200px] h-[200px]">
|
||||
<CardHeader className="p-0">
|
||||
<h5 className="pl-6 pt-3">{item.title}</h5>
|
||||
</CardHeader>
|
||||
<CardBody className="h-full justify-center">
|
||||
<img alt={item.title} className="w-[180px]" src={item.img} />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const WithDivider = WithDividerTemplate.bind({});
|
||||
WithDivider.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const WithFooter = WithFooterTemplate.bind({});
|
||||
WithFooter.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const WithAbsImageHeader = WithAbsImageHeaderTemplate.bind({});
|
||||
WithAbsImageHeader.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const WithAbsImgHeaderFooter = WithAbsImgHeaderFooterTemplate.bind({});
|
||||
WithAbsImgHeaderFooter.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const CoverImg = CoverImgTemplate.bind({});
|
||||
CoverImg.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const PrimaryAction = PrimaryActionTemplate.bind({});
|
||||
PrimaryAction.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const CenterImgWithHeader = CenterImgWithHeaderTemplate.bind({});
|
||||
CenterImgWithHeader.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
@ -1,556 +0,0 @@
|
||||
import React from "react";
|
||||
import {ComponentMeta, ComponentStory} from "@storybook/react";
|
||||
import {Link} from "@nextui-org/link";
|
||||
import {Code} from "@nextui-org/code";
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {Card, CardProps} from "../src";
|
||||
|
||||
export default {
|
||||
title: "General/Card",
|
||||
component: Card,
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["shadow", "bordered", "flat"],
|
||||
},
|
||||
},
|
||||
borderWeight: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["light", "normal", "bold", "extrabold", "black"],
|
||||
},
|
||||
},
|
||||
isPressable: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
disableAnimation: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
isHoverable: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof Card>;
|
||||
|
||||
const Template: ComponentStory<typeof Card> = (args: CardProps) => (
|
||||
<Card {...args} className="max-w-[50%]">
|
||||
<Card.Body>A basic card</Card.Body>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
variant: "shadow",
|
||||
};
|
||||
|
||||
export const Hoverable = Template.bind({});
|
||||
Hoverable.args = {
|
||||
variant: "bordered",
|
||||
isHoverable: true,
|
||||
};
|
||||
|
||||
export const Variants = () => (
|
||||
<div className="container flex gap-2">
|
||||
<div className="w-4/12">
|
||||
<Card>
|
||||
<Card.Body>
|
||||
<p>Default card. (shadow)</p>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="w-4/12">
|
||||
<Card variant="flat">
|
||||
<Card.Body>
|
||||
<p>Flat card.</p>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="w-4/12">
|
||||
<Card variant="bordered">
|
||||
<Card.Body>
|
||||
<p>Bordered card.</p>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const WithFooter = () => (
|
||||
<Card className="p-3 max-w-[400px]">
|
||||
<Card.Header>
|
||||
<img
|
||||
alt="nextui logo"
|
||||
height="34px"
|
||||
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
|
||||
width="34px"
|
||||
/>
|
||||
<div className="flex flex-col pl-3">
|
||||
<h4 className="pb-2">Next UI</h4>
|
||||
<p>nextui.org</p>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Body className="py-2">
|
||||
<p>Make beautiful websites regardless of your design experience.</p>
|
||||
</Card.Body>
|
||||
<Card.Footer>
|
||||
<Link isExternal color="primary" href="https://github.com/nextui-org/nextui" target="_blank">
|
||||
Visit source code on GitHub.
|
||||
</Link>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const AbsImageWithHeader = () => {
|
||||
return (
|
||||
<div className="flex justify-center gap-2">
|
||||
<Card className="w-[330px]">
|
||||
<Card.Header className="absolute top-5 z-10">
|
||||
<div className="grid-cols-2">
|
||||
<p className="text-white/75 text-sm uppercase font-bold">What to watch</p>
|
||||
<h3 className="text-white text-xl">Stream the Apple event</h3>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple event background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/apple-event.jpeg")}
|
||||
style={{objectFit: "cover"}}
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AbsImgWithHeaderFooter = () => {
|
||||
return (
|
||||
<div className="flex justify-center items-start gap-2">
|
||||
<Card className="w-[330px] bg-neutral-100">
|
||||
<Card.Header className="absolute top-5 z-10">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-xs text-neutral-400 upper font-bold">New</p>
|
||||
<h2 className="text-lg text-black">HomePod mini</h2>
|
||||
<p className="text-xs text-foreground pr-1.5">
|
||||
Room-filling sound, Intelligent assistant. Smart home control. Works seamlessly with
|
||||
iPhone. Check it out
|
||||
</p>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple homedpods background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/homepod.jpeg")}
|
||||
style={{objectFit: "cover", paddingTop: "100px"}}
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer className="justify-between">
|
||||
<div>
|
||||
<p className="text-xs">Available soon.</p>
|
||||
<p className="text-xs">Get notified.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-wrap justify-end">
|
||||
<p className="text-xs upper font-bold">Notify Me</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
<Card className="w-[630px]">
|
||||
<Card.Header className="absolute top-5 z-10">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-neutral-300 upper font-bold">Your day your way</p>
|
||||
<h3 className="text-white text-xl">Your checklist for better sleep</h3>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple homedpods background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/relaxing.jpeg")}
|
||||
style={{objectFit: "cover"}}
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer isBlurred className="absolute bottom-0 z-10 border-t border-border-dark">
|
||||
<div className="flex flex-grow items-start">
|
||||
<div className="w-[40px] mr-2">
|
||||
<Card.Image
|
||||
alt="Breathing app icon"
|
||||
autoResize={false}
|
||||
height={40}
|
||||
src={require("./assets/breathing-app-icon.jpeg")}
|
||||
style={{background: "black"}}
|
||||
width={40}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-xs text-neutral-400">Breathing App</p>
|
||||
<p className="text-xs text-neutral-400">Get a good night's sleep.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-white upper font-bold">Get App</p>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CoverImage = () => (
|
||||
<div className="gap-2 grid grid-cols-12">
|
||||
<div className="col-span-12 sm:col-span-4">
|
||||
<Card>
|
||||
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/75 upper font-bold">What to watch</p>
|
||||
<h4 className="text-white font-medium text-lg">Stream the Acme event</h4>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-4.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-4">
|
||||
<Card>
|
||||
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/75 upper font-bold">Plant a tree</p>
|
||||
<h4 className="text-white font-medium text-lg">Contribute to the planet</h4>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-3.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-4">
|
||||
<Card className="bg-black">
|
||||
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/75 upper font-bold">Supercharged</p>
|
||||
<h4 className="text-white font-medium text-lg">Creates beauty like a beast</h4>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-2.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-5">
|
||||
<Card className="w-full h-[400px]">
|
||||
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/75 upper font-bold">New</p>
|
||||
<h3 className="text-black font-medium text-2xl">Acme camera</h3>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card example background"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-6.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer
|
||||
isBlurred
|
||||
className="absolute bg-white/50 bottom-0 border-t border-border-dark z-10"
|
||||
>
|
||||
<div>
|
||||
<p className="text-black text-xs">Available soon.</p>
|
||||
<p className="text-black text-xs">Get notified.</p>
|
||||
</div>
|
||||
<p className="text-xs upper font-bold text-inherit ml-auto">Notify Me</p>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-7">
|
||||
<Card className="w-full h-[400px]">
|
||||
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
|
||||
<p className="text-xs text-white/75 upper font-bold">Your day your way</p>
|
||||
<h3 className="text-white font-medium text-2xl">Your checklist for better sleep</h3>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Relaxing app background"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-5.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer
|
||||
isBlurred
|
||||
className="absolute bottom-0 z-10 bg-black/50 border-t border-border-dark"
|
||||
>
|
||||
<div className="flex flex-grow items-center">
|
||||
<div className="w-[40px] mr-2">
|
||||
<Card.Image
|
||||
alt="Breathing app icon"
|
||||
autoResize={false}
|
||||
height={40}
|
||||
src={require("./assets/breathing-app-icon.jpeg")}
|
||||
style={{background: "black"}}
|
||||
width={40}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-xs text-neutral-400">Breathing App</p>
|
||||
<p className="text-xs text-neutral-400">Get a good night's sleep.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-white upper font-bold">Get App</p>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const PrimaryAction = () => {
|
||||
const list = [
|
||||
{
|
||||
title: "Orange",
|
||||
img: "/images/fruit-1.jpeg",
|
||||
price: "$5.50",
|
||||
},
|
||||
{
|
||||
title: "Tangerine",
|
||||
img: "/images/fruit-2.jpeg",
|
||||
price: "$3.00",
|
||||
},
|
||||
{
|
||||
title: "Raspberry",
|
||||
img: "/images/fruit-3.jpeg",
|
||||
price: "$10.00",
|
||||
},
|
||||
{
|
||||
title: "Lemon",
|
||||
img: "/images/fruit-4.jpeg",
|
||||
price: "$5.30",
|
||||
},
|
||||
{
|
||||
title: "Advocato",
|
||||
img: "/images/fruit-5.jpeg",
|
||||
price: "$15.70",
|
||||
},
|
||||
{
|
||||
title: "Lemon 2",
|
||||
img: "/images/fruit-6.jpeg",
|
||||
price: "$8.00",
|
||||
},
|
||||
{
|
||||
title: "Banana",
|
||||
img: "/images/fruit-7.jpeg",
|
||||
price: "$7.50",
|
||||
},
|
||||
{
|
||||
title: "Watermelon",
|
||||
img: "/images/fruit-8.jpeg",
|
||||
price: "$12.20",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="gap-2 grid grid-cols-2 sm:grid-cols-4">
|
||||
{list.map((item, index) => (
|
||||
// eslint-disable-next-line no-console
|
||||
<Card key={index} isPressable onPress={() => console.log("item pressed", item)}>
|
||||
<Card.Body className="!p-0">
|
||||
<Card.Image
|
||||
alt={item.title}
|
||||
height={140}
|
||||
src={"https://nextui.org" + item.img}
|
||||
style={{objectFit: "cover"}}
|
||||
width="100%"
|
||||
/>
|
||||
</Card.Body>
|
||||
<Card.Footer className="justify-between">
|
||||
<strong>{item.title}</strong>
|
||||
<p className="font-medium text-neutral-500">{item.price}</p>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CenterImgWithHeader = () => {
|
||||
const list = [
|
||||
{
|
||||
title: "Mac",
|
||||
img: require("./assets/mac.png"),
|
||||
},
|
||||
{
|
||||
title: "iPhone",
|
||||
img: require("./assets/iphone.png"),
|
||||
},
|
||||
{
|
||||
title: "iPad",
|
||||
img: require("./assets/ipad.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple Watch",
|
||||
img: require("./assets/apple-watch.png"),
|
||||
},
|
||||
{
|
||||
title: "AirPods",
|
||||
img: require("./assets/airpods.png"),
|
||||
},
|
||||
{
|
||||
title: "AirTag",
|
||||
img: require("./assets/airtag.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple TV",
|
||||
img: require("./assets/appletv.png"),
|
||||
},
|
||||
{
|
||||
title: "HomePod mini",
|
||||
img: require("./assets/homepod-mini.png"),
|
||||
},
|
||||
{
|
||||
title: "Accessories",
|
||||
img: require("./assets/accessories.png"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 justify-center flex-wrap">
|
||||
{list.map((item, index) => (
|
||||
<div key={index}>
|
||||
<Card isHoverable isPressable className="w-[200px] h-[200px]">
|
||||
<Card.Header className="!p-0">
|
||||
<h5 className="pl-6 pt-2.5">{item.title}</h5>
|
||||
</Card.Header>
|
||||
<Card.Body className="h-full justify-center">
|
||||
<Card.Image alt={item.title} autoResize={false} src={item.img} width={180} />
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithDivider = () => (
|
||||
<Card className="w-max-[400px]" variant="bordered">
|
||||
<Card.Header className="border-b border-border dark:border-border-dark">
|
||||
<strong>Description</strong>
|
||||
</Card.Header>
|
||||
<Card.Body>
|
||||
<p>The Object constructor creates an object wrapper for the given value.</p>
|
||||
</Card.Body>
|
||||
<Card.Footer className="border-t border-border dark:border-border-dark">
|
||||
<p>
|
||||
When called in a non-constructor context, Object behaves identically to{" "}
|
||||
<Code>new Object()</Code>.
|
||||
</p>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const Shadows = () => {
|
||||
const Box = styled("div", {
|
||||
size: "120px",
|
||||
dflex: "center",
|
||||
bg: "$backgroundContrast",
|
||||
br: "$md",
|
||||
});
|
||||
|
||||
const shadows = ["$xs", "$sm", "$md", "$lg", "$xl"];
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2 justify-center">
|
||||
<div className="flex justify-center col-span-2 sm:col-span-5">
|
||||
<strong>Drop shadows</strong>
|
||||
</div>
|
||||
{shadows.map((shadow, index) => (
|
||||
<div key={`${shadow}_${index}`}>
|
||||
<Box css={{dropShadow: shadow}}>
|
||||
<p>Shadow: {shadow}</p>
|
||||
</Box>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex justify-center col-span-2 sm:col-span-5">
|
||||
<strong>Box shadows</strong>
|
||||
</div>
|
||||
{shadows.map((shadow, index) => (
|
||||
<div key={`${shadow}_${index}`}>
|
||||
<Box css={{boxShadow: shadow}}>
|
||||
<p>Shadow: {shadow}</p>
|
||||
</Box>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
//TODO: Input & Button still missing
|
||||
// export const withForm = () => {
|
||||
// return (
|
||||
// <Card css={{mw: "400px"}}>
|
||||
// <Card.Header css={{justifyContent: "center"}}>
|
||||
// <Text size={18}>
|
||||
// Welcome to
|
||||
// <Text b size={18}>
|
||||
// NextUI
|
||||
// </Text>
|
||||
// </Text>
|
||||
// </Card.Header>
|
||||
// <Card.Body css={{px: "$10", pt: "$1", ov: "visible"}}>
|
||||
// <Input
|
||||
// bordered
|
||||
// clearable
|
||||
// fullWidth
|
||||
// color="primary"
|
||||
// contentLeft={<Mail fill="currentColor" />}
|
||||
// placeholder="Email"
|
||||
// size="lg"
|
||||
// />
|
||||
// <Spacer y={0.5} />
|
||||
// <Input
|
||||
// bordered
|
||||
// clearable
|
||||
// fullWidth
|
||||
// color="primary"
|
||||
// contentLeft={<Password />}
|
||||
// placeholder="Password"
|
||||
// size="lg"
|
||||
// />
|
||||
// <Spacer y={0.5} />
|
||||
// <Row align="center" justify="space-between">
|
||||
// <Checkbox>
|
||||
// <Text css={{color: "$accents8"}} size={14}>
|
||||
// Remember me
|
||||
// </Text>
|
||||
// </Checkbox>
|
||||
// <Link css={{color: "$link", fontSize: "$sm"}} href="#">
|
||||
// Forgot password?
|
||||
// </Link>
|
||||
// </Row>
|
||||
// </Card.Body>
|
||||
// <Card.Footer css={{pt: 0}}>
|
||||
// <Grid.Container gap={1} justify="flex-end">
|
||||
// <Grid>
|
||||
// <Button auto flat>
|
||||
// Sign Up
|
||||
// </Button>
|
||||
// </Grid>
|
||||
// <Grid>
|
||||
// <Button auto>Login</Button>
|
||||
// </Grid>
|
||||
// </Grid.Container>
|
||||
// </Card.Footer>
|
||||
// </Card>
|
||||
// );
|
||||
// };
|
||||
@ -25,6 +25,7 @@ const card = tv({
|
||||
"overflow-hidden",
|
||||
"w-full",
|
||||
"height-auto",
|
||||
"outline-none",
|
||||
"text-foreground",
|
||||
"box-border",
|
||||
"dark:bg-content1",
|
||||
@ -53,6 +54,7 @@ const card = tv({
|
||||
"h-auto",
|
||||
"py-5",
|
||||
"px-3",
|
||||
"break-words",
|
||||
"text-left",
|
||||
"overflow-y-auto",
|
||||
"subpixel-antialiased",
|
||||
@ -65,7 +67,6 @@ const card = tv({
|
||||
"items-center",
|
||||
"overflow-hidden",
|
||||
"color-inherit",
|
||||
"rounded-b-xl",
|
||||
"subpixel-antialiased",
|
||||
],
|
||||
},
|
||||
@ -96,30 +97,48 @@ const card = tv({
|
||||
radius: {
|
||||
none: {
|
||||
base: "rounded-none",
|
||||
header: "rounded-t-none",
|
||||
footer: "rounded-b-none",
|
||||
},
|
||||
base: {
|
||||
base: "rounded",
|
||||
header: "rounded-t",
|
||||
footer: "rounded-b",
|
||||
},
|
||||
sm: {
|
||||
base: "rounded-sm",
|
||||
header: "rounded-t-sm",
|
||||
footer: "rounded-b-sm",
|
||||
},
|
||||
md: {
|
||||
base: "rounded-md",
|
||||
header: "rounded-t-md",
|
||||
footer: "rounded-b-md",
|
||||
},
|
||||
lg: {
|
||||
base: "rounded-lg",
|
||||
header: "rounded-t-lg",
|
||||
footer: "rounded-b-lg",
|
||||
},
|
||||
xl: {
|
||||
base: "rounded-xl",
|
||||
header: "rounded-t-xl",
|
||||
footer: "rounded-b-xl",
|
||||
},
|
||||
"2xl": {
|
||||
base: "rounded-2xl",
|
||||
header: "rounded-t-2xl",
|
||||
footer: "rounded-b-2xl",
|
||||
},
|
||||
"3xl": {
|
||||
base: "rounded-3xl",
|
||||
header: "rounded-t-3xl",
|
||||
footer: "rounded-b-3xl",
|
||||
},
|
||||
full: {
|
||||
base: "rounded-full",
|
||||
header: "rounded-t-full",
|
||||
footer: "rounded-b-full",
|
||||
},
|
||||
},
|
||||
fullWidth: {
|
||||
@ -127,15 +146,8 @@ const card = tv({
|
||||
base: "w-full",
|
||||
},
|
||||
},
|
||||
isBordered: {
|
||||
true: {
|
||||
base: "border-2 border-neutral",
|
||||
},
|
||||
},
|
||||
isHoverable: {
|
||||
true: {
|
||||
base: "hover:drop-shadow-lg",
|
||||
},
|
||||
true: {},
|
||||
},
|
||||
isPressable: {
|
||||
true: {base: "cursor-pointer"},
|
||||
@ -147,7 +159,7 @@ const card = tv({
|
||||
},
|
||||
isFooterBlurred: {
|
||||
true: {
|
||||
footer: "backdrop-blur-md backdrop-saturate-[1.8]",
|
||||
footer: "backdrop-blur-xl backdrop-saturate-200",
|
||||
},
|
||||
},
|
||||
isDisabled: {
|
||||
@ -164,7 +176,7 @@ const card = tv({
|
||||
{
|
||||
isHoverable: true,
|
||||
disableAnimation: false,
|
||||
class: "hover:-translate-y-2",
|
||||
class: "hover:-translate-y-1.5",
|
||||
},
|
||||
{
|
||||
isPressable: true,
|
||||
@ -179,7 +191,6 @@ const card = tv({
|
||||
isHoverable: false,
|
||||
isPressable: false,
|
||||
isFocusVisible: false,
|
||||
isBordered: false,
|
||||
isDisabled: false,
|
||||
disableAnimation: false,
|
||||
isFooterBlurred: false,
|
||||
|
||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@ -429,6 +429,8 @@ importers:
|
||||
|
||||
packages/components/card:
|
||||
specifiers:
|
||||
'@nextui-org/avatar': workspace:*
|
||||
'@nextui-org/button': workspace:*
|
||||
'@nextui-org/code': workspace:*
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/drip': workspace:*
|
||||
@ -456,6 +458,8 @@ importers:
|
||||
'@react-aria/interactions': 3.14.0_react@18.2.0
|
||||
'@react-aria/utils': 3.15.0_react@18.2.0
|
||||
devDependencies:
|
||||
'@nextui-org/avatar': link:../avatar
|
||||
'@nextui-org/button': link:../button
|
||||
'@nextui-org/code': link:../code
|
||||
'@nextui-org/link': link:../link
|
||||
'@react-types/shared': 3.17.0_react@18.2.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user