widget-generator
Generate customizable widget plugins for the prompts.chat feed system
DeepseekModel
Curated skill
Quality Excellent · 90
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=f-prompts-chat-windsurf-skills-widget-generator-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name widget-generator description Generate customizable widget plugins for the prompts.chat feed system Widget Generator Skill This skill guides creation of widget plugins for prompts.chat . Widgets are injected into prompt feeds to display promotional content, sponsor cards, or custom interactive components. Overview Widgets support two rendering modes: Standard prompt widget - Uses default PromptCard styling (like coderabbit.ts ) Custom render widget - Full custom React component (like book.tsx ) Prerequisites Before creating a widget, gather from the user: Parameter Required Description Widget ID ✅ Unique identifier (kebab-case, e.g., my-sponsor ) Widget Name ✅ Display name for the plugin Rendering Mode ✅ standard or custom Sponsor Info ❌ Name, logo, logoDark, URL (for sponsored widgets) Step 1: Gather Widget Configuration Ask the user for the following configuration options: Basic Info - id: string (unique, kebab-case) - name: string (display name) - slug: string (URL-friendly identifier) - title: string (card title) - description: string (card description) Content (for standard mode) - content: string (prompt content, can be multi-line markdown) - type: "TEXT" | "STRUCTURED" - structuredFormat?: "json" | "yaml" (if type is STRUCTURED) Categorization - tags?: string[] (e.g., ["AI", "Development"]) - category?: string (e.g., "Development", "Writing") Action Button - actionUrl?: string (CTA link) - actionLabel?: string (CTA button text) Sponsor (optional) - sponsor?: { name: string logo: string (path to light mode logo) logoDark?: string (path to dark mode logo) url: string (sponsor website) } Positioning Strategy - positioning: { position: number (0-indexed start position, default: 2) mode: "once" | "repeat" (default: "once") repeatEvery?: number (for repeat mode, e.g., 30) maxCount?: number (max occurrences, default: 1 for once, unlimited for repeat) } Injection Logic - shouldInject?: (context) => boolean Context contains: - filters.q: search query - filters.category: category name - filters.categorySlug: category slug - filters.tag: tag filter - filters.sort: sort option - itemCount: total items in feed Step 2: Create Widget File Standard Widget (TypeScript only) Create file: src/lib/plugins/widgets/{widget-id}.ts import type { WidgetPlugin } from "./types" ; export const {widgetId} Widget : WidgetPlugin = { id : "{widget-id}" , name : "{Widget Name}" , prompts : [ { id : "{prompt-id}" , slug : "{prompt-slug}" , title : "{Title}" , description : "{Description}" , content : `{Multi-line content here}` , type : "TEXT" , // Optional sponsor sponsor : { name : "{Sponsor Name}" , logo : "/sponsors/{sponsor}.svg" , logoDark : "/sponsors/{sponsor}-dark.svg" , url : "{sponsor-url}" , }, tags : [ "{Tag1}" , "{Tag2}" ], category : "{Category}" , actionUrl : "{action-url}" , actionLabel : "{Action Label}" , positioning : { position : 2 , mode : "repeat" , repeatEvery : 50 , maxCount : 3 , }, shouldInject : ( context ) => { const { filters } = context; // Always show when no filters active if (!filters?. q && !filters?. category && !filters?. tag ) { return true ; } // Add custom filter logic here return false ; }, }, ], }; Custom Render Widget (TSX with React) Create file: src/lib/plugins/widgets/{widget-id}.tsx import Link from "next/link" ; import Image from "next/image" ; import { Button } from "@/components/ui/button" ; import type { WidgetPlugin } from "./types" ; function { WidgetName } Widget () { return ( < div className = "group border rounded-[var(--radius)] overflow-hidden hover:border-foreground/20 transition-colors bg-gradient-to-br from-primary/5 via-background to-primary/10 p-5" > {/* Custom widget content */} < div className = "flex flex-col items-center gap-4" > {/* Image/visual element */} < div className = "relative w-full aspect-video" > < Image src = "/path/to/image.jpg" alt = "{Alt text}" fill className = "object-cover rounded-lg" /> </ div > {/* Content */} < div className = "w-full text-center" > < h3 className = "font-semibold text-base mb-1.5" > {Title} </ h3 > < p className = "text-xs text-muted-foreground mb-4" > {Description} </ p > < Button asChild size = "sm" className = "w-full" > < Link href = "{action-url}" > {Action Label} </ Link > </ Button > </ div > </ div > </ div > ); } export const {widgetId} Widget : WidgetPlugin = { id : "{widget-id}" , name : "{Widget Name}" , prompts : [ { id : "{prompt-id}" , slug : "{prompt-slug}" , title : "{Title}" , description : "{Description}" , content : "" , type : "TEXT" , tags : [ "{Tag1}" , "{Tag2}" ], category : "{Category}" , actionUrl : "{action-url}" , actionLabel : "{Action Label}" , positioning : { position : 10 , mode : "repeat" , repeatEvery : 60 , maxCount : 4 , }, shouldInject : () => true , render : () => <{ WidgetName } Widget />, }, ], }; Step 3: Register Widget Edit src/lib/plugins/widgets/index.ts : Add import at top: import { {widgetId} Widget } from "./{widget-id}" ; Add to widgetPlugins array: const widgetPlugins : WidgetPlugin [] = [ coderabbitWidget, bookWidget, {widgetId} Widget , // Add new widget ]; Step 4: Add Sponsor Assets (if applicable) If the widget has a sponsor: Add light logo: public/sponsors/{sponsor}.svg Add dark logo (optional): public/sponsors/{sponsor}-dark.svg Positioning Examples Show once at position 5 positioning : { position : 5 , mode : "once" , } Repeat every 30 items, max 5 times positioning : { position : 3 , mode : "repeat" , repeatEvery : 30 , maxCount : 5 , } Unlimited repeating positioning : { position : 2 , mode : "repeat" , repeatEvery : 25 , // No maxCount = unlimited } shouldInject Examples Always show shouldInject : () => true , Only when no filters active shouldInject : ( context ) => { const { filters } = context; return !filters?. q && !filters?. category && !filters?. tag ; }, Show for specific categories shouldInject : ( context ) => { const slug = context. filters ?. categorySlug ?. toLowerCase (); return slug?. includes ( "development" ) || slug?. includes ( "coding" ); }, Show when search matches keywords shouldInject : ( context ) => { const query = context. filters ?. q ?. toLowerCase () || "" ; return [ "ai" , "automation" , "workflow" ]. some ( kw => query. includes (kw)); }, Show only when enough items shouldInject : ( context ) => { return (context. itemCount ?? 0 ) >= 10 ; }, Custom Render Patterns Card with gradient background <div className= "border rounded-[var(--radius)] overflow-hidden bg-gradient-to-br from-primary/5 via-background to-primary/10 p-5" > Sponsor badge <div className= "flex items-center gap-2 mb-2" > < span className = "text-xs font-medium text-primary" > Sponsored </ span > </div> Responsive image <div className= "relative w-full aspect-video" > < Image src = "/image.jpg" alt = "..." fill className = "object-cover" /> </div> CTA button < Button asChild size= "sm" className= "w-full" > < Link href = "https://example.com" > Learn More < ArrowRight className = "ml-2 h-3.5 w-3.5" /> </ Link > </ Button > Verification Run type check: npx tsc --noEmit Start dev server: npm run dev Navigate to /discover or /feed to verify widget appears at configured positions Type Reference interface WidgetPrompt { id : string ; slug : string ; title : string ; description : string ; content : string ; type : "TEXT" | "STRUCTURED" ; structuredFormat ?: "json" | "yaml" ; sponsor ?: { name : string ; logo : string ; logoDark ?: string ; url : string ; }; tags ?: string []; category ?: string ; actionUrl ?: string ; actionLabel ?: string ; positioning ?: { position ?: number ; // Default: 2 mode ?: "once" | "repeat" ; // Default: "once" repeatEvery ?: number ; // For repeat mode maxCount ?: number ; // Max occurrences }; shouldInject ?: ( context : WidgetContext ) => boolean ; render ?: () => ReactNode ; // For custom rendering } interface WidgetPlugin { id : string ; name : string ; prompts : WidgetPrompt []; } Common Issues Issue Solution Widget not showing Check shouldInject logic, verify registration in index.ts TypeScript errors Ensure imports from ./types , check sponsor object shape Styling issues Use Tailwind classes, match existing widget patterns Position wrong Remember positions are 0-indexed, check repeatEvery value
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.