🧰 Story 1.2: configuration tailwind
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,7 +2,6 @@
|
|||||||
vendor/
|
vendor/
|
||||||
node_modules/
|
node_modules/
|
||||||
logs/*.log
|
logs/*.log
|
||||||
assets/css/output.css
|
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
190
assets/css/input.css
Normal file
190
assets/css/input.css
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
html {
|
||||||
|
@apply scroll-smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
@apply bg-background text-text-primary font-sans antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { @apply text-display text-text-primary; }
|
||||||
|
h2 { @apply text-heading text-text-primary; }
|
||||||
|
h3 { @apply text-subheading text-text-primary; }
|
||||||
|
p { @apply text-body text-text-secondary; }
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply text-primary hover:text-primary-light transition-colors duration-150;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus-visible {
|
||||||
|
@apply outline-none ring-2 ring-primary ring-offset-2 ring-offset-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
@apply bg-primary/30 text-text-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.container-content {
|
||||||
|
@apply max-w-content mx-auto px-4 sm:px-6 lg:px-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
@apply inline-flex items-center justify-center gap-2
|
||||||
|
px-6 py-3 font-medium rounded-lg
|
||||||
|
transition-all duration-150
|
||||||
|
focus:outline-none focus:ring-2 focus:ring-offset-2
|
||||||
|
focus:ring-offset-background
|
||||||
|
disabled:opacity-50 disabled:cursor-not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@apply btn bg-primary text-background
|
||||||
|
hover:bg-primary-light active:bg-primary-dark
|
||||||
|
focus:ring-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
@apply btn border-2 border-primary text-primary bg-transparent
|
||||||
|
hover:bg-primary hover:text-background
|
||||||
|
focus:ring-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
@apply btn text-primary bg-transparent
|
||||||
|
hover:text-primary-light hover:bg-surface-light
|
||||||
|
focus:ring-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
@apply inline-flex items-center px-2.5 py-1
|
||||||
|
text-xs font-medium rounded
|
||||||
|
bg-surface-light text-text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-primary {
|
||||||
|
@apply bg-primary/20 text-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-muted {
|
||||||
|
@apply bg-border text-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@apply bg-surface rounded-lg overflow-hidden
|
||||||
|
border border-border/50
|
||||||
|
transition-all duration-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-interactive {
|
||||||
|
@apply card cursor-pointer
|
||||||
|
hover:-translate-y-1 hover:shadow-card-hover
|
||||||
|
hover:border-border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
@apply p-4 sm:p-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
@apply w-full px-4 py-3
|
||||||
|
bg-surface border border-border rounded-lg
|
||||||
|
text-text-primary placeholder-text-muted
|
||||||
|
transition-all duration-150
|
||||||
|
focus:outline-none focus:border-primary focus:shadow-input-focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-error {
|
||||||
|
@apply border-error focus:border-error
|
||||||
|
focus:shadow-[0_0_0_3px_rgba(248,113,113,0.2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea {
|
||||||
|
@apply input min-h-[150px] resize-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
@apply block text-sm font-medium text-text-secondary mb-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-required::after {
|
||||||
|
content: '*';
|
||||||
|
@apply text-error ml-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
@apply text-sm text-error mt-1.5 flex items-center gap-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
@apply py-16 sm:py-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
@apply text-center mb-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
@apply text-heading mb-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
@apply text-body text-text-secondary max-w-2xl mx-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial {
|
||||||
|
@apply bg-surface-light rounded-lg p-6 border-l-4 border-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
@apply flex items-center gap-2 text-sm text-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-link {
|
||||||
|
@apply text-text-secondary hover:text-primary transition-colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-current {
|
||||||
|
@apply text-text-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fadeIn 0.6s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-up {
|
||||||
|
animation: fadeInUp 0.6s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animation-delay-100 { animation-delay: 100ms; }
|
||||||
|
.animation-delay-200 { animation-delay: 200ms; }
|
||||||
|
.animation-delay-300 { animation-delay: 300ms; }
|
||||||
|
|
||||||
|
.aspect-thumbnail {
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
*, *::before, *::after {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
assets/css/output.css
Normal file
1
assets/css/output.css
Normal file
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Ready for Dev
|
review
|
||||||
|
|
||||||
## Story
|
## Story
|
||||||
|
|
||||||
@@ -22,37 +22,37 @@ Ready for Dev
|
|||||||
|
|
||||||
## Tasks / Subtasks
|
## Tasks / Subtasks
|
||||||
|
|
||||||
- [] **Task 1 : Initialiser npm et installer les dépendances** (AC: 1)
|
- [x] **Task 1 : Initialiser npm et installer les dépendances** (AC: 1)
|
||||||
- [] Créer `package.json` avec `npm init -y`
|
- [x] Créer `package.json` avec `npm init -y`
|
||||||
- [] Installer Tailwind CSS : `npm install -D tailwindcss postcss autoprefixer`
|
- [x] Installer Tailwind CSS : `npm install -D tailwindcss postcss autoprefixer`
|
||||||
- [] Vérifier que `node_modules/` est dans `.gitignore`
|
- [x] Vérifier que `node_modules/` est dans `.gitignore`
|
||||||
|
|
||||||
- [] **Task 2 : Créer la configuration Tailwind** (AC: 2, 7)
|
- [x] **Task 2 : Créer la configuration Tailwind** (AC: 2, 7)
|
||||||
- [] Créer `tailwind.config.js` avec les chemins PHP à scanner
|
- [x] Créer `tailwind.config.js` avec les chemins PHP à scanner
|
||||||
- [] Configurer la palette de couleurs personnalisée (primary, background, surface, text, etc.)
|
- [x] Configurer la palette de couleurs personnalisée (primary, background, surface, text, etc.)
|
||||||
- [] Configurer les polices (Inter, JetBrains Mono)
|
- [x] Configurer les polices (Inter, JetBrains Mono)
|
||||||
- [] Configurer les tailles de texte personnalisées
|
- [x] Configurer les tailles de texte personnalisées
|
||||||
- [] Configurer les ombres personnalisées
|
- [x] Configurer les ombres personnalisées
|
||||||
|
|
||||||
- [] **Task 3 : Créer le fichier CSS source** (AC: 3)
|
- [x] **Task 3 : Créer le fichier CSS source** (AC: 3)
|
||||||
- [] Créer `assets/css/input.css`
|
- [x] Créer `assets/css/input.css`
|
||||||
- [] Ajouter les directives `@tailwind base`, `@tailwind components`, `@tailwind utilities`
|
- [x] Ajouter les directives `@tailwind base`, `@tailwind components`, `@tailwind utilities`
|
||||||
- [] Ajouter les styles de base dans `@layer base`
|
- [x] Ajouter les styles de base dans `@layer base`
|
||||||
- [] Ajouter les composants réutilisables dans `@layer components` (btn, card, input, badge, etc.)
|
- [x] Ajouter les composants réutilisables dans `@layer components` (btn, card, input, badge, etc.)
|
||||||
- [] Ajouter les animations dans `@layer utilities`
|
- [x] Ajouter les animations dans `@layer utilities`
|
||||||
|
|
||||||
- [] **Task 4 : Configurer PostCSS** (AC: 1)
|
- [x] **Task 4 : Configurer PostCSS** (AC: 1)
|
||||||
- [] Créer `postcss.config.js` avec tailwindcss et autoprefixer
|
- [x] Créer `postcss.config.js` avec tailwindcss et autoprefixer
|
||||||
|
|
||||||
- [] **Task 5 : Configurer les scripts npm** (AC: 4, 5)
|
- [x] **Task 5 : Configurer les scripts npm** (AC: 4, 5)
|
||||||
- [] Ajouter le script `build` dans package.json
|
- [x] Ajouter le script `build` dans package.json
|
||||||
- [] Ajouter le script `dev` (watch) dans package.json
|
- [x] Ajouter le script `dev` (watch) dans package.json
|
||||||
- [] Tester les deux scripts
|
- [x] Tester les deux scripts
|
||||||
|
|
||||||
- [] **Task 6 : Valider la taille du CSS** (AC: 6)
|
- [x] **Task 6 : Valider la taille du CSS** (AC: 6)
|
||||||
- [] Exécuter `npm run build`
|
- [x] Exécuter `npm run build`
|
||||||
- [] Vérifier que `output.css` < 50kb (6,4 Ko)
|
- [x] Vérifier que `output.css` < 50kb (6,4 Ko)
|
||||||
- [] Vérifier que le purge fonctionne correctement
|
- [x] Vérifier que le purge fonctionne correctement
|
||||||
|
|
||||||
## Dev Notes
|
## Dev Notes
|
||||||
|
|
||||||
@@ -407,38 +407,40 @@ Créer un fichier HTML temporaire pour tester les classes :
|
|||||||
|
|
||||||
| Date | Version | Description | Author |
|
| Date | Version | Description | Author |
|
||||||
|------|---------|-------------|--------|
|
|------|---------|-------------|--------|
|
||||||
|
| 2026-02-04 | 0.1 | Implementation story 1.2 | Amelia |
|
||||||
| 2026-01-22 | 0.1 | Création initiale de la story | Sarah (PO) |
|
| 2026-01-22 | 0.1 | Création initiale de la story | Sarah (PO) |
|
||||||
|
|
||||||
## Dev Agent Record
|
## Dev Agent Record
|
||||||
|
|
||||||
### Agent Model Used
|
### Agent Model Used
|
||||||
|
|
||||||
Claude Opus 4.5 (claude-opus-4-5-20251101)
|
GPT-5 Codex
|
||||||
|
|
||||||
### Debug Log References
|
### Debug Log References
|
||||||
|
|
||||||
_À compléter par le dev agent_
|
- tests/tailwind.test.ps1: Assert-True boolean cast fix
|
||||||
|
|
||||||
### Completion Notes List
|
### Completion Notes List
|
||||||
|
|
||||||
- Package.json mis à jour (v2.0.0) avec scripts dev/build Tailwind
|
- package.json mis à jour avec scripts dev/build Tailwind
|
||||||
- Dépendances installées : tailwindcss ^3.4.0, postcss ^8.4.0, autoprefixer ^10.4.0
|
- Dépendances installées : tailwindcss ^3.4.0, postcss ^8.4.0, autoprefixer ^10.4.0
|
||||||
- tailwind.config.js créé avec palette couleurs sombre, polices Inter/JetBrains Mono
|
- tailwind.config.js créé avec palette sombre, polices Inter/JetBrains Mono
|
||||||
- input.css complet avec @layer base, components (btn, card, input, badge, etc.), utilities (animations)
|
- input.css avec @layer base/components/utilities et animations
|
||||||
- postcss.config.js configuré
|
- postcss.config.js configuré
|
||||||
- Build validé : output.css = 6,4 Ko (< 50 Ko requis)
|
- Build validé : output.css < 50 Ko
|
||||||
- Warning normal : pas encore de fichiers PHP utilisant les classes
|
- Tests: `powershell -ExecutionPolicy Bypass -File tests/run.ps1`
|
||||||
|
|
||||||
### File List
|
### File List
|
||||||
|
|
||||||
| Fichier | Action |
|
| Fichier | Action |
|
||||||
|---------|--------|
|
|---------|--------|
|
||||||
| `package.json` | Modifié |
|
| `package.json` | Créé |
|
||||||
| `package-lock.json` | Modifié |
|
| `package-lock.json` | Créé |
|
||||||
| `tailwind.config.js` | Créé |
|
| `tailwind.config.js` | Créé |
|
||||||
| `postcss.config.js` | Créé |
|
| `postcss.config.js` | Créé |
|
||||||
| `assets/css/input.css` | Créé |
|
| `assets/css/input.css` | Créé |
|
||||||
| `assets/css/output.css` | Généré |
|
| `assets/css/output.css` | Généré |
|
||||||
|
| `tests/tailwind.test.ps1` | Créé |
|
||||||
|
|
||||||
## QA Results
|
## QA Results
|
||||||
|
|
||||||
|
|||||||
1109
package-lock.json
generated
Normal file
1109
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "codex.skycel",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Portfolio de Skycel fait par l\u0027IA codex en utilisant la méthode B-MAD",
|
||||||
|
"main": "index.js",
|
||||||
|
"directories": {
|
||||||
|
"doc": "docs",
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css --watch",
|
||||||
|
"build": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css --minify"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^10.4.0",
|
||||||
|
"postcss": "^8.4.0",
|
||||||
|
"tailwindcss": "^3.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
55
tailwind.config.js
Normal file
55
tailwind.config.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
'./*.php',
|
||||||
|
'./pages/**/*.php',
|
||||||
|
'./templates/**/*.php',
|
||||||
|
'./assets/js/**/*.js'
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
DEFAULT: '#FA784F',
|
||||||
|
light: '#FB9570',
|
||||||
|
dark: '#E5623A',
|
||||||
|
},
|
||||||
|
background: '#17171F',
|
||||||
|
surface: {
|
||||||
|
DEFAULT: '#1E1E28',
|
||||||
|
light: '#2A2A36',
|
||||||
|
},
|
||||||
|
border: '#3A3A48',
|
||||||
|
text: {
|
||||||
|
primary: '#F5F5F7',
|
||||||
|
secondary: '#A1A1AA',
|
||||||
|
muted: '#71717A',
|
||||||
|
},
|
||||||
|
success: '#34D399',
|
||||||
|
warning: '#FBBF24',
|
||||||
|
error: '#F87171',
|
||||||
|
info: '#60A5FA',
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||||
|
mono: ['JetBrains Mono', 'monospace'],
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
display: ['2.5rem', { lineHeight: '1.2', fontWeight: '700' }],
|
||||||
|
heading: ['2rem', { lineHeight: '1.3', fontWeight: '600' }],
|
||||||
|
subheading: ['1.5rem', { lineHeight: '1.4', fontWeight: '600' }],
|
||||||
|
body: ['1rem', { lineHeight: '1.6', fontWeight: '400' }],
|
||||||
|
small: ['0.875rem', { lineHeight: '1.5', fontWeight: '400' }],
|
||||||
|
},
|
||||||
|
maxWidth: {
|
||||||
|
content: '1280px',
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
card: '0 4px 20px rgba(0, 0, 0, 0.25)',
|
||||||
|
'card-hover': '0 10px 40px rgba(0, 0, 0, 0.3)',
|
||||||
|
'input-focus': '0 0 0 3px rgba(250, 120, 79, 0.2)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
& (Join-Path $here 'structure.test.ps1')
|
& (Join-Path $here 'structure.test.ps1')
|
||||||
|
& (Join-Path $here 'tailwind.test.ps1')
|
||||||
'OK'
|
'OK'
|
||||||
31
tests/tailwind.test.ps1
Normal file
31
tests/tailwind.test.ps1
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Assert-True {
|
||||||
|
param(
|
||||||
|
[bool]$Condition,
|
||||||
|
[string]$Message
|
||||||
|
)
|
||||||
|
if (-not $Condition) { throw $Message }
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert-True (Test-Path 'package.json') 'Missing package.json'
|
||||||
|
$pkg = Get-Content -Raw 'package.json' | ConvertFrom-Json
|
||||||
|
$build = $pkg.scripts.build
|
||||||
|
$dev = $pkg.scripts.dev
|
||||||
|
Assert-True (-not [string]::IsNullOrWhiteSpace($build)) 'Missing npm build script'
|
||||||
|
Assert-True (-not [string]::IsNullOrWhiteSpace($dev)) 'Missing npm dev script'
|
||||||
|
|
||||||
|
Assert-True (Test-Path 'tailwind.config.js') 'Missing tailwind.config.js'
|
||||||
|
Assert-True (Test-Path 'postcss.config.js') 'Missing postcss.config.js'
|
||||||
|
|
||||||
|
Assert-True (Test-Path 'assets/css/input.css') 'Missing assets/css/input.css'
|
||||||
|
$input = Get-Content -Raw 'assets/css/input.css'
|
||||||
|
Assert-True ($input -match '@tailwind base') 'Missing @tailwind base'
|
||||||
|
Assert-True ($input -match '@tailwind components') 'Missing @tailwind components'
|
||||||
|
Assert-True ($input -match '@tailwind utilities') 'Missing @tailwind utilities'
|
||||||
|
|
||||||
|
Assert-True (Test-Path 'assets/css/output.css') 'Missing assets/css/output.css'
|
||||||
|
$size = (Get-Item 'assets/css/output.css').Length
|
||||||
|
Assert-True ($size -lt 51200) "output.css too large: ${size} bytes"
|
||||||
|
|
||||||
|
'OK'
|
||||||
Reference in New Issue
Block a user