BaliseTonSite

Scaffolding UI Intelligent

Génère des composants complexes (Radix UI / Tailwind) à partir de spécifications fonctionnelles, de la description à l'implémentation en 30 secondes.

3.1Le gabarit de forge

Dans un jeu de fabrication, tu ne forgilles pas une épée en improvisant. Tu suis un plan : matériaux → dimensions → enchantements → finitions. Chaque étape est définie à l'avance.

Générer un composant UI avec l'IA fonctionne pareil. Plus ton spec est précis, plus le composant généré sera directement utilisable sans retouche.

3.2Le template de prompt "scaffold composant"

Prompt : Scaffold composant complexemarkdown
Tu es un dev React/TypeScript senior spécialisé Next.js + Tailwind + Radix UI.

## Composant à créer
Nom : ArticleCard

## Spécification fonctionnelle
Affiche un aperçu d'article de blog.
- Image à la une (avec fallback si absente)
- Catégorie colorée (badge en haut à droite)
- Titre cliquable (lien vers /[slug])
- Extrait tronqué à 2 lignes
- Auteur + date de publication
- Bouton "Lire la suite" avec arrow icon

## Props (TypeScript strict)
interface ArticleCardProps {
  post: WpPost           // le type défini dans lib/types
  variant?: 'default' | 'featured' | 'compact'
  className?: string
}

## Stack
- Tailwind CSS (pas de style inline)
- Radix UI si interaction nécessaire
- Next.js Image pour l'image optimisée
- next/link pour les liens

## Contraintes
- Server Component (pas de 'use client')
- Accessible : rôles ARIA, alt text significatif
- Responsive mobile-first
- Animation hover subtile (scale + shadow)

Résultat typique généré par l'IA :

Résultat : ArticleCard générétsx
import Image from 'next/image';
import Link from 'next/link';
import { cn } from '@/lib/utils';
import type { WpPost } from '@/lib/types';

interface ArticleCardProps {
    post: WpPost;
    variant?: 'default' | 'featured' | 'compact';
    className?: string;
}

const CATEGORY_COLORS: Record<number, string> = {
    1: 'bg-blue-100 text-blue-800',
    2: 'bg-green-100 text-green-800',
};

export function ArticleCard({ post, variant = 'default', className }: ArticleCardProps) {
    const featuredImage = post._embedded?.['wp:featuredmedia']?.[0]?.source_url;
    const author = post._embedded?.author?.[0];
    const categoryId = post.categories[0];

    return (
        <article
            className={cn(
                'group rounded-2xl overflow-hidden bg-white border border-slate-200',
                'shadow-sm hover:shadow-md transition-all duration-300 hover:-translate-y-0.5',
                variant === 'featured' && 'md:col-span-2',
                className
            )}
        >
            {/* Image */}
            {featuredImage && (
                <div className="relative overflow-hidden aspect-video">
                    <Image
                        src={featuredImage}
                        alt={post.title.rendered}
                        fill
                        className="object-cover group-hover:scale-105 transition-transform duration-500"
                        sizes="(max-width: 768px) 100vw, 50vw"
                    />
                    {categoryId && (
                        <span className={cn(
                            'absolute top-3 right-3 text-xs font-medium px-2 py-1 rounded-full',
                            CATEGORY_COLORS[categoryId] ?? 'bg-slate-100 text-slate-700'
                        )}>
                            Catégorie
                        </span>
                    )}
                </div>
            )}

            {/* Contenu */}
            <div className="p-5">
                <h2 className="font-bold text-lg text-slate-900 mb-2 line-clamp-2">
                    <Link href={`/${post.slug}`} className="hover:text-blue-600 transition-colors">
                        {post.title.rendered}
                    </Link>
                </h2>
                <p
                    className="text-slate-500 text-sm mb-4 line-clamp-2"
                    dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }}
                />

                {/* Meta */}
                <div className="flex items-center justify-between">
                    <div className="flex items-center gap-2 text-xs text-slate-400">
                        <span>{author?.name}</span>
                        <span>·</span>
                        <time dateTime={post.date}>
                            {new Date(post.date).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', year: 'numeric' })}
                        </time>
                    </div>
                    <Link
                        href={`/${post.slug}`}
                        className="text-xs font-medium text-blue-600 hover:text-blue-800 flex items-center gap-1"
                        aria-label={`Lire ${post.title.rendered}`}
                    >
                        Lire <i className="fa-solid fa-arrow-right text-xs" />
                    </Link>
                </div>
            </div>
        </article>
    );
}

3.3La variante "composant Radix UI"

Pour les composants interactifs (dialog, dropdown, tooltip…), précise l'utilisation de Radix dans ton prompt :

Prompt : Composant Radix UI + Tailwindmarkdown
Crée un composant React "DeleteConfirmDialog" avec Radix UI Dialog.

Comportement :
- Bouton déclencheur rouge "Supprimer"
- Dialog de confirmation avec titre et description
- Bouton "Annuler" (secondary) et "Confirmer" (destructive, rouge)
- Fermeture avec Escape et clic overlay

Props :
- itemName: string - le nom de l'élément à supprimer
- onConfirm: () => Promise<void> - action asynchrone
- isLoading?: boolean - état de chargement

Stack : Radix UI Dialog + Tailwind CSS + TypeScript strict
Accessibilité : focus trap, aria-describedby, loading state désactive les boutons

Le ratio qualité/temps

Sans scaffold IA

45 min - 1h par composant complexe

Avec scaffold IA

5-10 min avec un prompt précis

Verifie tes acquis

5 questions pour valider ce chapitre

1. Qu'est-ce que le "scaffolding" UI avec l'IA ?

Valide et sauvegarde ce chapitre

Ne perds pas le fil de ton apprentissage. Chaque QCM terminé sauvegarde ton score. Crée ton profil gratuitement pour débloquer toutes les évaluations du site et retrouver tes résultats plus tard.

Commencer l'aventure
Déjà membre ?Connecte-toi