option
MaisonMaison Skill Autres frontend-ui-dark-ts

frontend-ui-dark-ts

microsoft/skills microsoft/skills

Créez des applications React au thème sombre à l'aide de Tailwind CSS, avec des thèmes personnalisés, des effets de « glassmorphism » et des animations Framer Motion pour des tableaux de bord, des panneaux d'administration ou des interfaces riches en données.

...Développer tout
3
Heure mise à jour 14 septembre 2026

Thème sombre pour interface utilisateur front-end (TypeScript)

Un système d'interface utilisateur React moderne au thème sombre, utilisant Tailwind CSS et Framer Motion. Conçu pour les tableaux de bord, les panneaux d'administration et les applications riches en données, avec des effets de « glassmorphism » et des animations raffinées.

Stack

Pack Version Objectif
React ^18.x Framework d'interface utilisateur
react-dom ^18.x Rendu DOM
react-router-dom ^6.x Routage
framer-motion ^11.x Animations
clsx ^2.x Fusion de classes
tailwindcss ^3.x Stylisation
vite ^5.x Outil de compilation
TypeScript ^5.x Sécurité des types

Démarrage rapide

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install framer-motion clsx react-router-dom
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Structure du projet

public/
├── favicon.ico                    # Favicon classique (32x32)
├── favicon.svg                    # Favicon SVG moderne
├── apple-touch-icon.png           # Écran d'accueil iOS (180x180)
├── og-image.png                   # Image de partage sur les réseaux sociaux (1200x630)
└── site.webmanifest               # Manifeste PWA
src/
├── assets/
│   └── fonts/
│       ├── Segoe UI.ttf
│       ├── Segoe UI Bold.ttf
│       ├── Segoe UI Italic.ttf
│       └── Segoe UI Bold Italic.ttf
├── components/
│   ├── ui/
│   │   ├── Button.tsx
│   │   ├── Card.tsx
│   │   ├── Input.tsx
│   │   ├── Badge.tsx
│   │   ├── Dialog.tsx
│   │   ├── Tabs.tsx
│   │   └── index.ts
│   └── layout/
│       ├── AppShell.tsx
│       ├── Sidebar.tsx
│       └── PageHeader.tsx
├── styles/
│   └── globals.css
├── App.tsx
└── main.tsx

Configuration

index.html

Le point d'entrée HTML avec la fenêtre d'affichage mobile, les favicons et les balises méta sociales :



  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    Nom de l’application
  
  
    

public/site.webmanifest

Manifeste PWA pour les applications web installables :

{
  "name": "Nom de l'application",
  "short_name": "App",
  "icons": [
    { "src": "/favicon.ico", "sizes": "32x32", "type": "image/x-icon" },
    { "src": "/apple-touch-icon.png", "sizes": "180x180", "type": "image/png" }
  ],
  "theme_color": "#18181B",
  "background_color": "#18181B",
  "display": "standalone"
}

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      fontFamily: {
        sans: ['Segoe UI', 'system-ui', 'sans-serif'],
      },
      colors : {
        brand : {
          DEFAULT : '#8251EE',
          hover : '#9366F5',
          light : '#A37EF5',
          subtle : 'rgba(130, 81, 238, 0.15)',
        },
        neutre : {
          bg1 : 'hsl(240, 6 %, 10 %)',
          bg2 : 'hsl(240, 5 %, 12 %)',
          bg3 : 'hsl(240, 5 %, 14 %)',
          bg4 : 'hsl(240, 4 %, 18 %)',
          bg5 : 'hsl(240, 4 %, 22 %)',
          bg6 : « hsl(240, 4 %, 26 %) »,
        },
        text : {
          primary : '#FFFFFF',
          secondary : '#A1A1AA',
          muted : '#71717A',
        },
        border: {
          subtle: 'hsla(0, 0 %, 100 %, 0,08)',
          DEFAULT : 'hsla(0, 0 %, 100 %, 0,12)',
          strong : 'hsla(0, 0 %, 100 %, 0,20)',
        },
        status : {
          success : '#10B981',
          warning : '#F59E0B',
          error : '#EF4444',
          info : '#3B82F6',
        },
        dataviz : {
          violet : '#8251EE',
          bleu : '#3B82F6',
          vert : '#10B981',
          jaune : '#F59E0B',
          rouge : '#EF4444',
          rose : '#EC4899',
          cyan : '#06B6D4',
        },
      },
      borderRadius : {
        DEFAULT : '0,5 rem',
        lg : '0,75 rem',
        xl : '1 rem',
      },
      boxShadow : {
        glow : '0 0 20px rgba(130, 81, 238, 0,3)',
        'glow-lg' : '0 0 40px rgba(130, 81, 238, 0,4)',
      },
      backdropBlur : {
        xs : '2px',
      },
      animation : {
        'fade-in' : 'fadeIn 0.3s ease-out',
        'slide-up' : 'slideUp 0.3s ease-out',
        'slide-down' : 'slideDown 0.3s ease-out',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp : {
          '0 %' : { opacity : '0', transform : 'translateY(10px)' },
          '100 %' : { opacity : '1', transform : 'translateY(0)' },
        },
        slideDown : {
          '0%' : { opacity : '0', transform : 'translateY(-10px)' },
          '100%' : { opacity : '1', transform : 'translateY(0)' },
        },
      },
      // Mobile : marges de sécurité pour les appareils à encoche
      spacing : {
        'safe-top' : 'env(safe-area-inset-top)',
        'safe-bottom' : 'env(safe-area-inset-bottom)',
        'safe-left' : 'env(safe-area-inset-left)',
        'safe-right' : 'env(safe-area-inset-right)',
      },
      // Mobile : tailles minimales des cibles tactiles (44 px selon les directives d'Apple/Google)
      minHeight : {
        'touch' : '44px',
      },
      minWidth : {
        'touch' : '44px',
      },
    },
  },
  plugins : [],
};

postcss.config.js

export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

src/styles/globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;

/* Polices de caractères */
@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI Bold.ttf') format('truetype');
  font-weight: 700;
  font-style : normal ;
  font-display : swap ;
}

@font-face {
  font-family : 'Segoe UI' ;
  src : url('../assets/fonts/Segoe UI Italic.ttf') format('truetype') ;
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'Segoe UI';
  src : url('../assets/fonts/Segoe UI Bold Italic.ttf') format('truetype');
  font-weight : 700 ;
  font-style : italic ;
  font-display : swap ;
}

/* Propriétés CSS personnalisées */
:root {
  /* Couleurs de la marque */
  --color-brand: #8251EE;
  --color-brand-hover: #9366F5;
  --color-brand-light: #A37EF5;
  --color-brand-subtle: rgba(130, 81, 238, 0.15);

  /* Arrière-plans neutres */
  --color-bg-1: hsl(240, 6%, 10%);
  --color-bg-2 : hsl(240, 5 %, 12 %) ;
  --color-bg-3 : hsl(240, 5 %, 14 %) ;
  --color-bg-4: hsl(240, 4%, 18%);
  --color-bg-5: hsl(240, 4%, 22%);
  --color-bg-6 : hsl(240, 4 %, 26 %) ;

  /* Couleurs du texte */
  --color-text-primary : #FFFFFF ;
  --color-text-secondary : #A1A1AA ;
  --color-text-muted : #71717A;

  /* Couleurs des bordures */
  --color-border-subtle : hsla(0, 0%, 100%, 0,08);
  --color-border-default : hsla(0, 0 %, 100 %, 0,12) ;
  --color-border-strong : hsla(0, 0 %, 100 %, 0,20) ;

  /* Couleurs d'état */
  --color-success : #10B981 ;
  --color-warning : #F59E0B ;
  --color-error : #EF4444 ;
  --color-info : #3B82F6 ;

  /* Espacement */
  --spacing-xs : 0,25rem ;
  --spacing-sm : 0,5rem ;
  --spacing-md : 1rem ;
  --spacing-lg : 1,5rem ;
  --spacing-xl : 2rem ;
  --spacing-2xl : 3rem ;

  /* Rayon des bordures */
  --radius-sm : 0,375rem ;
  --radius-md : 0,5rem ;
  --radius-lg : 0,75 rem ;
  --radius-xl : 1 rem ;

  /* Transitions */
  --transition-fast : 150 ms ease ;
  --transition-normal : 200 ms ease ;
  --transition-slow : 300 ms ease ;
}

/* Styles de base */
html {
  color-scheme : dark ;
}

body {
  @apply bg-neutral-bg1 text-text-primary font-sans antialiased ;
  min-height: 100vh;
}

/* Styles de focus */
*:focus-visible {
  @apply outline-none ring-2 ring-brand ring-offset-2 ring-offset-neutral-bg1;
}

/* Style de la barre de défilement */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  @apply bg-neutral-bg2;
}

::-webkit-scrollbar-thumb {
  @apply bg-neutral-bg5 rounded-full;
}

::-webkit-scrollbar-thumb:hover {
  @apply bg-neutral-bg6;
}

/* Classes utilitaires « Glass » */
@layer components {
  .glass {
    @apply backdrop-blur-md bg-white/5 border border-white/10;
  }

  .glass-card {
    @apply backdrop-blur-md bg-white/5 border border-white/10 rounded-xl;
  }

  .glass-panel {
    @apply backdrop-blur-lg bg-black/40 border border-white/5;
  }

  .glass-overlay {
    @apply backdrop-blur-sm bg-black/60;
  }

  .glass-input {
    @apply backdrop-blur-sm bg-white/5 border border-white/10 focus:border-brand focus:bg-white/10;
  }
}

/* Utilitaires d'animation */
@layer utilities {
  .animate-in {
    animation: fadeIn 0.3s ease-out, slideUp 0.3s ease-out;
  }
}

src/main.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './styles/globals.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
 
    
      
    
   
);

src/App.tsx

import { Routes, Route } from 'react-router-dom';
import { AnimatePresence } from 'framer-motion';
import { AppShell } from './components/layout/AppShell';
import { Dashboard } from './pages/Dashboard';
import { Settings } from './pages/Settings';

export default function App() {
  return (   
    
      
        
          <Route path="/" element={} />
          <Route path="/settings" element={} />
        
      
    
   );
}

Modèles d’animation

Variantes de mouvement Framer

// Fondu d'entrée au chargement
export const fadeIn = {
  initial: { opacity: 0 },
  animate: { opacity: 1 },
  exit: { opacity: 0 },
  transition: { duration: 0.2 },
};

// Glissement vers le haut lors de l'affichage
export const slideUp = {
  initial: { opacity: 0, y: 20 },
  animate: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: 20 },
  transition: { duration: 0.3, ease: 'easeOut' },
};

// Mise à l’échelle au survol (pour les boutons/cartes)
export const scaleOnHover = {
  whileHover: { scale: 1,02 },
  whileTap: { scale: 0,98 },
  transition : { type : 'spring', stiffness : 400, damping : 17 },
};

// Décalage des éléments enfants
export const staggerContainer = {
  hidden : { opacity : 0 },
  visible : {
    opacity : 1,
    transition : {
      staggerChildren : 0,05,
      delayChildren : 0,1,
    },
  },
};

export const staggerItem = {
  caché : { opacité : 0, y : 10 },
  visible : {
    opacité : 1,
    y : 0,
    transition : { durée : 0,2, ease : 'easeOut' },
  },
};

Conteneur de transition de page

import { motion } from 'framer-motion';
import { ReactNode } from 'react';

interface PageTransitionProps {
  children: ReactNode;
}

export function PageTransition({ children }: PageTransitionProps) {
  return ( 
    
      {children}
    
  );
}

Motifs d’effets de verre

Carte « verre »

Titre de la carte

Le contenu de la carte va ici.

Panneau en verre (barre latérale)


Superposition modale en verre


  
    {/* Contenu de la fenêtre modale */}
  

Typographie

Élément Classes
Titre de la page text-2xl font-semibold text-text-primary
Titre de la section text-lg font-semibold text-text-primary
Titre de la fiche text-base font-medium text-text-primary
Corps du texte text-sm text-text-secondary
Légende text-xs text-text-muted
Étiquette text-sm font-medium text-text-secondary

Utilisation des couleurs

Cas d’utilisation Couleur Classe
Action principale Violet de la marque bg-marque texte-blanc
Effet au survol principal Survol de la marque survol : bg-marque-survol
Arrière-plan de la page Arrière-plan neutre 1 bg-neutre-bg1
Arrière-plan de la carte Arrière-plan neutre 2 bg-neutre-bg2
Surface en relief Arrière-plan neutre 3 bg-neutre-bg3
Arrière-plan de saisie Arrière-plan neutre bg2 bg-neutre-bg2
Focalisation de la saisie Arrière-plan neutre bg3 focus:bg-neutre-bg3
Bordure par défaut Bordure par défaut border-border
Bordure subtile Bordure subtile border-border-subtle
Succès Statut : réussite text-status-success
Avertissement Statut « avertissement » text-status-warning
Erreur Statut « erreur » text-status-error

Fichiers associés

  • Jets de conception — Système complet de couleurs, d'espacement et d'échelles typographiques
  • Composants — Bouton, carte, champ de saisie, boîte de dialogue, onglets, etc.
  • Modèles — Mises en page, navigation, listes, formulaires
Voir sur GitHub
---
name: frontend-ui-dark-ts
description: Build dark-themed React applications using Tailwind CSS with custom theming, glassmorphism effects, and Framer Motion animations for dashboards, admin panels, or data-rich interfaces.
license: MIT
---

# Frontend UI Dark Theme (TypeScript)

A modern dark-themed React UI system using **Tailwind CSS** and **Framer Motion**. Designed for dashboards, admin panels, and data-rich applications with glassmorphism effects and tasteful animations.

## Stack

| Package | Version | Purpose |
|---------|---------|---------|
| `react` | ^18.x | UI framework |
| `react-dom` | ^18.x | DOM rendering |
| `react-router-dom` | ^6.x | Routing |
| `framer-motion` | ^11.x | Animations |
| `clsx` | ^2.x | Class merging |
| `tailwindcss` | ^3.x | Styling |
| `vite` | ^5.x | Build tool |
| `typescript` | ^5.x | Type safety |

## Quick Start

```bash
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install framer-motion clsx react-router-dom
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

## Project Structure

```
public/
├── favicon.ico                    # Classic favicon (32x32)
├── favicon.svg                    # Modern SVG favicon
├── apple-touch-icon.png           # iOS home screen (180x180)
├── og-image.png                   # Social sharing image (1200x630)
└── site.webmanifest               # PWA manifest
src/
├── assets/
│   └── fonts/
│       ├── Segoe UI.ttf
│       ├── Segoe UI Bold.ttf
│       ├── Segoe UI Italic.ttf
│       └── Segoe UI Bold Italic.ttf
├── components/
│   ├── ui/
│   │   ├── Button.tsx
│   │   ├── Card.tsx
│   │   ├── Input.tsx
│   │   ├── Badge.tsx
│   │   ├── Dialog.tsx
│   │   ├── Tabs.tsx
│   │   └── index.ts
│   └── layout/
│       ├── AppShell.tsx
│       ├── Sidebar.tsx
│       └── PageHeader.tsx
├── styles/
│   └── globals.css
├── App.tsx
└── main.tsx
```

## Configuration

### index.html

The HTML entry point with mobile viewport, favicons, and social meta tags:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
    
    <!-- Favicons -->
    <link rel="icon" href="/favicon.ico" sizes="32x32" />
    <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
    <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
    <link rel="manifest" href="/site.webmanifest" />
    
    <!-- Theme color for mobile browser chrome -->
    <meta name="theme-color" content="#18181B" />
    
    <!-- Open Graph -->
    <meta property="og:type" content="website" />
    <meta property="og:title" content="App Name" />
    <meta property="og:description" content="App description" />
    <meta property="og:image" content="https://example.com/og-image.png" />
    <meta property="og:url" content="https://example.com" />
    
    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:title" content="App Name" />
    <meta name="twitter:description" content="App description" />
    <meta name="twitter:image" content="https://example.com/og-image.png" />
    
    <title>App Name</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

### public/site.webmanifest

PWA manifest for installable web apps:

```json
{
  "name": "App Name",
  "short_name": "App",
  "icons": [
    { "src": "/favicon.ico", "sizes": "32x32", "type": "image/x-icon" },
    { "src": "/apple-touch-icon.png", "sizes": "180x180", "type": "image/png" }
  ],
  "theme_color": "#18181B",
  "background_color": "#18181B",
  "display": "standalone"
}
```

### tailwind.config.js

```js
/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      fontFamily: {
        sans: ['Segoe UI', 'system-ui', 'sans-serif'],
      },
      colors: {
        brand: {
          DEFAULT: '#8251EE',
          hover: '#9366F5',
          light: '#A37EF5',
          subtle: 'rgba(130, 81, 238, 0.15)',
        },
        neutral: {
          bg1: 'hsl(240, 6%, 10%)',
          bg2: 'hsl(240, 5%, 12%)',
          bg3: 'hsl(240, 5%, 14%)',
          bg4: 'hsl(240, 4%, 18%)',
          bg5: 'hsl(240, 4%, 22%)',
          bg6: 'hsl(240, 4%, 26%)',
        },
        text: {
          primary: '#FFFFFF',
          secondary: '#A1A1AA',
          muted: '#71717A',
        },
        border: {
          subtle: 'hsla(0, 0%, 100%, 0.08)',
          DEFAULT: 'hsla(0, 0%, 100%, 0.12)',
          strong: 'hsla(0, 0%, 100%, 0.20)',
        },
        status: {
          success: '#10B981',
          warning: '#F59E0B',
          error: '#EF4444',
          info: '#3B82F6',
        },
        dataviz: {
          purple: '#8251EE',
          blue: '#3B82F6',
          green: '#10B981',
          yellow: '#F59E0B',
          red: '#EF4444',
          pink: '#EC4899',
          cyan: '#06B6D4',
        },
      },
      borderRadius: {
        DEFAULT: '0.5rem',
        lg: '0.75rem',
        xl: '1rem',
      },
      boxShadow: {
        glow: '0 0 20px rgba(130, 81, 238, 0.3)',
        'glow-lg': '0 0 40px rgba(130, 81, 238, 0.4)',
      },
      backdropBlur: {
        xs: '2px',
      },
      animation: {
        'fade-in': 'fadeIn 0.3s ease-out',
        'slide-up': 'slideUp 0.3s ease-out',
        'slide-down': 'slideDown 0.3s ease-out',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { opacity: '0', transform: 'translateY(10px)' },
          '100%': { opacity: '1', transform: 'translateY(0)' },
        },
        slideDown: {
          '0%': { opacity: '0', transform: 'translateY(-10px)' },
          '100%': { opacity: '1', transform: 'translateY(0)' },
        },
      },
      // Mobile: safe area insets for notched devices
      spacing: {
        'safe-top': 'env(safe-area-inset-top)',
        'safe-bottom': 'env(safe-area-inset-bottom)',
        'safe-left': 'env(safe-area-inset-left)',
        'safe-right': 'env(safe-area-inset-right)',
      },
      // Mobile: minimum touch target sizes (44px per Apple/Google guidelines)
      minHeight: {
        'touch': '44px',
      },
      minWidth: {
        'touch': '44px',
      },
    },
  },
  plugins: [],
};
```

### postcss.config.js

```js
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};
```

### src/styles/globals.css

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Font faces */
@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI Italic.ttf') format('truetype');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'Segoe UI';
  src: url('../assets/fonts/Segoe UI Bold Italic.ttf') format('truetype');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

/* CSS Custom Properties */
:root {
  /* Brand colors */
  --color-brand: #8251EE;
  --color-brand-hover: #9366F5;
  --color-brand-light: #A37EF5;
  --color-brand-subtle: rgba(130, 81, 238, 0.15);

  /* Neutral backgrounds */
  --color-bg-1: hsl(240, 6%, 10%);
  --color-bg-2: hsl(240, 5%, 12%);
  --color-bg-3: hsl(240, 5%, 14%);
  --color-bg-4: hsl(240, 4%, 18%);
  --color-bg-5: hsl(240, 4%, 22%);
  --color-bg-6: hsl(240, 4%, 26%);

  /* Text colors */
  --color-text-primary: #FFFFFF;
  --color-text-secondary: #A1A1AA;
  --color-text-muted: #71717A;

  /* Border colors */
  --color-border-subtle: hsla(0, 0%, 100%, 0.08);
  --color-border-default: hsla(0, 0%, 100%, 0.12);
  --color-border-strong: hsla(0, 0%, 100%, 0.20);

  /* Status colors */
  --color-success: #10B981;
  --color-warning: #F59E0B;
  --color-error: #EF4444;
  --color-info: #3B82F6;

  /* Spacing */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  --spacing-2xl: 3rem;

  /* Border radius */
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;

  /* Transitions */
  --transition-fast: 150ms ease;
  --transition-normal: 200ms ease;
  --transition-slow: 300ms ease;
}

/* Base styles */
html {
  color-scheme: dark;
}

body {
  @apply bg-neutral-bg1 text-text-primary font-sans antialiased;
  min-height: 100vh;
}

/* Focus styles */
*:focus-visible {
  @apply outline-none ring-2 ring-brand ring-offset-2 ring-offset-neutral-bg1;
}

/* Scrollbar styling */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  @apply bg-neutral-bg2;
}

::-webkit-scrollbar-thumb {
  @apply bg-neutral-bg5 rounded-full;
}

::-webkit-scrollbar-thumb:hover {
  @apply bg-neutral-bg6;
}

/* Glass utility classes */
@layer components {
  .glass {
    @apply backdrop-blur-md bg-white/5 border border-white/10;
  }

  .glass-card {
    @apply backdrop-blur-md bg-white/5 border border-white/10 rounded-xl;
  }

  .glass-panel {
    @apply backdrop-blur-lg bg-black/40 border border-white/5;
  }

  .glass-overlay {
    @apply backdrop-blur-sm bg-black/60;
  }

  .glass-input {
    @apply backdrop-blur-sm bg-white/5 border border-white/10 focus:border-brand focus:bg-white/10;
  }
}

/* Animation utilities */
@layer utilities {
  .animate-in {
    animation: fadeIn 0.3s ease-out, slideUp 0.3s ease-out;
  }
}
```

### src/main.tsx

```tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './styles/globals.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);
```

### src/App.tsx

```tsx
import { Routes, Route } from 'react-router-dom';
import { AnimatePresence } from 'framer-motion';
import { AppShell } from './components/layout/AppShell';
import { Dashboard } from './pages/Dashboard';
import { Settings } from './pages/Settings';

export default function App() {
  return (
    <AppShell>
      <AnimatePresence mode="wait">
        <Routes>
          <Route path="/" element={<Dashboard />} />
          <Route path="/settings" element={<Settings />} />
        </Routes>
      </AnimatePresence>
    </AppShell>
  );
}
```

## Animation Patterns

### Framer Motion Variants

```tsx
// Fade in on mount
export const fadeIn = {
  initial: { opacity: 0 },
  animate: { opacity: 1 },
  exit: { opacity: 0 },
  transition: { duration: 0.2 },
};

// Slide up on mount
export const slideUp = {
  initial: { opacity: 0, y: 20 },
  animate: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: 20 },
  transition: { duration: 0.3, ease: 'easeOut' },
};

// Scale on hover (for buttons/cards)
export const scaleOnHover = {
  whileHover: { scale: 1.02 },
  whileTap: { scale: 0.98 },
  transition: { type: 'spring', stiffness: 400, damping: 17 },
};

// Stagger children
export const staggerContainer = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.05,
      delayChildren: 0.1,
    },
  },
};

export const staggerItem = {
  hidden: { opacity: 0, y: 10 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.2, ease: 'easeOut' },
  },
};
```

### Page Transition Wrapper

```tsx
import { motion } from 'framer-motion';
import { ReactNode } from 'react';

interface PageTransitionProps {
  children: ReactNode;
}

export function PageTransition({ children }: PageTransitionProps) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -20 }}
      transition={{ duration: 0.3, ease: 'easeOut' }}
    >
      {children}
    </motion.div>
  );
}
```

## Glass Effect Patterns

### Glass Card

```tsx
<div className="glass-card p-6">
  <h2 className="text-lg font-semibold text-text-primary">Card Title</h2>
  <p className="text-text-secondary mt-2">Card content goes here.</p>
</div>
```

### Glass Panel (Sidebar)

```tsx
<aside className="glass-panel w-64 h-screen p-4">
  <nav className="space-y-2">
    {/* Navigation items */}
  </nav>
</aside>
```

### Glass Modal Overlay

```tsx
<motion.div
  className="fixed inset-0 glass-overlay flex items-center justify-center z-50"
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  exit={{ opacity: 0 }}
>
  <motion.div
    className="glass-card p-6 max-w-md w-full mx-4"
    initial={{ scale: 0.95, opacity: 0 }}
    animate={{ scale: 1, opacity: 1 }}
    exit={{ scale: 0.95, opacity: 0 }}
  >
    {/* Modal content */}
  </motion.div>
</motion.div>
```

## Typography

| Element | Classes |
|---------|---------|
| Page title | `text-2xl font-semibold text-text-primary` |
| Section title | `text-lg font-semibold text-text-primary` |
| Card title | `text-base font-medium text-text-primary` |
| Body text | `text-sm text-text-secondary` |
| Caption | `text-xs text-text-muted` |
| Label | `text-sm font-medium text-text-secondary` |

## Color Usage

| Use Case | Color | Class |
|----------|-------|-------|
| Primary action | Brand purple | `bg-brand text-white` |
| Primary hover | Brand hover | `hover:bg-brand-hover` |
| Page background | Neutral bg1 | `bg-neutral-bg1` |
| Card background | Neutral bg2 | `bg-neutral-bg2` |
| Elevated surface | Neutral bg3 | `bg-neutral-bg3` |
| Input background | Neutral bg2 | `bg-neutral-bg2` |
| Input focus | Neutral bg3 | `focus:bg-neutral-bg3` |
| Border default | Border default | `border-border` |
| Border subtle | Border subtle | `border-border-subtle` |
| Success | Status success | `text-status-success` |
| Warning | Status warning | `text-status-warning` |
| Error | Status error | `text-status-error` |

## Related Files

- [Design Tokens](./references/design-tokens.md) — Complete color system, spacing, typography scales
- [Components](./references/components.md) — Button, Card, Input, Dialog, Tabs, and more
- [Patterns](./references/patterns.md) — Page layouts, navigation, lists, forms

Tous les fichiers

0 fichiers

Installer frontend-ui-dark-ts

Téléchargez et décompressez les fichiers de compétences dans votre répertoire .claude/skills/.

Télécharger le ZIP

Clonez le dépôt et copiez les fichiers de compétence dans votre projet.

git clone https://github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-typescript/skills/frontend-ui-dark-ts # Copy SKILL.md to your .claude/skills/ directory

Copier Copier
Configuration rapide: Copiez le dossier de la compétence dans .claude/skills/ Claude détectera automatiquement la compétence et l'utilisera

Compétences similaires

multica-creating-agents
Heure mise à jour 12 août 2026
tilemaps
Heure mise à jour 4 août 2026
v4-new-features
Heure mise à jour 4 août 2026
agent-github-pr-manager
Heure mise à jour 3 août 2026
OR