# Thèmes
Documentation [Tailwind CSS v4](https://tailwindcss.com/docs)
SmartMaker utilise **TailwindCSS v4** pour la stylisation. Cette version introduit une nouvelle syntaxe CSS-first avec ''@theme'' et ''@layer''.
## Configuration TailwindCSS 4
### Installation
TailwindCSS 4 est intégré via le plugin Vite :
```
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [
react(),
tailwindcss(),
],
});
```
### Point d'entrée CSS
```
/* src/assets/styles/style.css */
@import "tailwindcss";
@layer theme, base, components;
@import "./theme.css" layer(theme);
@import "./base.css" layer(base);
```
## Définir un thème
### Variables CSS avec @theme
```
/* src/assets/styles/theme.css */
@theme {
/* Couleurs principales */
--color-primary: #5fbabf;
--color-primary-light: #8cd4d8;
--color-primary-dark: #4a9599;
--color-secondary: #fc8c8c;
--color-secondary-light: #fdb5b5;
--color-secondary-dark: #e67070;
/* Couleurs sémantiques */
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6;
/* Couleurs de fond */
--color-background: #ffffff;
--color-surface: #f8fafc;
--color-muted: #f1f5f9;
/* Couleurs de texte */
--color-foreground: #0f172a;
--color-foreground-muted: #64748b;
/* Espacements customs */
--spacing-page: 1rem;
--spacing-card: 1.5rem;
/* Rayons de bordure */
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-full: 9999px;
/* Ombres */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
/* Typographie */
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'Fira Code', monospace;
}
```
### Utilisation dans les composants
Les variables ''@theme'' génèrent automatiquement des classes Tailwind :
```
Fond primaire
Texte atténué
Carte avec espacement
```
## Styles de base
### Reset et règles globales
```
/* src/assets/styles/base.css */
@layer base {
* {
@apply box-border p-0 m-0;
-webkit-tap-highlight-color: transparent;
}
*::-webkit-scrollbar {
display: none;
}
html {
@apply scroll-smooth antialiased;
}
body {
@apply bg-background text-foreground font-sans;
}
/* Focus visible pour accessibilité */
:focus-visible {
@apply outline-2 outline-offset-2 outline-primary;
}
/* Liens */
a {
@apply text-primary hover:text-primary-dark transition-colors;
}
/* Inputs */
input, textarea, select {
@apply bg-surface border border-gray-200 rounded-md;
@apply focus:border-primary focus:ring-1 focus:ring-primary;
}
}
```
## Créer des thèmes multiples
### Structure des fichiers
```
src/assets/
├── styles/
│ ├── style.css # Point d'entrée
│ ├── theme.css # Variables par défaut
│ └── base.css # Règles globales
└── themes/
├── light.css # Thème clair
└── dark.css # Thème sombre
```
### Thème clair (défaut)
```
/* src/assets/themes/light.css */
@theme {
--color-background: #ffffff;
--color-surface: #f8fafc;
--color-foreground: #0f172a;
--color-foreground-muted: #64748b;
}
```
### Thème sombre
```
/* src/assets/themes/dark.css */
@theme {
--color-background: #0f172a;
--color-surface: #1e293b;
--color-foreground: #f8fafc;
--color-foreground-muted: #94a3b8;
}
```
### Chargement dynamique
```
// src/main.jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./assets/styles/style.css";
// Charger le thème depuis les settings
const theme = localStorage.getItem('theme') || 'light';
import(`./assets/themes/${theme}.css`);
import { App } from "./App";
createRoot(document.getElementById("root")).render(
);
```
### Hook useTheme
```
import { useGlobalStates } from '@cap-rel/smartcommon';
import { useEffect } from 'react';
export const useTheme = () => {
const [theme, setTheme] = useGlobalStates('settings.theme');
useEffect(() => {
// Appliquer le thème au document
document.documentElement.setAttribute('data-theme', theme);
// Charger le CSS du thème
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = `/themes/${theme}.css`;
document.head.appendChild(link);
return () => {
document.head.removeChild(link);
};
}, [theme]);
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return { theme, setTheme, toggleTheme };
};
```
### Composant ThemeToggle
```
import { useTheme } from '../hooks/useTheme';
const ThemeToggle = () => {
const { theme, toggleTheme } = useTheme();
return (
);
};
```
## Variantes de composants
### Avec SmartCommon
SmartCommon permet de définir des variantes pour les composants :
```
// appConfig.js
export const config = {
components: {
variants: {
Button: {
default: "bg-primary text-white rounded-md px-4 py-2",
secondary: "bg-secondary text-white rounded-md px-4 py-2",
outline: "border-2 border-primary text-primary rounded-md px-4 py-2",
ghost: "text-primary hover:bg-primary/10 rounded-md px-4 py-2",
},
Input: {
default: "bg-surface border border-gray-200 rounded-md p-3",
filled: "bg-muted border-0 rounded-md p-3",
underline: "border-b-2 border-gray-200 rounded-none p-3",
},
},
},
};
```
### Utilisation
```
import { Button, Input } from '@cap-rel/smartcommon';
const MyForm = () => {
return (
);
};
```
## Classes utilitaires personnalisées
### Avec @layer components
```
/* src/assets/styles/components.css */
@layer components {
.card {
@apply bg-surface rounded-lg shadow-md p-card;
}
.btn {
@apply inline-flex items-center justify-center;
@apply px-4 py-2 rounded-md font-medium;
@apply transition-all duration-200;
@apply focus:outline-none focus:ring-2 focus:ring-offset-2;
}
.btn-primary {
@apply btn bg-primary text-white;
@apply hover:bg-primary-dark;
@apply focus:ring-primary;
}
.btn-secondary {
@apply btn bg-secondary text-white;
@apply hover:bg-secondary-dark;
@apply focus:ring-secondary;
}
.input {
@apply w-full px-4 py-3 rounded-md;
@apply bg-surface border border-gray-200;
@apply focus:border-primary focus:ring-1 focus:ring-primary;
@apply placeholder:text-foreground-muted;
}
}
```
## Dark mode automatique
### Avec prefers-color-scheme
```
/* src/assets/styles/theme.css */
@theme {
--color-background: #ffffff;
--color-foreground: #0f172a;
}
@media (prefers-color-scheme: dark) {
@theme {
--color-background: #0f172a;
--color-foreground: #f8fafc;
}
}
```
### Avec classe CSS
```
/* Thème par défaut (clair) */
@theme {
--color-background: #ffffff;
--color-foreground: #0f172a;
}
/* Thème sombre via classe */
.dark {
--color-background: #0f172a;
--color-foreground: #f8fafc;
}
```
```
// Toggle dark mode
document.documentElement.classList.toggle('dark');
```
## Conseils
### Performance
* Utilisez ''@theme'' pour les variables réutilisées
* Évitez les classes Tailwind dynamiques (''bg-${color}'')
* Préférez les variantes de composants
### Organisation
* Un fichier pour les variables (''theme.css'')
* Un fichier pour les règles de base (''base.css'')
* Un fichier par thème additionnel
### Accessibilité
* Respectez les contrastes WCAG
* Testez avec ''prefers-reduced-motion''
* Utilisez ''focus-visible'' pour le focus
## Voir aussi
* [[configuration|Configuration]] - Variantes de composants
* [[smartcommon|SmartCommon]] - Composants disponibles
* [[animations|Animations]] - Transitions de pages