🎨 Feature: Configuration Tailwind + Templates PHP + Page Canary
Stories 1.2, 1.3, 1.4: - Tailwind CSS configuré avec palette sombre personnalisée - Templates header.php et footer.php avec meta SEO/Open Graph - Fonction include_template() pour les composants réutilisables - Page canary avec animations et composants de test - Configuration nginx exemple pour le déploiement - Dépendances: vlucas/phpdotenv, tailwindcss, postcss, autoprefixer Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
199
assets/css/input.css
Normal file
199
assets/css/input.css
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
@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 */
|
||||||
|
.container-content {
|
||||||
|
@apply max-w-content mx-auto px-4 sm:px-6 lg:px-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boutons */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Badges */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cartes */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inputs */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Témoignage */
|
||||||
|
.testimonial {
|
||||||
|
@apply bg-surface-light rounded-lg p-6 border-l-4 border-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Breadcrumb */
|
||||||
|
.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); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accessibilité - Réduction de mouvement */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
*, *::before, *::after {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
assets/js/main.js
Normal file
6
assets/js/main.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// assets/js/main.js
|
||||||
|
// Script principal du portfolio
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
console.log('Portfolio chargé');
|
||||||
|
});
|
||||||
494
composer.lock
generated
Normal file
494
composer.lock
generated
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "adbddd7a48b14ed78896b2d6c5ef28e9",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "graham-campbell/result-type",
|
||||||
|
"version": "v1.1.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||||
|
"reference": "e01f4a821471308ba86aa202fed6698b6b695e3b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b",
|
||||||
|
"reference": "e01f4a821471308ba86aa202fed6698b6b695e3b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"phpoption/phpoption": "^1.9.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GrahamCampbell\\ResultType\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An Implementation Of The Result Type",
|
||||||
|
"keywords": [
|
||||||
|
"Graham Campbell",
|
||||||
|
"GrahamCampbell",
|
||||||
|
"Result Type",
|
||||||
|
"Result-Type",
|
||||||
|
"result"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||||
|
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/GrahamCampbell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-27T19:43:20+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "phpoption/phpoption",
|
||||||
|
"version": "1.9.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/schmittjoh/php-option.git",
|
||||||
|
"reference": "75365b91986c2405cf5e1e012c5595cd487a98be"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be",
|
||||||
|
"reference": "75365b91986c2405cf5e1e012c5595cd487a98be",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
|
"phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"bamarni-bin": {
|
||||||
|
"bin-links": true,
|
||||||
|
"forward-command": false
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.9-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpOption\\": "src/PhpOption/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Johannes M. Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com",
|
||||||
|
"homepage": "https://github.com/schmittjoh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Option Type for PHP",
|
||||||
|
"keywords": [
|
||||||
|
"language",
|
||||||
|
"option",
|
||||||
|
"php",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||||
|
"source": "https://github.com/schmittjoh/php-option/tree/1.9.5"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/GrahamCampbell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-27T19:41:33+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-ctype",
|
||||||
|
"version": "v1.33.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-ctype": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-ctype": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Ctype\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Gert de Pagter",
|
||||||
|
"email": "BackEndTea@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for ctype functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"ctype",
|
||||||
|
"polyfill",
|
||||||
|
"portable"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.33.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-12-23T08:48:59+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php80",
|
||||||
|
"version": "v1.33.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||||
|
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
|
||||||
|
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php80\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ion Bazan",
|
||||||
|
"email": "ion.bazan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-01-02T08:10:11+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vlucas/phpdotenv",
|
||||||
|
"version": "v5.6.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||||
|
"reference": "955e7815d677a3eaa7075231212f2110983adecc"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc",
|
||||||
|
"reference": "955e7815d677a3eaa7075231212f2110983adecc",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"graham-campbell/result-type": "^1.1.4",
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"phpoption/phpoption": "^1.9.5",
|
||||||
|
"symfony/polyfill-ctype": "^1.26",
|
||||||
|
"symfony/polyfill-mbstring": "^1.26",
|
||||||
|
"symfony/polyfill-php80": "^1.26"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
|
"ext-filter": "*",
|
||||||
|
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-filter": "Required to use the boolean validator."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"bamarni-bin": {
|
||||||
|
"bin-links": true,
|
||||||
|
"forward-command": false
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.6-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dotenv\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vance Lucas",
|
||||||
|
"email": "vance@vancelucas.com",
|
||||||
|
"homepage": "https://github.com/vlucas"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
|
||||||
|
"keywords": [
|
||||||
|
"dotenv",
|
||||||
|
"env",
|
||||||
|
"environment"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/vlucas/phpdotenv/issues",
|
||||||
|
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/GrahamCampbell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-27T19:49:13+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {
|
||||||
|
"php": ">=8.0"
|
||||||
|
},
|
||||||
|
"platform-dev": {},
|
||||||
|
"plugin-api-version": "2.6.0"
|
||||||
|
}
|
||||||
15
includes/functions.php
Normal file
15
includes/functions.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Fonctions helpers du portfolio
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inclut un template avec des données
|
||||||
|
* @param string $name Nom du template (sans .php)
|
||||||
|
* @param array $data Variables à passer au template
|
||||||
|
*/
|
||||||
|
function include_template(string $name, array $data = []): void
|
||||||
|
{
|
||||||
|
extract($data);
|
||||||
|
include __DIR__ . "/../templates/{$name}.php";
|
||||||
|
}
|
||||||
64
index.php
64
index.php
@@ -1,11 +1,53 @@
|
|||||||
<!DOCTYPE html>
|
<?php
|
||||||
<html lang="fr">
|
// index.php - Page Canary
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
require_once __DIR__ . '/includes/functions.php';
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Portfolio - Skycel</title>
|
include_template('header', [
|
||||||
</head>
|
'pageTitle' => 'Portfolio en construction',
|
||||||
<body>
|
'pageDescription' => 'Mon portfolio de développeur web arrive bientôt. Restez connectés !'
|
||||||
<h1>Hello World</h1>
|
]);
|
||||||
</body>
|
?>
|
||||||
</html>
|
|
||||||
|
<main class="min-h-screen flex items-center justify-center">
|
||||||
|
<div class="container-content text-center py-20">
|
||||||
|
<!-- Titre principal -->
|
||||||
|
<h1 class="text-display text-text-primary mb-4 animate-fade-in">
|
||||||
|
Portfolio <span class="text-primary">en construction</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Sous-titre -->
|
||||||
|
<p class="text-xl text-text-secondary mb-8 max-w-2xl mx-auto animate-fade-in animation-delay-100">
|
||||||
|
Je prépare quelque chose de génial pour vous.
|
||||||
|
<br>Revenez bientôt pour découvrir mes projets !
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Badge de test -->
|
||||||
|
<div class="flex justify-center gap-4 mb-12 animate-fade-in animation-delay-200">
|
||||||
|
<span class="badge">PHP</span>
|
||||||
|
<span class="badge">Tailwind CSS</span>
|
||||||
|
<span class="badge badge-primary">En cours</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Card de test -->
|
||||||
|
<div class="card max-w-md mx-auto animate-fade-in animation-delay-300">
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="text-subheading mb-2">Infrastructure validée</h3>
|
||||||
|
<p class="text-text-secondary mb-4">
|
||||||
|
PHP, Tailwind CSS et le serveur fonctionnent correctement.
|
||||||
|
</p>
|
||||||
|
<div class="flex gap-4 justify-center">
|
||||||
|
<span class="btn-primary">Bouton Primary</span>
|
||||||
|
<span class="btn-secondary">Bouton Secondary</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Test responsive -->
|
||||||
|
<p class="text-text-muted text-sm mt-12">
|
||||||
|
Testé sur mobile, tablette et desktop.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php include_template('footer'); ?>
|
||||||
|
|||||||
61
nginx.conf.example
Normal file
61
nginx.conf.example
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Configuration Nginx pour le Portfolio
|
||||||
|
# À adapter selon votre serveur
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name monportfolio.fr www.monportfolio.fr;
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name monportfolio.fr www.monportfolio.fr;
|
||||||
|
|
||||||
|
# SSL - À adapter selon votre configuration Let's Encrypt
|
||||||
|
ssl_certificate /etc/letsencrypt/live/monportfolio.fr/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/monportfolio.fr/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
root /var/www/portfolio;
|
||||||
|
index index.php;
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
# Headers de sécurité
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-Frame-Options "DENY" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
|
||||||
|
# Bloquer fichiers sensibles
|
||||||
|
location ~ /\.(env|git|htaccess) { deny all; return 404; }
|
||||||
|
location ^~ /vendor/ { deny all; return 404; }
|
||||||
|
location ^~ /node_modules/ { deny all; return 404; }
|
||||||
|
location ^~ /logs/ { deny all; return 404; }
|
||||||
|
location ^~ /data/ { deny all; return 404; }
|
||||||
|
location ^~ /includes/ { deny all; return 404; }
|
||||||
|
|
||||||
|
# Assets statiques avec cache long
|
||||||
|
location /assets/ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
gzip_static on;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Router PHP (front controller)
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# PHP-FPM - À adapter selon votre version PHP
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types text/plain text/css text/javascript application/javascript application/json image/svg+xml;
|
||||||
|
}
|
||||||
1110
package-lock.json
generated
1110
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
35
package.json
35
package.json
@@ -1,33 +1,24 @@
|
|||||||
{
|
{
|
||||||
"name": "portfolio-v0.1_scss",
|
"name": "skycel-portfolio",
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"description": "Skycel's portfolio",
|
"description": "Portfolio développeur web - Skycel",
|
||||||
"main": "index.js",
|
"author": "Skycel9",
|
||||||
|
"license": "ISC",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "sass ./public/assets/scss/style.scss ./public/assets/css/style.css --no-source-map",
|
"dev": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css --watch",
|
||||||
"watch": "sass ./public/assets/scss/style.scss ./public/assets/css/style.css -watch --no-source-map",
|
"build": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css --minify"
|
||||||
"build": "sass ./public/assets/css/style.css ./public/assets/css/style.min.css --style=compressed --no-source-map"
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tailwindcss": "^3.4.0",
|
||||||
|
"postcss": "^8.4.0",
|
||||||
|
"autoprefixer": "^10.4.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/Skycel9/Portfolio.git"
|
"url": "git+https://github.com/Skycel9/Portfolio.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
|
||||||
"portfolio",
|
|
||||||
"development",
|
|
||||||
"Skycel9"
|
|
||||||
],
|
|
||||||
"author": "Skycel9",
|
|
||||||
"license": "ISC",
|
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/Skycel9/Portfolio/issues"
|
"url": "https://github.com/Skycel9/Portfolio/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/Skycel9/Portfolio",
|
"homepage": "https://github.com/Skycel9/Portfolio"
|
||||||
"dependencies": {},
|
|
||||||
"prettier": {
|
|
||||||
"ignore": [
|
|
||||||
"**/*.min.js",
|
|
||||||
"**/*.min.css"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
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: [],
|
||||||
|
}
|
||||||
19
templates/footer.php
Normal file
19
templates/footer.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template Footer
|
||||||
|
*/
|
||||||
|
$currentYear = date('Y');
|
||||||
|
?>
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="bg-surface border-t border-border py-8 mt-auto">
|
||||||
|
<div class="container-content text-center">
|
||||||
|
<p class="text-text-muted text-sm">
|
||||||
|
© <?= $currentYear ?> Portfolio. Tous droits réservés.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="/assets/js/main.js" defer></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
38
templates/header.php
Normal file
38
templates/header.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template Header
|
||||||
|
* Variables disponibles :
|
||||||
|
* - $pageTitle (string) : Titre de la page
|
||||||
|
* - $pageDescription (string, optionnel) : Meta description
|
||||||
|
*/
|
||||||
|
|
||||||
|
$pageTitle = $pageTitle ?? 'Portfolio - Développeur Web';
|
||||||
|
$pageDescription = $pageDescription ?? 'Portfolio de développeur web full-stack. Découvrez mes projets, compétences et parcours.';
|
||||||
|
$siteName = 'Portfolio';
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="<?= htmlspecialchars($pageDescription, ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="<?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
<meta property="og:description" content="<?= htmlspecialchars($pageDescription, ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:locale" content="fr_FR">
|
||||||
|
|
||||||
|
<!-- Preload fonts -->
|
||||||
|
<link rel="preload" href="/assets/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
|
||||||
|
<link rel="preload" href="/assets/fonts/jetbrains-mono-var.woff2" as="font" type="font/woff2" crossorigin>
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<link rel="stylesheet" href="/assets/css/output.css">
|
||||||
|
|
||||||
|
<title><?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?> | <?= $siteName ?></title>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background text-text-primary font-sans antialiased">
|
||||||
Reference in New Issue
Block a user