← スキル一覧に戻る

web-artifacts-builder
by tienbm92
Personal AI context base used for bootstrapping new projects and feature development. Acts as the backbone for architecture, domain rules, and reusable design patterns.
⭐ 0🍴 0📅 2026年1月26日
SKILL.md
name: web-artifacts-builder description: 'Build high-quality React + Tailwind + shadcn/ui web artifacts. Tạo interactive components, dashboards, landing pages với production-ready code.'
Web Artifacts Builder Skill
Skill này provide guidelines và patterns cho building high-quality web artifacts using modern stack: React + Tailwind CSS + shadcn/ui.
Khi Nào Sử Dụng
- Tạo interactive web components
- Build dashboards và admin panels
- Create landing pages
- Prototype UI concepts nhanh
- Build standalone web tools
- Create data visualization components
Tech Stack
| Layer | Technology |
|---|---|
| Framework | React 18+ |
| Styling | Tailwind CSS v3+ |
| Components | shadcn/ui |
| Icons | Lucide React |
| Charts | Recharts |
| Animation | Framer Motion |
Component Patterns
Basic Component Structure
import { cn } from "@/lib/utils";
interface ComponentProps {
className?: string;
children?: React.ReactNode;
}
export function Component({ className, children }: ComponentProps) {
return (
<div className={cn("base-classes", className)}>
{children}
</div>
);
}
With State
import { useState } from "react";
import { Button } from "@/components/ui/button";
export function Counter() {
const [count, setCount] = useState(0);
return (
<div className="flex items-center gap-4">
<Button
variant="outline"
onClick={() => setCount(c => c - 1)}
>
-
</Button>
<span className="text-2xl font-bold">{count}</span>
<Button onClick={() => setCount(c => c + 1)}>
+
</Button>
</div>
);
}
Card Pattern
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export function FeatureCard({ title, description, icon: Icon }) {
return (
<Card className="hover:shadow-lg transition-shadow">
<CardHeader>
<Icon className="h-8 w-8 mb-2 text-primary" />
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
</CardHeader>
<CardContent>
{/* Content */}
</CardContent>
<CardFooter>
{/* Actions */}
</CardFooter>
</Card>
);
}
Layout Patterns
Page Layout
export function PageLayout({ children }) {
return (
<div className="min-h-screen bg-background">
<header className="border-b">
<div className="container mx-auto px-4 py-4">
{/* Nav */}
</div>
</header>
<main className="container mx-auto px-4 py-8">
{children}
</main>
<footer className="border-t mt-auto">
<div className="container mx-auto px-4 py-4">
{/* Footer */}
</div>
</footer>
</div>
);
}
Grid Layouts
// 3-column responsive grid
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{items.map(item => <Card key={item.id} {...item} />)}
</div>
// Sidebar layout
<div className="flex">
<aside className="w-64 border-r h-screen sticky top-0">
{/* Sidebar */}
</aside>
<main className="flex-1 p-6">
{/* Content */}
</main>
</div>
// Dashboard grid
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
<StatCard />
<StatCard />
<StatCard />
<StatCard />
</div>
Common Components
Stat Card
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { ArrowUpIcon, ArrowDownIcon } from "lucide-react";
interface StatCardProps {
title: string;
value: string | number;
change?: number;
icon?: React.ComponentType<{ className?: string }>;
}
export function StatCard({ title, value, change, icon: Icon }: StatCardProps) {
const isPositive = change && change > 0;
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
{Icon && <Icon className="h-4 w-4 text-muted-foreground" />}
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{value}</div>
{change !== undefined && (
<p className={cn(
"text-xs flex items-center",
isPositive ? "text-green-600" : "text-red-600"
)}>
{isPositive ? <ArrowUpIcon className="h-3 w-3" /> : <ArrowDownIcon className="h-3 w-3" />}
{Math.abs(change)}%
</p>
)}
</CardContent>
</Card>
);
}
Data Table
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
export function DataTable({ columns, data }) {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
{columns.map(col => (
<TableHead key={col.key}>{col.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{data.map((row, i) => (
<TableRow key={i}>
{columns.map(col => (
<TableCell key={col.key}>{row[col.key]}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Form Pattern
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export function ContactForm() {
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
// Submit logic
setIsLoading(false);
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="message">Message</Label>
<Textarea
id="message"
placeholder="Your message..."
required
/>
</div>
<Button type="submit" disabled={isLoading}>
{isLoading ? "Sending..." : "Send Message"}
</Button>
</form>
);
}
Charts with Recharts
Line Chart
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts";
export function SimpleLineChart({ data }) {
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Line
type="monotone"
dataKey="value"
stroke="hsl(var(--primary))"
strokeWidth={2}
/>
</LineChart>
</ResponsiveContainer>
);
}
Bar Chart
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts";
export function SimpleBarChart({ data }) {
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Bar dataKey="value" fill="hsl(var(--primary))" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
);
}
Animation with Framer Motion
Fade In
import { motion } from "framer-motion";
export function FadeIn({ children, delay = 0 }) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay }}
>
{children}
</motion.div>
);
}
Stagger Children
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
};
const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
};
export function StaggerList({ items }) {
return (
<motion.ul variants={container} initial="hidden" animate="show">
{items.map(i => (
<motion.li key={i.id} variants={item}>
{i.content}
</motion.li>
))}
</motion.ul>
);
}
Tailwind Tips
Responsive Prefixes
sm: → 640px
md: → 768px
lg: → 1024px
xl: → 1280px
2xl: → 1536px
Common Patterns
// Center everything
className="flex items-center justify-center"
// Full-bleed with max-width
className="w-full max-w-4xl mx-auto px-4"
// Aspect ratio
className="aspect-video" // 16:9
className="aspect-square" // 1:1
// Truncate text
className="truncate" // single line
className="line-clamp-2" // 2 lines
// Glass effect
className="bg-white/80 backdrop-blur-sm"
// Smooth scroll
className="scroll-smooth"
Artifact Quality Checklist
- Responsive design (mobile-first)
- Dark mode support (
dark:variants) - Loading states
- Error handling
- Accessibility (proper labels, focus states)
- Consistent spacing (4px grid)
- Meaningful animations (không excessive)
- Clean code structure
- TypeScript types
- Comments for complex logic
スコア
総合スコア
70/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です