From f36878e939085d3e1e5ad168c13d013b0a76a2ab Mon Sep 17 00:00:00 2001 From: spivakov83 Date: Tue, 27 Jan 2026 17:23:31 +0200 Subject: [PATCH 1/2] skills added --- app/page.tsx | 3 + app/skills/page.tsx | 55 +++++++++ components/skill-builder-form.tsx | 185 ++++++++++++++++++++++++++++++ components/ui/label.tsx | 23 ++++ components/ui/textarea.tsx | 23 ++++ file-templates/skill-template.md | 9 ++ lib/skill-templates.ts | 131 +++++++++++++++++++++ 7 files changed, 429 insertions(+) create mode 100644 app/skills/page.tsx create mode 100644 components/skill-builder-form.tsx create mode 100644 components/ui/label.tsx create mode 100644 components/ui/textarea.tsx create mode 100644 file-templates/skill-template.md create mode 100644 lib/skill-templates.ts diff --git a/app/page.tsx b/app/page.tsx index 3715200..8972680 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -61,6 +61,9 @@ export default function LandingPage() { + diff --git a/app/skills/page.tsx b/app/skills/page.tsx new file mode 100644 index 0000000..f3e864b --- /dev/null +++ b/app/skills/page.tsx @@ -0,0 +1,55 @@ +import { Github } from "lucide-react" +import Link from "next/link" +import type { Metadata } from "next" + +import { Button } from "@/components/ui/button" +import { SkillBuilderForm } from "@/components/skill-builder-form" +import { AnimatedBackground } from "@/components/AnimatedBackground" + +export const metadata: Metadata = { + title: "Claude Skill Builder | DevContext", + description: "Create custom skills for Claude AI. Generate properly formatted Skill.md files with metadata and instructions.", +} + +export default function SkillsPage() { + return ( +
+ + +
+
+ + DevContext + +
+ + +
+
+ +
+
+

+ Claude Custom Skill Builder +

+

+ Create Skill.md files to give Claude new capabilities. Define metadata, + dependencies, and instructions in a standardized format. +

+
+ + +
+
+
+ ) +} diff --git a/components/skill-builder-form.tsx b/components/skill-builder-form.tsx new file mode 100644 index 0000000..b31e2b2 --- /dev/null +++ b/components/skill-builder-form.tsx @@ -0,0 +1,185 @@ +"use client" + +import { useState, useEffect } from "react" +import { Download, Wand2 } from "lucide-react" +import { skillTemplates, type SkillTemplate } from "@/lib/skill-templates" + +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Textarea } from "@/components/ui/textarea" + +interface SkillData { + name: string + description: string + dependencies: string + content: string +} + +const DEFAULT_CONTENT = `## Steps +1. [Step 1] +2. [Step 2] + +## Examples +User: [Input] +Assistant: [Output] +` + +export function SkillBuilderForm() { + const [data, setData] = useState({ + name: "", + description: "", + dependencies: "", + content: DEFAULT_CONTENT, + }) + + const [preview, setPreview] = useState("") + + useEffect(() => { + // Generate preview + let output = `name: ${data.name || "My Skill"}\n` + output += `description: ${data.description || "Skill description"}\n` + + if (data.dependencies) { + output += `dependencies: ${data.dependencies}\n` + } + + output += `\n${data.content}` + + setPreview(output) + }, [data]) + + const handleChange = (field: keyof SkillData, value: string) => { + setData((prev) => ({ ...prev, [field]: value })) + } + + const handleDownload = () => { + const blob = new Blob([preview], { type: "text/markdown" }) + const url = URL.createObjectURL(blob) + const link = document.createElement("a") + link.href = url + // Use the skill name for filename, replacing spaces with dashes, or default + const safeName = (data.name || "skill").toLowerCase().replace(/[^a-z0-9]+/g, "-") + link.download = `${safeName}.md` + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(url) + } + + const loadTemplate = (template: SkillTemplate) => { + setData({ + name: template.skillData.name, + description: template.skillData.description, + dependencies: template.skillData.dependencies, + content: template.skillData.content, + }) + } + + return ( +
+
+
+

Start with a template

+
+

Select a template to pre-fill the skill configuration.

+
+ {skillTemplates.map((template) => ( + + ))} +
+
+ +
+ + + Skill Configuration + + Define metadata and instructions for your custom Claude skill. + + + +
+ + ) => handleChange("name", e.target.value)} + /> +
+ +
+ +