Skip to content

Commit

Permalink
feat(packages/ui): add <Card /> and <Form /> components & their stori…
Browse files Browse the repository at this point in the history
…es (#614)

Adds `<Card />` and `<Form />` components to our design system/component
lib.
  • Loading branch information
usirin authored Aug 8, 2023
1 parent d454766 commit ce04332
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 3 deletions.
2 changes: 1 addition & 1 deletion apps/ui/stories/Avatar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react";

import { UserAvatar } from "@kampus/ui-next/components/user-avatar";
import { UserAvatar } from "@kampus/ui-next";

const meta = {
component: UserAvatar,
Expand Down
68 changes: 68 additions & 0 deletions apps/ui/stories/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use client";

import type { Meta, StoryObj } from "@storybook/react";

import {
Button,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Input,
Label,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@kampus/ui-next";

const meta = {
title: "Card",
component: Card,
} satisfies Meta<typeof Card>;

export default meta;
type Story = StoryObj<typeof meta>;
export const Default = {
render: () => {
return (
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>Deploy your new project in one-click.</CardDescription>
</CardHeader>
<CardContent>
<form>
<div className="grid w-full items-center gap-4">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="Name of your project" />
</div>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="framework">Framework</Label>
<Select>
<SelectTrigger id="framework">
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="next">Next.js</SelectItem>
<SelectItem value="sveltekit">SvelteKit</SelectItem>
<SelectItem value="astro">Astro</SelectItem>
<SelectItem value="nuxt">Nuxt.js</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</form>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline">Cancel</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>
);
},
} satisfies Story;
115 changes: 115 additions & 0 deletions apps/ui/stories/Form.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"use client";

import type { Meta, StoryObj } from "@storybook/react";

import {
Button,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
Input,
Textarea,
useForm,
z,
} from "@kampus/ui-next";

// 1. create a form schema

const formSchema = z.object({
title: z.string().min(1, { message: "baslik en az 1 karakterli" }),
content: z.string().optional(),
});

const FormStory = () => {
// create a form state helper using `useForm` hook
const form = useForm(formSchema, {
defaultValues: {
title: "",
content: "",
},
});

const onSubmit = (values: z.infer<typeof formSchema>) => {
console.log({ values });
};

return (
<Card>
<CardHeader>
<CardTitle>Add new post</CardTitle>
<CardDescription>Share your links & thoughts with us</CardDescription>
</CardHeader>
<Form {...form}>
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
<form onSubmit={form.handleSubmit(onSubmit)}>
<CardContent className="space-y-4">
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input placeholder="What's your title?" {...field} />
</FormControl>
<FormDescription>Write a descriptive title for your post.</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="content"
render={({ field }) => (
<FormItem>
<FormLabel>Content</FormLabel>
<FormControl>
<Textarea placeholder="Add your thoughts ..." {...field} />
</FormControl>
<FormDescription>Add your thoughts about this post.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
<CardFooter className="space-x-2">
<Button variant="outline" type="reset" onClick={() => form.reset()}>
Reset form
</Button>
<Button type="submit">Submit</Button>
</CardFooter>
</form>
</Form>
</Card>
);
};

export const Default = {
render: () => {
return (
<>
<FormStory />
</>
);
},
} satisfies Story;

const meta = {
title: "Form",
component: FormStory,
} satisfies Meta<typeof FormStory>;

export default meta;

type Story = StoryObj<typeof meta>;
1 change: 1 addition & 0 deletions apps/ui/stories/Toast.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default meta;
type Story = StoryObj<typeof meta>;
export const Default = {
render: () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { toast } = useToast();

return (
Expand Down
28 changes: 27 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions packages/ui/components/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from "react";

import { cn } from "@kampus/ui-next/utils";

const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("bg-card text-card-foreground rounded-lg border shadow-sm", className)}
{...props}
/>
)
);
Card.displayName = "Card";

const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
)
);
CardHeader.displayName = "CardHeader";

const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn("text-2xl font-semibold leading-none tracking-tight", className)}
{...props}
/>
)
);
CardTitle.displayName = "CardTitle";

const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p ref={ref} className={cn("text-muted-foreground text-sm", className)} {...props} />
));
CardDescription.displayName = "CardDescription";

const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
)
);
CardContent.displayName = "CardContent";

const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
)
);
CardFooter.displayName = "CardFooter";

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
Loading

0 comments on commit ce04332

Please sign in to comment.