بنقرة واحدة
shadcn-stack
Next.js 15 + shadcn/ui + Server Components patterns for server-rendered React applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Next.js 15 + shadcn/ui + Server Components patterns for server-rendered React applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Add email verification, password reset, and account management emails to Better Auth using Resend.
TypeScript authentication framework (framework-agnostic). Features: email/password, OAuth (Google, GitHub, Discord), 2FA (TOTP, SMS), passkeys/WebAuthn, session management, RBAC, rate limiting, database adapters. Actions: implement, configure, secure authentication systems. Keywords: Better Auth, authentication, authorization, OAuth, email/password, 2FA, MFA, TOTP, passkeys, WebAuthn, session management, RBAC, rate limiting, database adapter, TypeScript auth, social login, Google auth, GitHub auth, Discord auth, email verification, password reset. Use when: implementing TypeScript auth, adding OAuth providers, setting up 2FA/MFA, managing sessions, configuring RBAC, building secure auth systems.
Build websites and web applications using Telefonica's Mistica design system React components. Use this skill when writing React UI code with @telefonica/mistica, creating pages, layouts, forms, or any user interface that should follow Telefonica's design guidelines. Triggers on tasks involving Mistica components, Telefonica branding, or when the user mentions Mistica.
Provides shadcn/ui component library expertise for React applications with shadcn/cli v4, preset system, RTL support, unified radix-ui, and OKLCH theming. Use when implementing UI components, design systems, CLI workflows, or registry authoring with shadcn/ui.
React 19 performance optimization guidelines for concurrent rendering, Server Components, actions, hooks, and memoization (formerly react-19). This skill should be used when writing React 19 components, using concurrent features, or optimizing re-renders. This skill does NOT cover Next.js-specific features like App Router, next.config.js, or Next.js caching (use nextjs-16-app-router skill). For client-side form validation with React Hook Form, use react-hook-form skill.
Implement, review, debug, and refactor TanStack Start React Server Components in React 19 apps. Use when tasks mention @tanstack/react-start/rsc, renderServerComponent, createCompositeComponent, CompositeComponent, renderToReadableStream, createFromReadableStream, createFromFetch, Composite Components, React Flight streams, loader or query owned RSC caching, router.invalidate, structuralSharing: false, selective SSR, stale names like renderRsc or .validator, or migration from Next App Router RSC patterns. Do not use for generic SSR or non-TanStack RSC frameworks except brief comparison.
| name | shadcn-stack |
| description | Next.js 15 + shadcn/ui + Server Components patterns for server-rendered React applications |
| agents | ["blaze","nova","tap","spark"] |
| context7_libraries | ["/vercel/next.js","/shadcn-ui/ui","/tanstack/query","/react-hook-form/react-hook-form","/effect-ts/effect"] |
| llm_docs | ["shadcn","tanstack","effect"] |
Modern Next.js architecture optimized for server-side rendering, SEO, and progressive enhancement.
| Library | Purpose | Install |
|---|---|---|
| Next.js 15 | Full-stack React framework | next |
| shadcn/ui | Accessible UI components | npx shadcn@latest add [component] |
| React Query | Client-side data caching | @tanstack/react-query |
| React Hook Form | Form state management | react-hook-form |
| Effect | Type-safe validation & errors | effect, @hookform/resolvers |
| Tailwind CSS | Utility-first styling | tailwindcss |
app/
├── layout.tsx # Root layout
├── page.tsx # Home page (/)
├── loading.tsx # Loading UI
├── error.tsx # Error boundary
├── dashboard/
│ ├── layout.tsx # Dashboard layout
│ ├── page.tsx # /dashboard
│ └── settings/
│ └── page.tsx # /dashboard/settings
└── api/
└── users/
└── route.ts # API route
// app/users/page.tsx - Server Component by default
import { getUsers } from '@/lib/db';
export default async function UsersPage() {
const users = await getUsers(); // Direct database access
return (
<div>
<h1>Users</h1>
<UserList users={users} />
</div>
);
}
// components/user-search.tsx
'use client';
import { useState } from 'react';
import { Input } from '@/components/ui/input';
export function UserSearch({ onSearch }: { onSearch: (query: string) => void }) {
const [query, setQuery] = useState('');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
onSearch(e.target.value);
};
return (
<Input
value={query}
onChange={handleChange}
placeholder="Search users..."
/>
);
}
// app/actions/users.ts
'use server';
import { revalidatePath } from 'next/cache';
import { Schema, Effect } from 'effect';
import { db } from '@/lib/db';
const CreateUserSchema = Schema.Struct({
name: Schema.String.pipe(Schema.minLength(2)),
email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+\.[^@]+$/)),
role: Schema.Literal('admin', 'user', 'guest'),
});
export async function createUser(formData: FormData) {
const validated = Schema.decodeUnknownSync(CreateUserSchema)({
name: formData.get('name'),
email: formData.get('email'),
role: formData.get('role'),
});
await db.user.create({ data: validated });
revalidatePath('/users');
}
export async function deleteUser(id: string) {
await db.user.delete({ where: { id } });
revalidatePath('/users');
}
// app/users/create/page.tsx
import { createUser } from '@/app/actions/users';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
export default function CreateUserPage() {
return (
<form action={createUser}>
<Input name="name" placeholder="Name" required />
<Input name="email" type="email" placeholder="Email" required />
<select name="role">
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
<Button type="submit">Create User</Button>
</form>
);
}
'use client';
import { useFormStatus } from 'react-dom';
import { Button } from '@/components/ui/button';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<Button type="submit" disabled={pending}>
{pending ? 'Creating...' : 'Create User'}
</Button>
);
}
npx shadcn@latest init
npx shadcn@latest add button card input form table dialog
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
export function UserCard({ user }: { user: User }) {
return (
<Card>
<CardHeader>
<CardTitle>{user.name}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">{user.email}</p>
</CardContent>
<CardFooter>
<Button variant="outline">Edit</Button>
<Button variant="destructive">Delete</Button>
</CardFooter>
</Card>
);
}
'use client';
import { useState } from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
export function CreateUserDialog() {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>Create User</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create New User</DialogTitle>
<DialogDescription>
Add a new user to the system.
</DialogDescription>
</DialogHeader>
<CreateUserForm onSuccess={() => setOpen(false)} />
</DialogContent>
</Dialog>
);
}
'use client';
import { useForm } from 'react-hook-form';
import { effectTsResolver } from '@hookform/resolvers/effect-ts';
import { Schema } from 'effect';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
const formSchema = Schema.Struct({
name: Schema.String.pipe(Schema.minLength(2, { message: () => 'Name must be at least 2 characters' })),
email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+\.[^@]+$/, { message: () => 'Invalid email address' })),
});
type FormValues = Schema.Schema.Type<typeof formSchema>;
export function CreateUserForm({ onSuccess }: { onSuccess: () => void }) {
const form = useForm<FormValues>({
resolver: effectTsResolver(formSchema),
defaultValues: { name: '', email: '' },
});
async function onSubmit(values: FormValues) {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(values),
});
if (response.ok) {
onSuccess();
}
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="John Doe" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" placeholder="john@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? 'Creating...' : 'Create'}
</Button>
</form>
</Form>
);
}
'use client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: async () => {
const response = await fetch('/api/users');
return response.json();
},
});
}
export function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (newUser: CreateUserInput) => {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(newUser),
});
return response.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
// app/providers.tsx
'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';
export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
// app/users/page.tsx
import { getUsers } from '@/lib/db';
import { UsersTable } from './users-table';
export default async function UsersPage() {
const users = await getUsers();
return <UsersTable data={users} />;
}
// app/users/users-table.tsx
'use client';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { deleteUser } from '@/app/actions/users';
export function UsersTable({ data }: { data: User[] }) {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((user) => (
<TableRow key={user.id}>
<TableCell>{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>
<Badge variant={user.role === 'admin' ? 'default' : 'secondary'}>
{user.role}
</Badge>
</TableCell>
<TableCell>
<form action={deleteUser.bind(null, user.id)}>
<Button variant="destructive" size="sm" type="submit">
Delete
</Button>
</form>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}
// app/users/loading.tsx
import { Skeleton } from '@/components/ui/skeleton';
export default function Loading() {
return (
<div className="space-y-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-64 w-full" />
</div>
);
}
// app/users/error.tsx
'use client';
import { Button } from '@/components/ui/button';
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div className="flex flex-col items-center gap-4 py-16">
<h2 className="text-xl font-semibold">Something went wrong!</h2>
<p className="text-muted-foreground">{error.message}</p>
<Button onClick={reset}>Try again</Button>
</div>
);
}
// app/users/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Users | My App',
description: 'Manage users in the system',
openGraph: {
title: 'Users',
description: 'Manage users in the system',
},
};
export default async function UsersPage() {
// ...
}
// app/users/[id]/page.tsx
import { Metadata } from 'next';
import { getUser } from '@/lib/db';
type Props = { params: Promise<{ id: string }> };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { id } = await params;
const user = await getUser(id);
return {
title: `${user.name} | My App`,
description: `Profile for ${user.name}`,
};
}