Update documentation rules for various contexts and functionalities (#235)

Update cusor rules for various contexts and functionalities
This commit is contained in:
Giancarlo Buomprisco
2025-04-16 09:11:20 +07:00
committed by GitHub
parent 53b09fcb8e
commit 1030c84eee
17 changed files with 854 additions and 276 deletions

View File

@@ -3,16 +3,18 @@ description: Writing Forms with Shadcn UI, Server Actions, Zod
globs: apps/**/*.tsx,packages/**/*.tsx
alwaysApply: false
---
# Forms
- Use React Hook Form for form validation and submission.
- Use Zod for form validation.
- Use the `zodResolver` function to resolve the Zod schema to the form.
- Use Server Actions [server-actions.mdc](mdc:.cursor/rules/server-actions.mdc) for server-side code handling
- Use Sonner for writing toasters for UI feedback
Follow the example below to create all forms:
## Define the schema
Zod schemas should be defined in the `schema` folder and exported, so we can reuse them across a Server Action and the client-side form:
```tsx
@@ -27,19 +29,15 @@ export const CreateNoteSchema = z.object({
## Create the Server Action
Server Actions [server-actions.mdc](mdc:.cursor/rules/server-actions.mdc) can help us create endpoints for our forms.
```tsx
// _lib/server/server-actions.ts
'use server';
import { z } from 'zod';
import { enhanceAction } from '@kit/next/actions';
import { CreateNoteSchema } from '../schema/create-note.schema';
const CreateNoteSchema = z.object({
title: z.string().min(1),
content: z.string().min(1),
});
export const createNoteAction = enhanceAction(
async function (data, user) {
// 1. "data" has been validated against the Zod schema, and it's safe to use
@@ -62,18 +60,22 @@ export const createNoteAction = enhanceAction(
Then create a client component to handle the form submission:
```tsx
// _components/create-note-form.tsx
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Textarea } from '@kit/ui/textarea';
import { Input } from '@kit/ui/input';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@kit/ui/form';
import { toast } from '@kit/ui/sonner';
import { useTranslation } from 'react-i18next';
import { CreateNoteSchema } from '../_lib/schema/create-note.schema';
export function CreateNoteForm() {
const [pending, startTransition] = useTransition();
const { t } = useTranslation();
const form = useForm({
resolver: zodResolver(CreateNoteSchema),
@@ -85,58 +87,58 @@ export function CreateNoteForm() {
const onSubmit = (data) => {
startTransition(async () => {
try {
await createNoteAction(data);
} catch {
// handle error
}
await toast.promise(createNoteAction(data), {
loading: t('notes:creatingNote`),
success: t('notes:createNoteSuccess`),
error: t('notes:createNoteError`)
})
});
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
<Form {...form}>
<FormField name={'title'} render={({ field }) => (
<FormItem>
<FormLabel>
<span className={'text-sm font-medium'}>Title</span>
</FormLabel>
<Form {...form}>
<FormField name={'title'} render={({ field }) => (
<FormItem>
<FormLabel>
<span className={'text-sm font-medium'}>Title</span>
</FormLabel>
<FormControl>
<input
type={'text'}
className={'w-full'}
placeholder={'Title'}
{...field}
/>
</FormControl>
<FormControl>
<Input
type={'text'}
className={'w-full'}
placeholder={'Title'}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />
<FormMessage />
</FormItem>
)} />
<FormField name={'content'} render={({ field }) => (
<FormItem>
<FormLabel>
<span className={'text-sm font-medium'}>Content</span>
</FormLabel>
<FormField name={'content'} render={({ field }) => (
<FormItem>
<FormLabel>
<span className={'text-sm font-medium'}>Content</span>
</FormLabel>
<FormControl>
<textarea
className={'w-full'}
placeholder={'Content'}
{...field}
/>
</FormControl>
<FormControl>
<Textarea
className={'w-full'}
placeholder={'Content'}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />
<FormMessage />
</FormItem>
)} />
<button disabled={pending} type={'submit'} className={'w-full'}>
Submit
</button>
</Form>
<button disabled={pending} type={'submit'} className={'w-full'}>
Submit
</button>
</Form>
</form>
);
}