ui-step-wizard
Implements multi-step forms with validation, progress indicators, and audit logging.
Install
mkdir -p .claude/skills/ui-step-wizard && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/14938" && unzip -o skill.zip -d .claude/skills/ui-step-wizard && rm skill.zipInstalls to .claude/skills/ui-step-wizard
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
StepWizard pentru formulare multi-step ERP: validare per step cu Zod, progress indicator, back/next navigation, submit la final. PrintLayout pentru documente printabile cu @media print. AuditTrail — timeline din audit.audit_log.Key capabilities
- →Create multi-step forms with navigation
- →Validate form data per step using Zod schemas
- →Display a progress indicator for multi-step forms
- →Generate printable documents with custom CSS for print media
- →Display an audit trail timeline from audit logs
- →Handle form submission and loading states
How it works
The skill provides React components for a multi-step wizard with Zod validation and navigation, a print layout component for styling documents for printing, and an audit trail component to visualize log data as a timeline. These components are designed for ERP forms.
Inputs & outputs
When to use ui-step-wizard
- →Build ERP forms
- →Manage form state
- →Implement step-based navigation
- →Validate forms with Zod
About this skill
StepWizard, PrintLayout, AuditTrail
StepWizard
// components/common/StepWizard/StepWizard.tsx
import { useState } from 'react';
import { CheckIcon } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import type { ZodSchema } from 'zod';
import type { UseFormReturn } from 'react-hook-form';
export interface WizardStep {
id: string;
title: string;
description?: string;
schema?: ZodSchema; // validare Zod pentru acest step
component: React.ReactNode;
}
interface StepWizardProps {
steps: WizardStep[];
form: UseFormReturn<any>;
onSubmit: (data: any) => void;
isSubmitting?: boolean;
}
export function StepWizard({
steps,
form,
onSubmit,
isSubmitting,
}: StepWizardProps) {
const [current, setCurrent] = useState(0);
const isFirst = current === 0;
const isLast = current === steps.length - 1;
const goNext = async () => {
const step = steps[current];
if (step.schema) {
// Validează doar câmpurile din step-ul curent
const values = form.getValues();
const result = step.schema.safeParse(values);
if (!result.success) {
// Triggerează erorile RHF pentru câmpurile invalide
result.error.issues.forEach((issue) => {
const path = issue.path.join('.');
form.setError(path as any, { message: issue.message });
});
return;
}
}
setCurrent((c) => c + 1);
};
const goBack = () => setCurrent((c) => c - 1);
return (
<div className="space-y-6">
{/* Progress indicator */}
<div className="flex items-center">
{steps.map((step, index) => (
<div key={step.id} className="flex items-center flex-1 last:flex-none">
{/* Circle */}
<div className={cn(
'h-8 w-8 rounded-full flex items-center justify-center',
'text-xs font-semibold shrink-0 border-2 transition-colors',
index < current
? 'bg-primary-500 border-primary-500 text-white'
: index === current
? 'border-primary-500 text-primary-600'
: 'border-border-strong text-text-muted'
)}>
{index < current
? <CheckIcon className="h-4 w-4" />
: index + 1
}
</div>
{/* Label */}
<div className="ml-2 hidden sm:block">
<p className={cn(
'text-xs font-medium',
index === current ? 'text-primary-600' : 'text-text-muted'
)}>
{step.title}
</p>
</div>
{/* Connector */}
{index < steps.length - 1 && (
<div className={cn(
'flex-1 h-0.5 mx-3',
index < current ? 'bg-primary-500' : 'bg-border-default'
)} />
)}
</div>
))}
</div>
{/* Step content */}
<div className="min-h-[300px]">
<div className="mb-4">
<h3 className="text-base font-semibold">{steps[current].title}</h3>
{steps[current].description && (
<p className="text-sm text-text-muted mt-1">
{steps[current].description}
</p>
)}
</div>
{steps[current].component}
</div>
{/* Navigation */}
<div className="flex justify-between pt-4 border-t border-border-default">
<Button
type="button"
variant="outline"
onClick={goBack}
disabled={isFirst}
>
Înapoi
</Button>
{isLast ? (
<Button
type="button"
onClick={form.handleSubmit(onSubmit)}
disabled={isSubmitting}
>
{isSubmitting ? 'Se salvează...' : 'Finalizează'}
</Button>
) : (
<Button type="button" onClick={goNext}>
Continuă
</Button>
)}
</div>
</div>
);
}
PrintLayout — Document Printabil
// components/common/PrintLayout/PrintLayout.tsx
// CSS @media print — ascunde UI, afișează doar documentul
interface PrintLayoutProps {
children: React.ReactNode;
title?: string; // titlu document în header print
}
export function PrintLayout({ children, title }: PrintLayoutProps) {
return (
<>
{/* Buton print — ascuns la printare */}
<div className="print:hidden mb-4 flex gap-2">
<Button variant="outline" onClick={() => window.print()}>
Printează
</Button>
</div>
{/* Conținut document */}
<div className="print:block">
{children}
</div>
{/* Stiluri print */}
<style>{`
@media print {
/* Ascunde UI */
nav, aside, header, .print\\:hidden { display: none !important; }
/* Dimensiuni pagină A4 */
@page {
size: A4 portrait;
margin: 15mm 20mm;
}
body {
font-size: 11pt;
color: #000;
background: #fff;
}
/* Evită ruperea tabelelor între pagini */
table { page-break-inside: avoid; }
tr { page-break-inside: avoid; }
/* Header pe fiecare pagină */
thead { display: table-header-group; }
tfoot { display: table-footer-group; }
}
`}</style>
</>
);
}
// Template factură printabilă
function InvoicePrint({ invoice }: { invoice: InvoiceDetailDto }) {
return (
<PrintLayout title={`Factură ${invoice.invoiceNumber}`}>
<div className="p-8 max-w-3xl mx-auto">
{/* Header */}
<div className="flex justify-between mb-8">
<div>
<h1 className="text-2xl font-bold">FACTURĂ FISCALĂ</h1>
<p className="text-lg font-semibold">{invoice.invoiceNumber}</p>
</div>
<div className="text-right text-sm">
<p>Data: {new Date(invoice.createdAt).toLocaleDateString('ro-RO')}</p>
<p>Scadent: {new Date(invoice.dueDate).toLocaleDateString('ro-RO')}</p>
</div>
</div>
{/* Furnizor / Client */}
<div className="grid grid-cols-2 gap-8 mb-8 text-sm">
<div>
<h3 className="font-semibold mb-1">Furnizor</h3>
{/* date furnizor */}
</div>
<div>
<h3 className="font-semibold mb-1">Client</h3>
<p>{invoice.customerName}</p>
</div>
</div>
{/* Linii */}
<table className="w-full text-sm border-collapse mb-6">
<thead>
<tr className="border-b-2 border-black">
<th className="text-left py-2">Descriere</th>
<th className="text-right py-2">Cant.</th>
<th className="text-right py-2">Preț unit.</th>
<th className="text-right py-2">TVA</th>
<th className="text-right py-2">Total</th>
</tr>
</thead>
<tbody>
{invoice.lines?.map((line, i) => (
<tr key={i} className="border-b border-gray-200">
<td className="py-1">{line.description}</td>
<td className="text-right py-1">{line.quantity}</td>
<td className="text-right py-1 font-mono">
{line.unitPrice.toLocaleString('ro-RO', { minimumFractionDigits: 2 })}
</td>
<td className="text-right py-1">{line.vatRate * 100}%</td>
<td className="text-right py-1 font-mono">
{line.lineTotal.toLocaleString('ro-RO', { minimumFractionDigits: 2 })}
</td>
</tr>
))}
</tbody>
<tfoot>
<tr className="border-t-2 border-black font-semibold">
<td colSpan={4} className="text-right py-2">TOTAL:</td>
<td className="text-right py-2 font-mono">
{invoice.totalAmount.toLocaleString('ro-RO', {
minimumFractionDigits: 2
})} RON
</td>
</tr>
</tfoot>
</table>
</div>
</PrintLayout>
);
}
AuditTrail — Timeline Modificări
// components/common/AuditTrail/AuditTrail.tsx
import { useQuery } from '@tanstack/react-query';
import { api } from '@/lib/axios';
import { format } from 'date-fns';
import { ro } from 'date-fns/locale';
interface AuditEntry {
id: number;
action: string;
userName: string;
oldValues?: Record<string, unknown>;
newValues?: Record<string, unknown>;
createdAt: string;
}
interface AuditTrailProps {
entityType: string;
entityId: string;
}
export function AuditTrail({ entityType, entityId }: AuditTrailProps) {
const { data = [], isLoading } = useQuery({
queryKey: ['audit', entityType, entityId],
queryFn: () => api.get<AuditEntry[]>('/administration/audit', {
params: { entityType, entityId }
}),
staleTime: 60_000,
});
if (isLoading) {
return <div className="space-y-3">
{[1,2,3].map(i => (
<div key={i} className="h-16 bg-surface-muted rounded animate-pulse" />
))}
</div>;
}
if (data.length === 0) {
return (
<p className="text-sm text-text-muted text-center py-8">
Nu există istoric modificări.
</p>
);
}
return (
<div className="space-y-0">
{data.map((entry, index) => (
<div key={entry.id} className="flex gap-3">
{/* Timeline line */}
<div className="flex flex-col items-center">
<div className="h-2.5 w-2.5 rounded-full bg-primary-400 mt-1.5 shrink-0" />
{index < data.length - 1 && (
<div className="flex-1 w-px bg-border-default mt-1" />
)}
</div>
{/* Content */}
<div className="pb-4 min-w-0 fl
---
*Content truncated.*
When not to use it
- →When a single-step form is sufficient
- →When print layouts are not required
- →When audit trail visualization is not needed
Limitations
- →Specific to React and Zod for form validation
- →PrintLayout uses CSS @media print for styling
- →AuditTrail component expects a specific audit log data structure
How it compares
This skill offers pre-built, integrated UI components for complex multi-step forms, print layouts, and audit trails, providing a ready-to-use solution that simplifies development compared to building these functionalities from scratch.
Compared to similar skills
ui-step-wizard side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| ui-step-wizard (this skill) | 0 | 3mo | Review | Intermediate |
| ui-ux-pro-max | 1,909 | 5mo | Review | Intermediate |
| scroll-experience | 101 | 6mo | No flags | Intermediate |
| ui-styling | 12 | 9mo | Review | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
ui-ux-pro-max
nextlevelbuilder
UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient.
scroll-experience
davila7
Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences. Makes websites feel like experiences, not just pages. Use when: scroll animation, parallax, scroll storytelling, interactive story, cinematic website.
ui-styling
mrgoonie
Create beautiful, accessible user interfaces with shadcn/ui components (built on Radix UI + Tailwind), Tailwind CSS utility-first styling, and canvas-based visual designs. Use when building user interfaces, implementing design systems, creating responsive layouts, adding accessible components (dialogs, dropdowns, forms, tables), customizing themes and colors, implementing dark mode, generating visual designs and posters, or establishing consistent styling patterns across applications.
elegant-design
rand
Create world-class, accessible, responsive interfaces with sophisticated interactive elements including chat, terminals, code display, and streaming content. Use when building user interfaces that need professional polish and developer-focused features.
figma
openai
Use the Figma MCP server to fetch design context, screenshots, variables, and assets from Figma, and to translate Figma nodes into production code. Trigger when a task involves Figma URLs, node IDs, design-to-code implementation, or Figma MCP setup and troubleshooting.
interaction-design
wshobson
Design and implement microinteractions, motion design, transitions, and user feedback patterns. Use when adding polish to UI interactions, implementing loading states, or creating delightful user experiences.