This commit is contained in:
gcch 2025-06-19 16:07:29 +02:00
commit de73fc619a
3560 changed files with 747274 additions and 0 deletions

56
.gitignore vendored Executable file
View file

@ -0,0 +1,56 @@
# Application
web/app/plugins/*
!web/app/plugins/.gitkeep
web/app/mu-plugins/*/
web/app/themes/twentytwentyfour/
web/app/upgrade
web/app/cache/*
# WordPress
web/wp
web/vendor
web/.htaccess
# Compilation
web/app/themes/haiku-atelier-2024/assets/js
web/app/themes/haiku-atelier-2024/assets/js/.vite/manifest.json
# Logs
*.log
# Dotenv
.env
.env.*
!.env.example
# Composer
/vendor
# WP-CLI
wp-cli.local.yml
# Node
node_modules
# Cache
.cache
cache
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# pre-commit
.pre-commit-config.yaml
# Gleam
build/
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

2
.npmrc Executable file
View file

@ -0,0 +1,2 @@
# Nécessaire pour better-typescript-lib
public-hoist-pattern[]=@typescript/*

38
.oxlintrc.json Executable file
View file

@ -0,0 +1,38 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": { "browser": true, "es2020": true, "es2022": true },
"categories": {
"correctness": "error",
"nursery": "error",
"pedantic": "error",
"perf": "warn",
"restriction": "error",
"style": "warn",
"suspicious": "error"
},
"plugins": ["jsdoc", "promise", "unicorn", "jsdoc", "oxc", "promise", "typescript", "unicorn"],
"rules": {
"import/export": "error",
"no-array-for-each": "off",
"no-async-await": "off",
"no-console": "off",
"no-magic-numbers": "warn",
"no-map-spread": "off",
"no-misused-promises": "off",
"no-optional-chaining": "off",
"no-rest-spread-properties": "off",
"no-ternary": "off",
"no-undefined": "off",
"no-unused-expressions": "off",
"no-void": "off",
"prefer-await-to-then": "off",
"promise/prefer-await-to-callbacks": "off",
"sort-imports": "off",
"typescript/array-type": ["error", { "default": "generic", "readonly": "generic" }],
"typescript/consistent-indexed-object-style": ["error", "record"],
"typescript/consistent-type-imports": "error",
"typescript/explicit-function-return-type": "warn",
"unicorn/prefer-dom-node-dataset": "off",
"yoda": ["error", "never"]
}
}

6
.phpactor.json Executable file
View file

@ -0,0 +1,6 @@
{
"$schema": "/opt/phpactor/phpactor.schema.json",
"language_server_phpstan.enabled": true,
"language_server_psalm.enabled": false,
"php_code_sniffer.enabled": false
}

29
.prettierignore Executable file
View file

@ -0,0 +1,29 @@
# Tout ce qui est traité par dprint
*.css
*.html
*.js
*.json
!package.json
*.jsonc
*.md
*.scss
*.ts
*.twig
*.yml
*.yaml
# Tout sauf le thème
.ddev
web/app/*
!web/app/themes
web/app/themes/haiku-atelier-2024/assets
web/app/languages
web/app/plugins
web/vendor
# Dépendances
composer.lock
pnpm-lock.yaml
# Jujutsu
.jj

31
.swcrc Executable file
View file

@ -0,0 +1,31 @@
{
"$schema": "https://swc.rs/schema.json",
"jsc": {
"externalHelpers": false,
"keepClassNames": false,
"loose": false,
"minify": {
"compress": true,
"mangle": true
},
"parser": {
"decorators": false,
"decoratorsBeforeExport": false,
"dynamicImport": false,
"exportDefaultFrom": false,
"exportNamespaceFrom": false,
"functionBind": false,
"importMeta": false,
"jsx": false,
"privateMethod": false,
"syntax": "typescript",
"topLevelAwait": false,
"tsx": false
},
"preserveAllComments": false,
"target": "es2020",
"transform": null
},
"minify": true,
"sourceMaps": true
}

24
README.md Executable file
View file

@ -0,0 +1,24 @@
# Haiku Atelier
## Dépendances
### PHP
#### Dépendances
- `composer/installers` : permet d'installer et récupérer des dépendances dans des dossiers personnalisés ; nécessaire pour _Bedrock_.
- `crell/fp` : librairie proposant des méthodes de programmation fonctionnelle.
- `htmlburger/carbon-fields` : librairie en alternative à _Advanced Custom Fields_ permettant la création de champs et taxonomies personnalisés.
- `laravel/helpers` : ensemble de fonctions utilitaires ;
- `lstrojny/functional-php` libraire proposant des méthodes de programmation fonctionnelle (à sûrement remplacer par `laravel/helpers`).
- `mnsami/composer-custom-directory-installer` : permet d'installer des dépendances dans des dossiers personnalisés ; nécessaire pour `htmlburger/carbon-fields`.
- `oscarotero/env` : permet de récupérer les variables d'environnements des fichiers `.env` (?).
- `ramsey/uuid` : librairie pour la génération de _UUID_.
- `vlucas/phpdotenv` : permet de récupérer les variables d'environnements des fichiers `.env` (?).
#### Dépendances de développement
- `phpstan/phpstan` : vérification de types statiques.
- `squizlabels/php_codesniffer` : linter.
- `szepeviktor/phpstan-wordpress` : _stubs WordPress_.
- `vimeo/pslam` : analyseur de code statique.

47
biome.json Executable file
View file

@ -0,0 +1,47 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"css": { "formatter": { "enabled": false }, "linter": { "enabled": true } },
"files": {
"experimentalScannerIgnores": [
"*.min.js",
"vendor",
"web/app/plugins",
"web/app/themes/haiku-atelier-2024/assets",
"web/wp"
],
"ignoreUnknown": true,
"maxSize": 100000000
},
"formatter": { "enabled": false },
"graphql": { "formatter": { "enabled": false }, "linter": { "enabled": true } },
"json": { "formatter": { "enabled": false }, "linter": { "enabled": true } },
"linter": {
"enabled": true,
"rules": {
"complexity": { "noForEach": "off" },
"nursery": {
"recommended": true,
"useSortedClasses": {
"fix": "unsafe",
"level": "error",
"options": { "attributes": ["class"], "functions": [""] }
}
},
"style": {
"recommended": true,
"noNonNullAssertion": "off",
"noParameterAssign": "error",
"useAsConstAssertion": "error",
"useDefaultParameterLast": "error",
"useEnumInitializers": "error",
"useSelfClosingElements": "error",
"useSingleVarDeclarator": "error",
"noUnusedTemplateLiteral": "error",
"useNumberNamespace": "error",
"noInferrableTypes": "error",
"noUselessElse": "error"
},
"recommended": true
}
}
}

1707
bun.lock Normal file

File diff suppressed because it is too large Load diff

82
composer.json Executable file
View file

@ -0,0 +1,82 @@
{
"name": "roots/bedrock",
"type": "project",
"license": "MIT",
"description": "WordPress boilerplate with Composer, easier configuration, and an improved folder structure",
"homepage": "https://roots.io/bedrock/",
"authors": [
{ "name": "Scott Walkinshaw", "email": "scott.walkinshaw@gmail.com", "homepage": "https://github.com/swalkinshaw" },
{ "name": "Ben Word", "email": "ben@benword.com", "homepage": "https://github.com/retlehs" }
],
"keywords": ["bedrock", "composer", "roots", "wordpress", "wp", "wp-config"],
"support": {
"issues": "https://github.com/roots/bedrock/issues",
"forum": "https://discourse.roots.io/category/bedrock"
},
"repositories": [
{ "type": "composer", "url": "https://wpackagist.org", "only": ["wpackagist-plugin/*", "wpackagist-theme/*"] }
],
"require": {
"php": ">=8.2",
"composer/installers": "^2.3",
"crell/fp": "^1.0",
"htmlburger/carbon-fields": "^3.6.5",
"illuminate/support": "^12.18",
"laravel/helpers": "^1.7.1",
"log1x/wp-smtp": "^1.0.2",
"lstrojny/functional-php": "^1.17",
"mnsami/composer-custom-directory-installer": "^2.0",
"nesbot/carbon": "^3.8.2",
"oscarotero/env": "^2.1.1",
"ramsey/uuid": "^4.7.6",
"roots/bedrock-autoloader": "^1.0.4",
"roots/bedrock-disallow-indexing": "^2.0",
"roots/wordpress": "^6.8.1",
"roots/wp-config": "^1.0",
"stripe/stripe-php": "^16.3",
"symfony/uid": "^7.2.0",
"timber/timber": "^2.3",
"vlucas/phpdotenv": "^5.6.1",
"wpackagist-plugin/falcon": "^2.8.4",
"wpackagist-plugin/force-regenerate-thumbnails": "^2.2.1",
"wpackagist-plugin/query-monitor": "^3.17.0",
"wpackagist-plugin/redis-cache": "^2.5.4",
"wpackagist-plugin/wc-multishipping": "^2.5.4",
"wpackagist-plugin/woo-preview-emails": "^2.2.13",
"wpackagist-plugin/woocommerce": "^9.4.3",
"wpackagist-plugin/wp-mail-logging": "^1.13.1",
"wpackagist-plugin/wp-mail-smtp": "^4.2",
"wpackagist-plugin/wp-openapi": "^1.0.16",
"wpackagist-theme/twentytwentyfour": "^1.3"
},
"require-dev": {
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.0.3",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.11.1",
"szepeviktor/phpstan-wordpress": "2.x-dev"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"allow-plugins": {
"composer/installers": true,
"mnsami/composer-custom-directory-installer": true,
"roots/wordpress-core-installer": true,
"phpstan/extension-installer": true
},
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"installer-paths": {
"web/vendor/{$vendor}/{$name}": ["htmlburger/carbon-fields"],
"web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
"web/app/plugins/{$name}/": ["type:wordpress-plugin"],
"web/app/themes/{$name}/": ["type:wordpress-theme"]
},
"wordpress-install-dir": "web/wp"
},
"scripts": { "test": ["phpcs"] }
}

4786
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

160
config/application.php Executable file
View file

@ -0,0 +1,160 @@
<?php
/**
* Your base production configuration goes in this file. Environment-specific
* overrides go in their respective config/environments/{{WP_ENV}}.php file.
*
* A good default policy is to deviate from the production config as little as
* possible. Try to define as much of your configuration in this file as you
* can.
*/
use Roots\WPConfig\Config;
use function Env\env;
// USE_ENV_ARRAY + CONVERT_* + STRIP_QUOTES
Env\Env::$options = 31;
/**
* Directory containing all of the site's files
*
* @var string
*/
$root_dir = dirname(__DIR__);
/**
* Document Root
*
* @var string
*/
$webroot_dir = $root_dir . "/web";
/**
* Use Dotenv to set required environment variables and load .env file in root
* .env.local will override .env if it exists
*/
if (file_exists($root_dir . "/.env")) {
$env_files = file_exists($root_dir . "/.env.local") ? [".env", ".env.local"] : [".env"];
$dotenv = Dotenv\Dotenv::createImmutable($root_dir, $env_files, false);
$dotenv->load();
$dotenv->required(["WP_HOME", "WP_SITEURL"]);
if (!env("DATABASE_URL")) {
$dotenv->required(["DB_NAME", "DB_USER", "DB_PASSWORD"]);
}
}
/**
* Set up our global environment constant and load its config first
* Default: production
*/
define("WP_ENV", env("WP_ENV") ?: "production");
/**
* Infer WP_ENVIRONMENT_TYPE based on WP_ENV
*/
if (!env("WP_ENVIRONMENT_TYPE") && in_array(WP_ENV, ["production", "staging", "development", "local"])) {
Config::define("WP_ENVIRONMENT_TYPE", WP_ENV);
}
/**
* URLs
*/
Config::define("WP_HOME", env("WP_HOME"));
Config::define("WP_SITEURL", env("WP_SITEURL"));
/**
* Custom Content Directory
*/
Config::define("CONTENT_DIR", "/app");
Config::define("WP_CONTENT_DIR", $webroot_dir . Config::get("CONTENT_DIR"));
Config::define("WP_CONTENT_URL", Config::get("WP_HOME") . Config::get("CONTENT_DIR"));
/**
* DB settings
*/
if (env("DB_SSL")) {
Config::define("MYSQL_CLIENT_FLAGS", MYSQLI_CLIENT_SSL);
}
Config::define("DB_NAME", env("DB_NAME"));
Config::define("DB_USER", env("DB_USER"));
Config::define("DB_PASSWORD", env("DB_PASSWORD"));
Config::define("DB_HOST", env("DB_HOST") ?: "localhost");
Config::define("DB_CHARSET", "utf8mb4");
Config::define("DB_COLLATE", "");
$table_prefix = env("DB_PREFIX") ?: "wp_";
if (env("DATABASE_URL")) {
$dsn = (object) parse_url(env("DATABASE_URL"));
Config::define("DB_NAME", substr($dsn->path, 1));
Config::define("DB_USER", $dsn->user);
Config::define("DB_PASSWORD", isset($dsn->pass) ? $dsn->pass : null);
Config::define("DB_HOST", isset($dsn->port) ? "{$dsn->host}:{$dsn->port}" : $dsn->host);
}
/**
* Authentication Unique Keys and Salts
*/
Config::define("AUTH_KEY", env("AUTH_KEY"));
Config::define("SECURE_AUTH_KEY", env("SECURE_AUTH_KEY"));
Config::define("LOGGED_IN_KEY", env("LOGGED_IN_KEY"));
Config::define("NONCE_KEY", env("NONCE_KEY"));
Config::define("AUTH_SALT", env("AUTH_SALT"));
Config::define("SECURE_AUTH_SALT", env("SECURE_AUTH_SALT"));
Config::define("LOGGED_IN_SALT", env("LOGGED_IN_SALT"));
Config::define("NONCE_SALT", env("NONCE_SALT"));
/**
* Custom Settings
*/
Config::define("AUTOMATIC_UPDATER_DISABLED", true);
Config::define("DISABLE_WP_CRON", env("DISABLE_WP_CRON") ?: false);
// Disable the plugin and theme file editor in the admin
Config::define("DISALLOW_FILE_EDIT", true);
// Disable plugin and theme updates and installation from the admin
Config::define("DISALLOW_FILE_MODS", true);
// Limit the number of post revisions
Config::define("WP_POST_REVISIONS", env("WP_POST_REVISIONS") ?? true);
/**
* Debugging Settings
*/
Config::define("WP_DEBUG_DISPLAY", false);
Config::define("WP_DEBUG_LOG", false);
Config::define("SCRIPT_DEBUG", false);
ini_set("display_errors", "0");
/**
* Plugins
*/
Config::define("WPMU_PLUGIN_DIR", Config::get("WP_CONTENT_DIR") . "/mu-plugins");
Config::define("WP_PLUGIN_DIR", Config::get("WP_CONTENT_DIR") . "/plugins");
/**
* Allow WordPress to detect HTTPS when used behind a reverse proxy or a load balancer
* See https://codex.wordpress.org/Function_Reference/is_ssl#Notes
*/
if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] === "https") {
$_SERVER["HTTPS"] = "on";
}
$env_config = __DIR__ . "/environments/" . WP_ENV . ".php";
if (file_exists($env_config)) {
require_once $env_config;
}
Config::apply();
/**
* Bootstrap WordPress
*/
if (!defined("ABSPATH")) {
define("ABSPATH", $webroot_dir . "/wp/");
}

View file

@ -0,0 +1,35 @@
<?php
/**
* Configuration overrides for WP_ENV === 'development'
*/
declare(strict_types=1);
use Roots\WPConfig\Config;
use function Env\env;
Config::define("SAVEQUERIES", true);
Config::define("WP_DEBUG", true);
Config::define("WP_DEBUG_DISPLAY", false);
Config::define("WP_DEBUG_LOG", env("WP_DEBUG_LOG") ?? true);
Config::define("WP_DISABLE_FATAL_ERROR_HANDLER", true);
Config::define("SCRIPT_DEBUG", true);
Config::define("DISALLOW_INDEXING", true);
ini_set("display_errors", "1");
// Enable plugin and theme updates and installation from the admin
Config::define("DISALLOW_FILE_MODS", false);
// WooCommerce
Config::define("WOOCOMMERCE_API_CONSUMER_KEY", env("WOOCOMMERCE_API_CONSUMER_KEY"));
Config::define("WOOCOMMERCE_API_CONSUMER_SECRET", env("WOOCOMMERCE_API_CONSUMER_SECRET"));
// Stripe
Config::define("STRIPE_API_SECRET", env("STRIPE_API_SECRET"));
// Redis
Config::define("WP_REDIS_HOST", env("WP_REDIS_HOST"));
Config::define("WP_REDIS_PASSWORD", env("WP_REDIS_PASSWORD"));
// Désactive la mise à jour des traductions automatiques
Config::define("WP_AUTO_UPDATE_TRANSLATION", false);

View file

@ -0,0 +1,23 @@
<?php
/**
* Configuration overrides for WP_ENV === 'production'
*/
declare(strict_types=1);
use Roots\WPConfig\Config;
use function Env\env;
Config::define("WP_DEBUG", true);
Config::define("WP_DEBUG_DISPLAY", false);
Config::define("WP_DEBUG_LOG", env("WP_DEBUG_LOG") ?? true);
Config::define("WP_DISABLE_FATAL_ERROR_HANDLER", false);
Config::define("DISALLOW_INDEXING", false);
Config::define("DISALLOW_FILE_MODS", false);
Config::define("WOOCOMMERCE_API_CONSUMER_KEY", env("WOOCOMMERCE_API_CONSUMER_KEY"));
Config::define("WOOCOMMERCE_API_CONSUMER_SECRET", env("WOOCOMMERCE_API_CONSUMER_SECRET"));
// Stripe
Config::define("STRIPE_API_SECRET", env("STRIPE_API_SECRET"));

13
config/environments/staging.php Executable file
View file

@ -0,0 +1,13 @@
<?php
/**
* Configuration overrides for WP_ENV === 'staging'
*/
declare(strict_types=1);
use Roots\WPConfig\Config;
use function Env\env;
Config::define("DISALLOW_INDEXING", true);
Config::define("WOOCOMMERCE_API_CONSUMER_KEY", env("WOOCOMMERCE_API_CONSUMER_KEY"));
Config::define("WOOCOMMERCE_API_CONSUMER_SECRET", env("WOOCOMMERCE_API_CONSUMER_SECRET"));

1
cspell.json Normal file
View file

@ -0,0 +1 @@
{ "dictionaries": ["fr-fr", "en-gb"], "words": ["oxlint"] }

3030
db/db-2024-08-13-e0d996d.sql Executable file

File diff suppressed because one or more lines are too long

2862
db/db-2024-09-25-94454e3.sql Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

58
docs/STUFF.md Normal file
View file

@ -0,0 +1,58 @@
I'll see you soup
Google API
AIzaSyDGe62r-bDxvNuDCP6HIfWIJAMvelFxU1s
402628219773-hl8niqniiiklf15f9biou8g06pbm9sac.apps.googleusercontent.com
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
- Code promo ?
- La commande peut être associée au panier.
- Vu que l'on passe par l'API REST, le panier est dissocié de la commande.
- Il est possible de fixer le hash du panier dans la commande avec la fonction set_cart_hash de WC_Order.
- Cela permet par la suite d'utiliser la fonction cancel_order WC_Order à l'annulation de cette dernière lors du retour au Panier depuis Stripe.
- Ce ne sera possible qu'en utilisant un endpoint personnalisé réalisant ces opérations plutôt que l'API REST.
- Dans l'idéal,
- Ajouter un bouton "Reset cart" quelque part pour tout réinitialiser (et appeler cancel_order si implémenté)
---
- BadRequestError
- reponse.status === 400
- reponse.body = {
code: string,
message: string (différenciation sur le message ?),
data: {
status: number (400),
}
}
- Chargement de la page
- Récupération des informations à la génération de la page
- Panier
- Code promo
- Mode de livraison
- Sous-totaux
- Total
- Adresses
- Récupération des informations dans le LocalStorage
- Code promo
- Mode de livraison
- Adresses
- À l'injection de données du LocalStorage
- Mettre à jour les sous-totaux
- À l'appui sur le bouton de calcul de la livraison et au succès de la requête
- Mettre à jour les méthodes de livraison
- Mettre à jour les sous-totaux et le total
- Sauvegarder les nouvelles données dans le LocalStorage
- Événements à créer
- MiseAJourCodePromo
- Se déclenche quand le champ du Code promo est modifié
- MiseAJourProduits
- Se déclenche quand une des lignes du Panier est modifiée (addition/soustraction/suppression)
- MiseAJourMethodeLivraison
- Se déclence quand le choix de la Méthode de livraison est modifié
- MiseAJourAdresses
- Se déclenche quand un des champs du formulaire des adresses est modifié

60
docs/TODO.md Executable file
View file

@ -0,0 +1,60 @@
- PAGE PANIER
- [-] Bouton « Réinitialiser » pour les Articles
- [-] Bouton « Réinitialiser » pour les Adresses
- [ ] Sauvegarder la dernière adresse validée dans le LocalStorage
- VITE
- Récupérer les liens des fichiers JS depuis le manifeste dans les fichiers PHP
- Menu Mobile
- Reprendre pour suivre la maquette initiale
- PayPal à faire
- Styles pour les focus à faire
- Boutons
- Champs
- Utiliser un polyfill pour BroadcastChannel
- PAGE SHOP
- [ ] Faire apparaître le menu des catégories de Produits quand on scroll vers le haut
- PAGE PANIER
- MÉTHODES DE LIVRAISON
- [ ] Proposer la livraison à domicile en Belgique et en France pour le coût unique de 8 euros, quel que soit le montant de la commande
- PAGE PRODUIT
- Retirer les flèches de défilement.
- Réduire l'image en focus pour que l'on perçoive les images précédentes/suivantes.
- PIED DE PAGE
- Réduire la hauteur.
- TOUTES LES PAGES
- Trouver la source des bordures superflues.
---
## Bouton « Retour en haut »
Un bouton « Retour en haut » permet pour un Utilisateur de rapidement revenir au sommet d'une page fournie en contenu.
Ne pas proposer ce bouton pour des pages faibles en contenus. Hoa Loranger recommende ainsi d'utiliser le seuil de **plus de quatre pages** de contenu (une page correspond à ce qui traversé avec l'appui sur la touche Espace dans le navigateur).
### Apparence et contenu
- Un lien `<a>` vers une ancre située en haut de la page (par exemple `#en-tete`) OU un bouton utilisant _JavaScript_ pour revenir en haut.
- Cet élément doit en envelopper deux autres :
- une icône sous forme de balises `<img>` ou `<svg>` avec un attribut `aria-hidden="true"` ;
- un texte « Retour en haut » qui peut être visuellement caché mais toujours accessible par les lecteurs d'écrans via une classe `.visuellement-cache`.
- Le bouton apparaît au sommet du reste du contenu.
- On peut idéalement ajouter une impression de profondeur avec l'utilisation d'ombres.
### Comportement
- Le bouton apparaît en bas à droite de l'écran une fois que l'Utilisateur a défilé plus d'une page.
- Il disparaît en-deça de ce seuil.
- Le bouton reçoit alors l'attribut `aria-hidden="true"` et `tabindex="-1"` pour éviter que l'Utilisateur _tab_ dessus par erreur.
- Quand il reçoit le focus, cela doit être visuellement indiqué.
- Il est idéalement le dernier élément dans la _tabbing sequence_.
- Le clic sur le bouton renvoie l'Utilisateur au sommet de la page, avec ou sans défilement doux.
- Considérations pour les Utilisateurs avec lecteurs d'écran :
- Le renvoie au sommet de la page doit s'accompagner à un focus sur le premier élément pour le recevoir (par exemple un bouton).
### Liens
- [Creating an accessible 'back to top' button](https://jhartshorne.co.uk/posts/back-to-top/).
- [Back-to-Top Button Design Guidelines](https://www.nngroup.com/articles/back-to-top/).
- [Back to Top](https://designsystem.utah.gov/library/components/navigationLinks/backToTop).

22
docs/lol/cute.ts Executable file
View file

@ -0,0 +1,22 @@
const etapes = [
"┌(・ω・)┘",
"└(・ω・)┐",
"┌(;・ω・)┘",
"└(;・ω・)┐",
"┌(;・ω・;)┘",
"└(;・ω・;)┐",
];
const assigneTexte = (texte: string): void => ELEMENTS.BOUTON_CODE_PROMO.textContent = texte;
let index = 0;
const z = {};
const callback = () => {
if (!ELEMENTS.BOUTON_CODE_PROMO.hasAttribute(ATTRIBUT_CHARGEMENT)) {
ELEMENTS.BOUTON_CODE_PROMO.textContent = "Apply";
clearInterval(z.interval);
}
assigneTexte(etapes.at(index) ?? "Loading...");
index = index + 1 === etapes.length - 1 ? 0 : index + 1;
};
callback();
z.interval = setInterval(callback, 500);

View file

@ -0,0 +1,9 @@
# Informations produit sous forme de grille
- L'idée est de réimplémenter les informations essentiels du produit (nom, prix), le sélecteur de variation, les textes de détail, de conditions et d'entretien, et le bouton d'ajout au Panier.
- Plutôt qu'un encart flottant, contenant tout, il n'y aurait qu'une barre pleine longueur comprenant nom, prix et sélecteur de variation (`.essentiel-produit`).
- Il flotterait en bas de l'écran jusqu'à ce se poser à la fin des photos.
- Une nouvelle section, statique elle et faisant suite à la fois aux photos et à la barre, s'afficherait en pleine longueur sous forme d'accordéon, avec les anciens onglets comme sections.
- Par défaut, la section « Détails » serait développée.
- `<details>` et `<summary>` sont aujourd'hui pris en charge par les navigateurs (niveau _Baseline_), mais l'attribut `name` permettant l'ouverture exclusive d'une section par accordéon (p. ex. le développement d'une ferme toutes les autres) n'a que récemment été implémentée (2024 pour _Firefox_).
- Une implémentation en _JavaScript_ est donc pour l'instant nécessaire.

View file

@ -0,0 +1,5 @@
# Remaniement du défilement des photos de la page Produit
- Les flèches de défilement sont supprimées.
- À la place, les photos ne s'affichent plus en pleine longueur.
- Elles le sont à ~93%, pour que l'on perçoive sur les bords la photo précédente/suivante et signale à l'utilisteur qu'il est possible de défiler.

122
dprint.json Executable file
View file

@ -0,0 +1,122 @@
{
"excludes": [
"**/node_modules",
"**/pnpm-lock.yaml",
"./lib/",
"web/app/languages",
"web/app/plugins",
"web/app/themes/haiku-atelier-2024/assets",
"web/vendor"
],
"exec": {
"cacheKey": "1",
"commands": [
{ "command": "prettier --ignore-unknown --write --stdin-filepath {{file_path}}", "exts": ["php", "xml"] },
{ "command": "just --dump", "fileNames": ["justfile"], "stdin": false }
],
"cwd": "${originConfigDir}",
"indentWidth": 2,
"lineWidth": 120,
"timeout": 30,
"useTabs": false
},
"indentWidth": 2,
"json": {
"commentLine.forceSpaceAfterSlashes": true,
"indentWidth": 2,
"jsonTrailingCommaFiles": [".swcrc", "biome.jsonc", "settings.json", "tsconfig.json"],
"lineWidth": 120,
"newLineKind": "lf",
"preferSingleLine": true,
"trailingCommas": "never",
"useTabs": false
},
"lineWidth": 120,
"malva": {
"alignComments": true,
"attrValueQuotes": "always",
"blockSelectorLinebreak": "wrap",
"declarationOrder": null,
"formatComments": true,
"hexCase": "lower",
"hexColorLength": "short",
"indentWidth": 2,
"keyframeSelectorNotation": "keyword",
"lineBreak": "lf",
"linebreakInPseudoParens": true,
"omitNumberLeadingZero": false,
"operatorLinebreak": "before",
"preferSingleLine": true,
"printWidth": 100,
"quotes": "alwaysDouble",
"singleLineBlockThreshold": null,
"singleLineTopLevelDeclarations": false,
"trailingComma": false,
"useTabs": false
},
"markup": {
"closingBracketSameLine": false,
"closingTagLineBreakForEmpty": "never",
"component.selfClosing": false,
"doctypeKeywordCase": "lower",
"formatComments": true,
"html.normal.selfClosing": false,
"html.void.selfClosing": false,
"indentWidth": 2,
"lineBreak": "lf",
"maxAttrsPerLine": 1,
"printWidth": 120,
"quotes": "double",
"scriptFormatter": "dprint",
"scriptIndent": true,
"styleIndent": true,
"svg.selfClosing": true,
"useTabs": false,
"whitespaceSensitivity": "strict"
},
"newLineKind": "lf",
"plugins": [
"https://plugins.dprint.dev/typescript-0.95.7.wasm",
"https://plugins.dprint.dev/json-0.20.0.wasm",
"https://plugins.dprint.dev/markdown-0.18.0.wasm",
"https://plugins.dprint.dev/toml-0.7.0.wasm",
"https://plugins.dprint.dev/g-plane/malva-v0.12.1.wasm",
"https://plugins.dprint.dev/g-plane/markup_fmt-v0.20.0.wasm",
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm",
"https://plugins.dprint.dev/exec-0.5.1.json@492414e39dea4dccc07b4af796d2f4efdb89e84bae2bd4e1e924c0cc050855bf"
],
"toml": {
"cargo.applyConventions": true,
"comment.forceLeadingSpace": true,
"indentWidth": 2,
"lineWidth": 120,
"newLineKind": "lf",
"useTabs": false
},
"typescript": {
"arrowFunction.useParentheses": "preferNone",
"conditionalExpression.operatorPosition": "nextLine",
"conditionalExpression.preferSingleLine": true,
"exportDeclaration.sortNamedExports": "maintain",
"importDeclaration.sortNamedImports": "maintain",
"module.sortExportDeclarations": "maintain",
"module.sortImportDeclarations": "maintain",
"quoteProps": "asNeeded",
"trailingCommas": "onlyMultiLine",
"useBraces": "whenNotSingleLine"
},
"yaml": {
"braceSpacing": true,
"bracketSpacing": false,
"formatComments": true,
"indentBlockSequenceInMap": true,
"indentWidth": 2,
"lineBreak": "lf",
"preferSingleLine": false,
"printWidth": 120,
"quotes": "preferDouble",
"trailingComma": true,
"trimTrailingWhitespaces": true,
"trimTrailingZero": false
}
}

65
eslint.config.js Executable file
View file

@ -0,0 +1,65 @@
import js from "@eslint/js";
import oxlint from "eslint-plugin-oxlint";
import perfectionist from "eslint-plugin-perfectionist";
import globals from "globals";
import tseslint from "typescript-eslint";
export default tseslint.config(
js.configs.recommended,
perfectionist.configs["recommended-natural"],
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
oxlint.configs["flat/recommended"],
{
files: ["*.js", "web/app/themes/haiku-atelier-2024/src/**/*.ts"],
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.browser,
...globals.es2020,
},
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
/* Utilise Array<T> plutôt que T[]. */
"@typescript-eslint/array-type": [
"error",
{
default: "generic",
readonly: "generic",
},
],
/* L'usage d'interfaces ou de types doit être à la discrétion du développeur. */
"@typescript-eslint/consistent-type-definitions": "off",
/* Désactive cette règle pour les fonctions fléchées pour rendre le code moins verbeux. */
"@typescript-eslint/no-confusing-void-expression": [
"error",
{
ignoreArrowShorthand: true,
ignoreVoidOperator: false,
},
],
/* Chiant avec certaines Promises. */
"@typescript-eslint/no-misused-promises": "off",
/* Cette règle empêche l'usage de génériques précisant les types de retour de fonctions. */
"@typescript-eslint/no-unnecessary-type-parameters": "off",
"@typescript-eslint/no-unused-expressions": [
"error",
{
allowTernary: true,
},
],
/* Cette règle est doublon avec les règles noUnused* de TypeScript. */
"@typescript-eslint/no-unused-vars": "off",
/* Cette règle empêche de lever des erreurs génériques (p.ex. `E extends Error`). */
"@typescript-eslint/only-throw-error": "off",
/* Cette règle empêche le style fonctionnel « point free ». */
"@typescript-eslint/unbound-method": "off",
/* Cette règle interdit l'usage de fonctions vides sauf pour les fonctions fléchées. */
"no-empty-function": ["error", { allow: ["arrowFunctions"] }],
},
},
);

119
justfile Executable file
View file

@ -0,0 +1,119 @@
set shell := ["fish", "-c"]
cacheFolder := ".cache"
eslintCacheFile := "eslintcache"
prettierCacheFile := "prettiercache"
stylelintCacheFile := "stylelintcache"
# Liste toutes les recettes
list:
@just --list --list-heading 'Recettes disponibles :'\n'' --unsorted
# Démarre le conteneur ddev
start:
ddev start
# Arrête le conteneur ddev
stop:
ddev stop
# Met à jour les dépendances composer et npm
update:
composer update
bun update
# Formatte avec Prettier et dprint
format:
@echo "Formatage de l'ensemble du code avec Prettier et dprint."
bunx prettier \
--cache \
--cache-location "{{ cacheFolder }}/{{ prettierCacheFile }}" \
--ignore-unknown \
--write \
.
dprint fmt
# Compile, minifie et optimise Sass vers CSS
build-css:
bunx sass \
--update \
"web/app/themes/haiku-atelier-2024/src/sass":"web/app/themes/haiku-atelier-2024/assets/css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/main.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/main.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-panier.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-panier.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-accueil.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-accueil.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-boutique.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-boutique.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-a-propos.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-a-propos.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-modele-simple.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-modele-simple.css"
bunx lightningcss \
--bundle \
--minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-succes-commande.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-succes-commande.css"
# Compile le CSS à chaque changement de fichier
watch-css:
bunx sass \
--update \
--watch \
"web/app/themes/haiku-atelier-2024/src/sass":"web/app/themes/haiku-atelier-2024/assets/css"
# Compile TypeScript en JavaScript
build-js:
bunx vite build
# Compile tout
build-all:
just build-css
just build-js
# Compile TypeScript à chaque changement de fichier
watch-js:
bunx vite build --watch
# Vérifie le code TypeScript avec des analyseurs statiques
lint-js:
-bunx eslint "web/app/themes/haiku-atelier-2024/src/scripts"
-bunx biome check --reporter=summary "web/app/themes/haiku-atelier-2024/src/scripts"
-bunx oxlint "web/app/themes/haiku-atelier-2024/src/scripts"
# Vérifie le code Sass avec Stylelint
lint-css:
-bunx stylelint "web/app/themes/haiku-atelier-2024/src/sass/" --fix
# Vérifie le code TypeScript mort avec knip
lint-code-mort:
-bunx knip
# Avec Jujetsu, fusionne tous les changements actuels dans le commit précédent et pousse sur le répertoire distant
squash-and-push:
-jj squash --ignore-immutable && jj bookmark set principale -r @- --allow-backwards && jj git push
# Compile, analyse statiquement (avec corrections automatiques) et formate le CSS
build-lint-format-css:
-just build-css
-just lint-css
-just format

66455
lib/openapi3_1.json Executable file

File diff suppressed because it is too large Load diff

8
lib/stylelint.d.ts vendored Executable file
View file

@ -0,0 +1,8 @@
/**
* Définition d'un groupe de Propriétés _CSS_ du plugin `stylelint-config-clean-order` pour _Stylelint_.
*/
export type stylelintconfigcleanorderpropertygroup = {
emptyLineBefore: "never" | "threshold";
noEmptyLineBetween: boolean;
properties: string | array<string>;
};

14486
lib/woocommerce-openapi-3.0.x.yml Executable file

File diff suppressed because it is too large Load diff

66455
lib/wp-json-openapi.json Executable file

File diff suppressed because it is too large Load diff

99225
lib/wp-json-schema.json Executable file

File diff suppressed because it is too large Load diff

82
package.json Executable file
View file

@ -0,0 +1,82 @@
{
"name": "haikuatelier.fr",
"version": "1.0.0",
"type": "module",
"description": "",
"author": "",
"license": "ISC",
"main": "index.js",
"keywords": [],
"scripts": { "knip": "knip" },
"dependencies": {
"@mobily/ts-belt": "v4.0.0-rc.5",
"@sentry/browser": "9.30.0",
"@swan-io/boxed": "^3.2.0",
"a11y-dialog": "^8.1.3",
"chalk": "^5.4.1",
"lit-html": "^3.3.0",
"loglevel": "^1.9.2",
"loglevel-plugin-prefix": "^0.8.4",
"optics-ts": "^2.4.1",
"purify-ts": "2.1.1",
"ts-pattern": "^5.7.1",
"valibot": "1.1.0"
},
"devDependencies": {
"@biomejs/biome": "^2.0.0",
"@cspell/dict-fr-fr": "^2.3.0",
"@eslint/js": "^9.29.0",
"@playwright/test": "^1.53.1",
"@prettier/plugin-php": "^0.22.4",
"@prettier/plugin-xml": "^3.4.1",
"@sentry/core": "^9.30.0",
"@swc/cli": "0.7.7",
"@types/eslint__js": "^9.14.0",
"@types/node": "^24.0.3",
"@vitejs/plugin-legacy": "^6.1.1",
"better-typescript-lib": "^2.11.0",
"browserslist": "^4.25.0",
"eslint": "^9.29.0",
"eslint-plugin-oxlint": "^1.2.0",
"eslint-plugin-perfectionist": "^4.15.0",
"fdir": "^6.4.6",
"globals": "^16.2.0",
"knip": "^5.61.2",
"lightningcss-cli": "^1.30.1",
"oxlint": "^1.2.0",
"picomatch": "^4.0.2",
"playwright": "^1.53.1",
"prettier": "^3.5.3",
"prettier-plugin-pkg": "^0.21.1",
"prettier-plugin-sh": "^0.17.4",
"sass-embedded": "^1.89.2",
"stylelint": "^16.21.0",
"stylelint-config-clean-order": "^7.0.0",
"stylelint-config-sass-guidelines": "^12.1.0",
"stylelint-config-standard-scss": "^15.0.1",
"stylelint-declaration-block-no-ignored-properties": "^2.8.0",
"stylelint-plugin-logical-css": "^1.2.3",
"typescript": "5.8.3",
"typescript-eslint": "^8.34.1",
"vite": "^6.3.5",
"vite-plugin-manifest-sri": "^0.2.0",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-valibot-env": "^0.10.2",
"vite-tsconfig-paths": "^5.1.4",
"wp-types": "^4.68.0"
},
"browserslist": [
"chrome >0 and last 3 years",
"edge >0 and last 3 years",
"safari >0 and last 3 years",
"firefox >0 and last 3 years",
"and_chr >0 and last 3 years",
"and_ff >0 and last 3 years",
"ios >0 and last 3 years"
],
"knip": {
"entry": ["web/app/themes/haiku-atelier-2024/src/scripts/*.ts"],
"project": ["web/app/themes/haiku-atelier-2024/src/scripts/**/*.{js,ts,d.ts}"]
},
"trustedDependencies": ["@biomejs/biome", "@parcel/watcher", "@swc/core", "core-js", "esbuild", "lightningcss-cli"]
}

58
phpcs.xml Executable file
View file

@ -0,0 +1,58 @@
<?xml version="1.0" ?>
<ruleset name="Roots">
<description>Roots Coding Standards</description>
<!-- Scan all files in directory -->
<file>.</file>
<!-- Scan only PHP files -->
<arg
name="extensions"
value="php"
/>
<!-- Ignore WordPress and Composer dependencies -->
<exclude-pattern>web/wp</exclude-pattern>
<exclude-pattern>web/app/themes/twentytwentyfour/</exclude-pattern>
<exclude-pattern>vendor/</exclude-pattern>
<!-- Show colors in console -->
<arg value="-colors" />
<!-- Show sniff codes in all reports -->
<arg value="ns" />
<!-- Use PSR-2 as a base -->
<rule ref="PSR2" />
<!-- Désactivate certaines règles -->
<rule ref="Generic">
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found" />
<exclude name="Generic.Files.EndFileNoNewline.Found" />
<exclude name="Generic.Files.LowercasedFilename.NotFound" />
<exclude name="Generic.Functions.OpeningFunctionBraceBsdAllman.BraceOnSameLine" />
<exclude name="Generic.NamingConventions.CamelCapsFunctionName.NotCamelCaps" />
<exclude name="Generic.NamingConventions.CamelCapsFunctionName.ScopeNotCamelCaps" />
<exclude name="Generic.PHP.ClosingPHPTag.NotFound" />
<exclude name="Generic.PHP.UpperCaseConstant.Found" />
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed" />
<exclude name="Generic.WhiteSpace.ScopeIndent.Incorrect" />
<exclude name="Generic.WhiteSpace.ScopeIndent.IncorrectExact" />
</rule>
<rule ref="PSR1">
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps" />
</rule>
<rule ref="PSR2">
<exclude name="PSR2.Classes.ClassDeclaration.OpenBraceNewLine" />
</rule>
<rule ref="Squiz">
<exclude name="Squiz.Commenting.ClosingDeclarationComment.Missing" />
<exclude name="Squiz.Commenting.InlineComment.InvalidEndChar" />
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine" />
<exclude name="Squiz.NamingConventions.ValidFunctionName.NotCamelCaps" />
<exclude name="Squiz.NamingConventions.ValidVariableName.NotCamelCaps" />
<exclude name="Squiz.Strings.DoubleQuoteUsage.NotRequired" />
<exclude name="Squiz.WhiteSpace.FunctionClosingBraceSpace.SpacingBeforeClose" />
<exclude name="Squiz.WhiteSpace.FunctionSpacing.After" />
</rule>
</ruleset>

12
phpstan.neon Executable file
View file

@ -0,0 +1,12 @@
parameters:
level: 6
paths:
- web/app/themes/haiku-atelier-2024
scanDirectories:
- vendor
- web/app/plugins
- web/vendor
- web/wp
typeAliases:
InformationsProduitShop: 'array{id: int, nom: string, prix: string, photo_repos: string, photo_survol: string, url: string}'
InformationsVariation: 'array{id: int, titre: string, prix: string}'

Some files were not shown because too many files have changed in this diff Show more