Compare commits

..

15 commits

17 changed files with 278 additions and 187 deletions

View file

@ -11,6 +11,7 @@
"!oxlint", "!oxlint",
"!prettier", "!prettier",
"!tailwindcss-language-server", "!tailwindcss-language-server",
"!tsgo",
"!vtsls", "!vtsls",
"..." "..."
], ],

View file

@ -13,13 +13,16 @@ importers:
version: 4.0.0-rc.5 version: 4.0.0-rc.5
'@sentry/browser': '@sentry/browser':
specifier: ^10.50.0 specifier: ^10.50.0
version: 10.50.0 version: 10.51.0
a11y-dialog: a11y-dialog:
specifier: ^8.1.5 specifier: ^8.1.5
version: 8.1.5 version: 8.1.5
effect: effect:
specifier: ^4.0.0-beta.59 specifier: ^4.0.0-beta.59
version: 4.0.0-beta.59 version: 4.0.0-beta.59
html-template-tag:
specifier: ^5.0.0
version: 5.0.0
lit-html: lit-html:
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2 version: 3.3.2
@ -52,8 +55,8 @@ importers:
specifier: ^0.85.1 specifier: ^0.85.1
version: 0.85.1 version: 0.85.1
'@effect/tsgo': '@effect/tsgo':
specifier: 0.5.1 specifier: ^0.5.1
version: 0.5.1 version: 0.5.2
'@gcch/configuration-eslint': '@gcch/configuration-eslint':
specifier: git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54 specifier: git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54
version: https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45 version: https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45
@ -68,7 +71,7 @@ importers:
version: 1.59.1 version: 1.59.1
'@sentry/core': '@sentry/core':
specifier: ^10.50.0 specifier: ^10.50.0
version: 10.50.0 version: 10.51.0
'@types/bun': '@types/bun':
specifier: ^1.3.13 specifier: ^1.3.13
version: 1.3.13 version: 1.3.13
@ -116,7 +119,7 @@ importers:
version: 2.6.1 version: 2.6.1
knip: knip:
specifier: ^6.8.0 specifier: ^6.8.0
version: 6.8.0 version: 6.9.0
lightningcss: lightningcss:
specifier: ^1.32.0 specifier: ^1.32.0
version: 1.32.0 version: 1.32.0
@ -740,15 +743,15 @@ packages:
resolution: {integrity: sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw==} resolution: {integrity: sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw==}
hasBin: true hasBin: true
'@effect/tsgo-linux-x64@0.5.1': '@effect/tsgo-linux-x64@0.5.2':
resolution: {integrity: sha512-70dMv3/H+P3KDNWb31qPXJiJh6s78k3+J+QXN8RatKiQYrJw2HhREYL6ToVx9y5WOV7XFvC0eCIIa4/AMwQLTw==} resolution: {integrity: sha512-V6sHIZlKQv693ABb9REX0RzIvzyCbNg2uP5+4MXwetlSxz8pmeAUCpraAQLXBkKlYL5rG9kMIobDFU9A88Nqig==}
os: os:
- linux - linux
cpu: cpu:
- x64 - x64
'@effect/tsgo@0.5.1': '@effect/tsgo@0.5.2':
resolution: {integrity: sha512-INANZ/NK9akOwSQVWpQgSDLjlegrs4gui21nuQsgN7zCjCmj4m/ixUDuVgtW2C0UfqhPWWabyFWCDntu7ryCZQ==} resolution: {integrity: sha512-LEKmx1rwP1j3l9mPW6Bx8VIdGKW+uEvvML89z4xiWnPC+h/uFm3y6FGHULop9Kl09Ybwn2TVuZzVPSZLj+ydmg==}
hasBin: true hasBin: true
'@es-joy/jsdoccomment@0.86.0': '@es-joy/jsdoccomment@0.86.0':
@ -969,28 +972,28 @@ packages:
'@rolldown/pluginutils@1.0.0-rc.17': '@rolldown/pluginutils@1.0.0-rc.17':
resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==}
'@sentry-internal/browser-utils@10.50.0': '@sentry-internal/browser-utils@10.51.0':
resolution: {integrity: sha512-42bxyRTxnCmYlWnvz4CxikuQNanw8UNma2WJrtxJ0f1MAJV2GhQGSHDLnA+lvFlmiz6qct3pfen/NXGyOTegTA==} resolution: {integrity: sha512-lNKBS4P7RUvf1niojXQWe9bU3gnBUCbST4Dj0pSiyat1N96cXVyHkeE+uGxowD0RrVWhs+kGHiVX3FcmRWF6sA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/feedback@10.50.0': '@sentry-internal/feedback@10.51.0':
resolution: {integrity: sha512-0k9XZF0wn86f77mIO2U3gNNyDZooy139CnEanRzHinrN106vVzvBZ6TUEQoHtoO1fqQxr+nWWVrqV/PXUqk47w==} resolution: {integrity: sha512-bCM95bcpphx28e6aU0bwRLxOgwosYsdNzezM1sM0pVOkb0TB3hDFRamramVDK+/Hp1o8qmRxS4c5w/A7YBZGkA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/replay-canvas@10.50.0': '@sentry-internal/replay-canvas@10.51.0':
resolution: {integrity: sha512-jx6RKBmcJSWdI92qDGS/sBv1w+7Cww879Z/moX7bw7ipHa/Ts3iDcB3rgZwvhmi17U+mvYsbJeL2DXkPo3TjPw==} resolution: {integrity: sha512-8PW1Pp+Yl3lPwYqhBCr5SgkuhDanu9ZLzUqD2bPKL/ElqbM2eDVIWxq4z4ZzePrmZa6IcCjTv6sVQJ7Z4dLyLA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/replay@10.50.0': '@sentry-internal/replay@10.51.0':
resolution: {integrity: sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==} resolution: {integrity: sha512-jCpI5HXSwK6ZT2HX70+mDRciAocHzSiDk4DTgvzV69Wvd+Ei5WLgE+d39eaEPsm8lUC0Ydntb5sJIB6uG9D4bw==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry/browser@10.50.0': '@sentry/browser@10.51.0':
resolution: {integrity: sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==} resolution: {integrity: sha512-Zdc0sKfenxUtW/OGhtJ7xHFN44bXR7YqxJ1zBDzlZfW0nTbeTTUZBq9z5NUw6qdS0Vs/i3V4qzAKTbRKWfqSEA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry/core@10.50.0': '@sentry/core@10.51.0':
resolution: {integrity: sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==} resolution: {integrity: sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sindresorhus/base62@1.0.0': '@sindresorhus/base62@1.0.0':
@ -1928,13 +1931,22 @@ packages:
hookified@2.2.0: hookified@2.2.0:
resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==}
html-element-attributes@3.5.0:
resolution: {integrity: sha512-rU2BFhp0kQla9sqPBI46C+zbP6PFOtD7z6XNAJ6as+cGecCDXLx0W3aIs6XdPLmBBG/Fy1meRi/n65Exofz4Qw==}
html-entities@2.6.0: html-entities@2.6.0:
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
html-es6cape@2.0.2:
resolution: {integrity: sha512-utzhH8rq2VABdW1LsPdv5tmxeMNOtP83If0jKCa79xPBgLWfcMvdf9K+EZoxJ5P7KioCxTs6WBnSDWLQHJ2lWA==}
html-tags@5.1.0: html-tags@5.1.0:
resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==}
engines: {node: '>=20.10'} engines: {node: '>=20.10'}
html-template-tag@5.0.0:
resolution: {integrity: sha512-FwF3Fi+v5Dr6ygxqqyJwJWdHteQtDusRXF5ae1syxTKbbVRC8UPtlfIua5KWbgXGneRAc7zNc+Z6x9efFl0W/w==}
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@ -2164,8 +2176,8 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
knip@6.8.0: knip@6.9.0:
resolution: {integrity: sha512-FaTrNiqc74KTUMI4KZ5CWWxR2oVTm/bEEik16NKz7usiUJXG4+Df2XA2SPAm+mG9bBY22NvBMM4IeBcUZFslyg==} resolution: {integrity: sha512-2GLjxteBwmsSA3Z5sJZpPDaNPBIMnlm4/9Nx4CZadEK7YccJZ2/4kwKgPWhVYEqxhwhD0WO4txWXNGTO/Odkkg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
@ -3830,11 +3842,11 @@ snapshots:
'@effect/language-service@0.85.1': {} '@effect/language-service@0.85.1': {}
'@effect/tsgo-linux-x64@0.5.1': {} '@effect/tsgo-linux-x64@0.5.2': {}
'@effect/tsgo@0.5.1': '@effect/tsgo@0.5.2':
optionalDependencies: optionalDependencies:
'@effect/tsgo-linux-x64': 0.5.1 '@effect/tsgo-linux-x64': 0.5.2
'@es-joy/jsdoccomment@0.86.0': '@es-joy/jsdoccomment@0.86.0':
dependencies: dependencies:
@ -4007,33 +4019,33 @@ snapshots:
'@rolldown/pluginutils@1.0.0-rc.17': {} '@rolldown/pluginutils@1.0.0-rc.17': {}
'@sentry-internal/browser-utils@10.50.0': '@sentry-internal/browser-utils@10.51.0':
dependencies: dependencies:
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/feedback@10.50.0': '@sentry-internal/feedback@10.51.0':
dependencies: dependencies:
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/replay-canvas@10.50.0': '@sentry-internal/replay-canvas@10.51.0':
dependencies: dependencies:
'@sentry-internal/replay': 10.50.0 '@sentry-internal/replay': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/replay@10.50.0': '@sentry-internal/replay@10.51.0':
dependencies: dependencies:
'@sentry-internal/browser-utils': 10.50.0 '@sentry-internal/browser-utils': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry/browser@10.50.0': '@sentry/browser@10.51.0':
dependencies: dependencies:
'@sentry-internal/browser-utils': 10.50.0 '@sentry-internal/browser-utils': 10.51.0
'@sentry-internal/feedback': 10.50.0 '@sentry-internal/feedback': 10.51.0
'@sentry-internal/replay': 10.50.0 '@sentry-internal/replay': 10.51.0
'@sentry-internal/replay-canvas': 10.50.0 '@sentry-internal/replay-canvas': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry/core@10.50.0': {} '@sentry/core@10.51.0': {}
'@sindresorhus/base62@1.0.0': {} '@sindresorhus/base62@1.0.0': {}
@ -5102,10 +5114,19 @@ snapshots:
hookified@2.2.0: {} hookified@2.2.0: {}
html-element-attributes@3.5.0: {}
html-entities@2.6.0: {} html-entities@2.6.0: {}
html-es6cape@2.0.2: {}
html-tags@5.1.0: {} html-tags@5.1.0: {}
html-template-tag@5.0.0:
dependencies:
html-element-attributes: 3.5.0
html-es6cape: 2.0.2
ignore@5.3.2: {} ignore@5.3.2: {}
ignore@7.0.5: {} ignore@7.0.5: {}
@ -5310,7 +5331,7 @@ snapshots:
kind-of@6.0.3: {} kind-of@6.0.3: {}
knip@6.8.0: knip@6.9.0:
dependencies: dependencies:
fdir: 6.5.0(picomatch@4.0.4) fdir: 6.5.0(picomatch@4.0.4)
formatly: 0.3.0 formatly: 0.3.0

View file

@ -8,6 +8,7 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('SAVEQUERIES', true); Config::define('SAVEQUERIES', true);
@ -25,6 +26,10 @@ Config::define('DISALLOW_FILE_MODS', false);
// WooCommerce // WooCommerce
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);
// Stripe // Stripe
Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET')); Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET'));

View file

@ -8,6 +8,7 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('WP_DEBUG', true); Config::define('WP_DEBUG', true);
@ -20,6 +21,10 @@ Config::define('DISALLOW_FILE_MODS', false);
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);
// Stripe // Stripe
Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET')); Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET'));

View file

@ -8,8 +8,13 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('DISALLOW_INDEXING', true); Config::define('DISALLOW_INDEXING', true);
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);

View file

@ -1,7 +1,7 @@
set shell := ["fish", "-c"] set shell := ["fish", "-c"]
# Recette par défaut. # Recette par défaut.
default: dev default: build-all
# Liste toutes les recettes # Liste toutes les recettes
list: list:
@ -12,7 +12,7 @@ list:
[group('php')] [group('php')]
update: update:
composer update composer update
bun update aube update
# Formatte avec treefmt. # Formatte avec treefmt.
[group('qualité')] [group('qualité')]
@ -22,7 +22,7 @@ treefmt:
# Formatte avec Prettier et treefmt. # Formatte avec Prettier et treefmt.
[group('qualité')] [group('qualité')]
format: format:
bun prettier \ aube x prettier \
--cache --cache-location ".cache/prettiercache" \ --cache --cache-location ".cache/prettiercache" \
--config "cfg/prettier.config.ts" \ --config "cfg/prettier.config.ts" \
--ignore-path "cfg/prettierignore" \ --ignore-path "cfg/prettierignore" \
@ -41,40 +41,40 @@ format:
# Compile, minifie et optimise Sass vers CSS. # Compile, minifie et optimise Sass vers CSS.
[group('css')] [group('css')]
build-css: build-css:
@bun sass \ @aube x sass \
--update \ --update \
"web/app/themes/haiku-atelier-2024/src/sass":"web/app/themes/haiku-atelier-2024/assets/css" "web/app/themes/haiku-atelier-2024/src/sass":"web/app/themes/haiku-atelier-2024/assets/css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/main.min.css" \ --output-file "web/app/themes/haiku-atelier-2024/assets/css/main.min.css" \
-- "web/app/themes/haiku-atelier-2024/assets/css/main.css" -- "web/app/themes/haiku-atelier-2024/assets/css/main.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-panier.min.css" \ --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" -- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-panier.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-accueil.min.css" \ --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" -- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-accueil.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-boutique.min.css" \ --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" -- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-boutique.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-a-propos.min.css" \ --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" -- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-a-propos.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-modele-simple.min.css" \ --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" -- "web/app/themes/haiku-atelier-2024/assets/css/pages/page-modele-simple.css"
@bun lightningcss \ @aube x lightningcss \
--bundle \ --bundle \
--minify \ --minify \
--output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-succes-commande.min.css" \ --output-file "web/app/themes/haiku-atelier-2024/assets/css/pages/page-succes-commande.min.css" \
@ -88,7 +88,12 @@ watch-css:
# Compile TypeScript en JavaScript. # Compile TypeScript en JavaScript.
[group('js')] [group('js')]
build-js: build-js:
bun --bun vite build --config "cfg/vite.config.ts" aube x vite build --config "cfg/vite.config.ts"
# Compile TypeScript à chaque changement de fichier.
[group('js')]
watch-js:
@watchexec -w "web/app/themes/haiku-atelier-2024/src/scripts" -w "web/app/themes/haiku-atelier-2024/src/scripts-effect" -- just build-js treefmt
# Compile tout. # Compile tout.
[group('css')] [group('css')]
@ -98,22 +103,17 @@ build-all:
@just build-js @just build-js
@just format @just format
# Compile TypeScript à chaque changement de fichier.
[group('js')]
watch-js:
bun --bun vite build --config "cfg/vite.config.ts" --watch
# Vérifie le code TypeScript avec des analyseurs statiques. # Vérifie le code TypeScript avec des analyseurs statiques.
[group('js')] [group('js')]
[group('qualité')] [group('qualité')]
lint-js: lint-js:
-bun eslint "web/app/themes/haiku-atelier-2024/src/scripts" -aube x eslint "web/app/themes/haiku-atelier-2024/src/scripts"
bun --bun oxlint \ -aube x oxlint \
--config cfg/oxlint.config.ts \ --config cfg/oxlint.config.ts \
--format stylish --format stylish
fix-js: fix-js:
bun --bun oxlint \ aube x oxlint \
--config cfg/oxlint.config.ts \ --config cfg/oxlint.config.ts \
--format stylish \ --format stylish \
--fix --fix-suggestions --fix-dangerously --fix --fix-suggestions --fix-dangerously
@ -122,13 +122,13 @@ fix-js:
[group('css')] [group('css')]
[group('qualité')] [group('qualité')]
lint-css: lint-css:
-bun stylelint --config "cfg/stylelint.config.ts" "web/app/themes/haiku-atelier-2024/src/sass/" --fix -aube x stylelint --config "cfg/stylelint.config.ts" "web/app/themes/haiku-atelier-2024/src/sass/" --fix
# Vérifie le code TypeScript mort avec knip # Vérifie le code TypeScript mort avec knip
[group('js')] [group('js')]
[group('qualité')] [group('qualité')]
lint-code-mort: lint-code-mort:
-bun knip -aube x knip
# Fusionne tous les changements actuels dans le commit précédent et pousse sur le répertoire distant avec Jujetsu. # Fusionne tous les changements actuels dans le commit précédent et pousse sur le répertoire distant avec Jujetsu.
[group('vcs')] [group('vcs')]
@ -143,19 +143,6 @@ lint-build-format-css:
-just build-css -just build-css
-just format -just format
# Lance un navigateur de développement.
[group('développement')]
dev:
@/opt/cromite/chrome --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222 --profile-directory=Guest "https://haikuatelier.gcch.local" &
# Recharge le premier onglet du navigateur de développement.
[group('développement')]
reload-tab:
#!/usr/bin/fish
set -f WSURL (curl -s http://127.1:9222/json | fx '.[0].webSocketDebuggerUrl')
set -f REQUEST '{ "id": 2, "method": "Page.reload", "params": { "ignoreCache": true, "scriptToEvaluateOnLoad": "" } }'
echo $REQUEST | websocat $WSURL
# Créé l'image OCI. # Créé l'image OCI.
[group('container')] [group('container')]
build-wordpress-container: build-wordpress-container:
@ -179,7 +166,7 @@ restart-services:
# Met à jour les conteneurs images des conteneurs. # Met à jour les conteneurs images des conteneurs.
[group('container')] [group('container')]
pull-images: pull-images:
bun "scripts/pull-container-images.ts" bun run "scripts/pull-container-images.ts"
export_production_db: export_production_db:
fish "scripts/déclenche-sauvegarde-bdd-production.fish" fish "scripts/déclenche-sauvegarde-bdd-production.fish"

View file

@ -16,6 +16,7 @@
"@sentry/browser": "^10.50.0", "@sentry/browser": "^10.50.0",
"a11y-dialog": "^8.1.5", "a11y-dialog": "^8.1.5",
"effect": "^4.0.0-beta.59", "effect": "^4.0.0-beta.59",
"html-template-tag": "^5.0.0",
"lit-html": "^3.3.2", "lit-html": "^3.3.2",
"purify-ts": "2.1.2", "purify-ts": "2.1.2",
"ts-pattern": "^5.9.0", "ts-pattern": "^5.9.0",
@ -23,7 +24,7 @@
}, },
"devDependencies": { "devDependencies": {
"@effect/language-service": "^0.85.1", "@effect/language-service": "^0.85.1",
"@effect/tsgo": "0.5.1", "@effect/tsgo": "^0.5.1",
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54", "@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54",
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd", "@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd",
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#d267d6dc5e", "@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#d267d6dc5e",

View file

@ -17,7 +17,6 @@ use WC_Product;
use function add_action; use function add_action;
use function array_map; use function array_map;
use function assert; use function assert;
use function base64_encode;
use function is_string; use function is_string;
use function wc_get_products; use function wc_get_products;
use function wp_create_nonce; use function wp_create_nonce;
@ -33,12 +32,7 @@ $products = array_map(callback: Product::from_wc_product(...), array: $wc_produc
$context['products'] = $products; $context['products'] = $products;
// Injecte les états initiaux des données du Produit sous forme de JSON dans le contexte. // Injecte les états initiaux des données du Produit sous forme de JSON dans le contexte.
$page_states = [ $page_states = ['authString' => Config::get('WOOCOMMERCE_API_AUTH_STRING'), 'nonce' => wp_create_nonce('wc_store_api')]
'nonce' => wp_create_nonce('wc_store_api'),
'authString' => base64_encode(
Config::get('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . Config::get('WOOCOMMERCE_API_CONSUMER_SECRET'),
),
]
|> wp_json_encode(...); |> wp_json_encode(...);
assert(is_string($page_states)); assert(is_string($page_states));
$context['page_states'] = $page_states; $context['page_states'] = $page_states;

View file

@ -462,8 +462,8 @@ input[type="checkbox"], input[type="radio"] {
transition: 0.2s background; transition: 0.2s background;
} }
input[type="checkbox"]:checked, input[type="radio"]:checked { input[type="checkbox"]:checked, input[type="radio"]:checked {
color: var(--couleur-blanc); color: var(--couleur-noir);
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
input[type="checkbox"]:checked::before, input[type="radio"]:checked::before { input[type="checkbox"]:checked::before, input[type="radio"]:checked::before {
content: "x"; content: "x";
@ -492,7 +492,7 @@ input[type="radio"] + label {
} }
@media (hover: hover) { @media (hover: hover) {
input[type="checkbox"]:hover, input[type="radio"]:hover { input[type="checkbox"]:hover, input[type="radio"]:hover {
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
} }

File diff suppressed because one or more lines are too long

View file

@ -131,7 +131,8 @@ function retire_merdes_wc(): void {
*/ */
function genere_balises_img_dans_produit_dans_reponse_rest( function genere_balises_img_dans_produit_dans_reponse_rest(
WP_REST_Response $response, WP_REST_Response $response,
mixed $_product, WC_Data $_product,
WP_REST_Request $_request,
): WP_REST_Response { ): WP_REST_Response {
// Vérifie que la Réponse a des données // Vérifie que la Réponse a des données
if (empty($response->data)) { if (empty($response->data)) {
@ -169,37 +170,34 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
return $response; return $response;
} }
add_filter('woocommerce_rest_prepare_product_object', 'genere_balises_img_dans_produit_dans_reponse_rest', 10, 2);
/** /**
* TODO. * TODO.
*/ */
function genere_prix_maximal_produit_variable_dans_reponse_rest( function genere_prix_maximal_produit_variable_dans_reponse_rest(
WP_REST_Response $reponse, WP_REST_Response $response,
WC_Data $_produit, WC_Data $_product,
WP_REST_Request $_request,
): WP_REST_Response { ): WP_REST_Response {
// Vérifie que la Réponse a des données // Vérifie que la Réponse a des données
if (empty($reponse->data)) { if (empty($response->data)) {
return $reponse; return $response;
} }
// Si le Produit n'est pas Variable, assigner le prix du Produit comme prix maximal // Si le Produit n'est pas Variable, assigner le prix du Produit comme prix maximal
if ('variable' !== $reponse->data['type']) { if ('variable' !== $response->data['type']) {
$reponse->data['prix_maximal'] = $reponse->data['regular_price']; $response->data['prix_maximal'] = $response->data['regular_price'];
return $reponse; return $response;
} }
// Assigne le prix de la Variation la plus chère dans la Réponse // Assigne le prix de la Variation la plus chère dans la Réponse
$reponse->data['prix_maximal'] = collect($reponse->data['variations']) $response->data['prix_maximal'] = collect($response->data['variations'])
->map(wc_get_product(...)) ->map(wc_get_product(...))
->map(static fn($p) => $p->get_price())->max(); ->map(static fn($p) => $p->get_price())->max();
return $reponse; return $response;
} }
add_filter('woocommerce_rest_prepare_product_object', 'genere_prix_maximal_produit_variable_dans_reponse_rest', 10, 2);
/** /**
* Retire la propagande commerciale de WooCommerce du menu. * Retire la propagande commerciale de WooCommerce du menu.
*/ */
@ -216,3 +214,8 @@ add_action('init', 'retire_script_galerie');
add_action('template_redirect', 'retire_merdes_wc'); add_action('template_redirect', 'retire_merdes_wc');
add_action('wp_enqueue_scripts', 'dequeue_woocommerce_styles_scripts'); add_action('wp_enqueue_scripts', 'dequeue_woocommerce_styles_scripts');
add_filter('woocommerce_enqueue_styles', '__return_empty_array'); add_filter('woocommerce_enqueue_styles', '__return_empty_array');
add_filter('woocommerce_rest_prepare_product_object', 'genere_balises_img_dans_produit_dans_reponse_rest', 10, 3);
add_filter('woocommerce_rest_prepare_product_object', 'genere_prix_maximal_produit_variable_dans_reponse_rest', 10, 3);
// DEBUG
// add_filter('woocommerce_store_api_disable_nonce_check', '__return_true');

View file

@ -66,8 +66,8 @@ input[type="checkbox"], input[type="radio"] {
transition: 0.2s background; transition: 0.2s background;
&:checked { &:checked {
color: var(--couleur-blanc); color: var(--couleur-noir);
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
// TODO: Utiliser un SVG plutôt qu'un « x » ? // TODO: Utiliser un SVG plutôt qu'un « x » ?
&::before { &::before {
@ -98,7 +98,7 @@ input[type="checkbox"], input[type="radio"] {
@media (hover: hover) { @media (hover: hover) {
&:hover { &:hover {
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
} }
} }

View file

@ -1,4 +1,4 @@
import { Console, Context, Effect, Layer, Match, pipe, Schedule, Schema, SchemaIssue } from "effect"; import { Console, Context, Effect, Layer, Match, pipe, References, Schedule, Schema, SchemaIssue } from "effect";
import type { SchemaError } from "effect/Schema"; import type { SchemaError } from "effect/Schema";
import type { import type {
HttpClientError, HttpClientError,
@ -11,6 +11,7 @@ import {
} from "effect/unstable/http"; } from "effect/unstable/http";
import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError"; import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError";
import type { CartProduct, GetProducts } from "../schemas/api.ts"; import type { CartProduct, GetProducts } from "../schemas/api.ts";
import { Product } from "../schemas/api.ts";
import { WooCommerceCart } from "../schemas/cart.ts"; import { WooCommerceCart } from "../schemas/cart.ts";
/** Le nombre maximal d'essais pour une Requête. */ /** Le nombre maximal d'essais pour une Requête. */
@ -52,7 +53,7 @@ const APIFetchClient = FetchHttpClient.layer.pipe(
Layer.succeed( Layer.succeed(
FetchHttpClient.RequestInit, FetchHttpClient.RequestInit,
{ {
credentials: "same-origin", credentials: "include",
headers: { headers: {
Accept: "application/json", Accept: "application/json",
"Content-Type": "application/json", "Content-Type": "application/json",
@ -135,18 +136,22 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
); );
const GetProducts = Effect.fn("APIClient.GetProducts")( const GetProducts = Effect.fn("APIClient.GetProducts")(
function*(nonce: string, authString: string, queryParams: GetProducts) { function*(nonce: string, queryParams: GetProducts) {
const request = pipe( const request = pipe(
HttpClientRequest.get(`/wp-json/wc/store/products`), HttpClientRequest.get(`/wp-json/wc/v3/products`),
HttpClientRequest.setHeader("Nonce", nonce), HttpClientRequest.setHeader("Nonce", nonce),
HttpClientRequest.bearerToken(authString), // TODO: Utiliser l'environnement
HttpClientRequest.basicAuth(
"ck_eded693107df0dbc19dab937e0c71325db810a4a",
"cs_a68c0f3e711c4a21be51495d09e6fe807649bbfb",
),
// Le corps de la Requête a été validée en amont, on peut utiliser Unsafe. // Le corps de la Requête a été validée en amont, on peut utiliser Unsafe.
HttpClientRequest.setUrlParams(queryParams), HttpClientRequest.setUrlParams(queryParams),
); );
const response = yield* pipe( const response = yield* pipe(
haikuHTTPClient.execute(request), haikuHTTPClient.execute(request),
Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Unknown)), Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Array(Product))),
Effect.mapError(error => matchAPIError(error)), Effect.mapError(error => matchAPIError(error)),
Effect.tapError(error => printErrorAsSuccinctMessage(error)), Effect.tapError(error => printErrorAsSuccinctMessage(error)),
); );

View file

@ -18,4 +18,47 @@ class GetProducts extends Schema.Class<GetProducts>("GetProducts")({
status: ProductStatus, status: ProductStatus,
}) {} }) {}
export { CartProduct, GetProducts }; class Product extends Schema.Class<Product>("Product")({
attributes: Schema.Unknown,
brands: Schema.Unknown,
// TODO: Pourrait être une énumération.
catalog_visibility: Schema.String,
categories: Schema.Unknown,
description: Schema.String,
dimensions: Schema.Unknown,
featured: Schema.Boolean,
grouped_products: Schema.Unknown,
has_options: Schema.Boolean,
id: Schema.Int,
// NOTE: Non-standard, injecté dans la Réponse.
image_repos: Schema.String,
// NOTE: Non-standard, injecté dans la Réponse.
image_survol: Schema.String,
images: Schema.Unknown,
low_stock_amount: Schema.Union([Schema.Number, Schema.Null]),
menu_order: Schema.Int,
meta_data: Schema.Unknown,
name: Schema.String,
on_sale: Schema.Boolean,
parent_id: Schema.Int,
permalink: Schema.URLFromString,
price: Schema.String,
// NOTE: Non-standard, injecté dans la Réponse.
prix_maximal: Schema.String,
regular_price: Schema.String,
sale_price: Schema.String,
short_description: Schema.String,
sku: Schema.String,
slug: Schema.String,
sold_individually: Schema.Boolean,
stock_quantity: Schema.Union([Schema.Int, Schema.Null]),
// TODO: Pourrait être une énumération.
stock_status: Schema.String,
tags: Schema.Unknown,
type: Schema.Literals(["external", "grouped", "simple", "variable"]),
variations: Schema.Array(Schema.Int),
virtual: Schema.Boolean,
weight: Schema.String,
}) {}
export { CartProduct, GetProducts, Product };

View file

@ -1,4 +1,5 @@
import { import {
Array as FxArray,
Console, Console,
Context, Context,
Effect, Effect,
@ -12,55 +13,111 @@ import {
SubscriptionRef, SubscriptionRef,
} from "effect"; } from "effect";
import { SchemaError } from "effect/Schema"; import { SchemaError } from "effect/Schema";
import html from "html-template-tag";
import { APIClient } from "../../scripts-effect/lib/api.ts"; import { APIClient } from "../../scripts-effect/lib/api.ts";
import { setLoadingState } from "../../scripts-effect/lib/elements.ts"; import { setLoadingState } from "../../scripts-effect/lib/elements.ts";
import { GetProducts } from "../../scripts-effect/schemas/api.ts"; import { GetProducts, Product } from "../../scripts-effect/schemas/api.ts";
import { ATTRIBUT_ID_CATEGORIE_PRODUITS } from "../constantes/dom.ts"; import { ATTRIBUT_HIDDEN, ATTRIBUT_ID_CATEGORIE_PRODUITS, ATTRIBUT_PAGE } from "../constantes/dom.ts";
import ShopPageElements from "./service-elements.ts"; import ShopPageElements from "./service-elements.ts";
import ShopPageMessages from "./service-messages.ts"; import ShopPageMessages from "./service-messages.ts";
/** Le nombre de Produits à afficher par « page ». */
const PRODUCTS_PER_PAGE = 18; const PRODUCTS_PER_PAGE = 18;
const PageStatesSchema = Schema.Struct({ /** Forme attendue des données injectées dans la page sous forme de JSON. */
class PageStates extends Schema.Opaque<PageStates>()(
Schema.Struct({
authString: Schema.NonEmptyString, authString: Schema.NonEmptyString,
nonce: Schema.NonEmptyString, nonce: Schema.NonEmptyString,
}); }),
) {}
class InvalidPageStateError extends Schema.TaggedErrorClass<InvalidPageStateError>()("InvalidPageStateError", { /** Représente une Erreur liée à un état de page invalide ou incohérent empêchant la poursuite des interactions/de la navigation. */
class InvalidShopPageStateError
extends Schema.TaggedErrorClass<InvalidShopPageStateError>()("InvalidShopPageStateError", {
cause: Schema.String, cause: Schema.String,
}) { })
static readonly fromSchemaError = (schemaError: SchemaError): InvalidPageStateError => {
new InvalidPageStateError({ /** Créé une `InvalidShopPageStateError` depuis une `SchemaError` levée suite à une validation. */
static readonly fromSchemaError = (schemaError: SchemaError): InvalidShopPageStateError =>
new InvalidShopPageStateError({
cause: SchemaIssue.makeFormatterDefault()(schemaError.issue), cause: SchemaIssue.makeFormatterDefault()(schemaError.issue),
}); });
} }
class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/ShopPageDOM", { class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/ShopPageDOM", {
make: Effect.gen(function*() { make: Effect.gen(function*() {
const Elements = yield* ShopPageElements; const { PageStatesRawJson, ProductsGrid, ShowMoreButton } = yield* ShopPageElements;
const Messages = yield* ShopPageMessages; const { ShowMoreButtonText } = yield* ShopPageMessages;
const API = yield* APIClient; const API = yield* APIClient;
const PageStates = yield* pipe( const { authString, nonce } = yield* pipe(
Elements.PageStatesRawJson.textContent, PageStatesRawJson.textContent,
(textContent: string) => (textContent: string) =>
Schema.decodeUnknownEffect(Schema.fromJsonString(PageStatesSchema))(textContent, { errors: "all" }), Schema.decodeUnknownEffect(Schema.fromJsonString(PageStates))(textContent, { errors: "all" }),
Effect.mapError(InvalidPageStateError.fromSchemaError), Effect.mapError(InvalidShopPageStateError.fromSchemaError),
); );
/** ID de la Catégorie des Produits de la Page, si la Page courante est une Archive. */ /** ID de la Catégorie des Produits de la Page, si la Page courante est une Archive. */
const ProductsCategoryId: Ref.Ref<Option.Option<number>> = yield* Ref.make( const ProductsCategoryId = yield* pipe(
Option.fromNullishOr(Number(Elements.ProductsGrid.getAttribute(ATTRIBUT_ID_CATEGORIE_PRODUITS))), ProductsGrid.getAttribute(ATTRIBUT_ID_CATEGORIE_PRODUITS),
Number,
Option.fromNullishOr,
Ref.make,
); );
// TODO: Créer une SubscriptionRef mettant à jour le DOM au changement de valeur. // TODO: Créer une SubscriptionRef mettant à jour le DOM au changement de valeur.
const PageNumber = yield* Ref.make(1); const PageNumber = yield* Ref.make(1);
const createProductDOM = (product: Product): HTMLElement => {
const article = document.createElement("article");
article.classList.add("produit");
article.innerHTML = html`<figure>
<a href="/product/${product.slug}">
<picture class="produit__illustration produit__illustration__principale">
$${product.image_repos}
</picture>
<picture class="produit__illustration produit__illustration__survol">
$${product.image_survol}
</picture>
</a>
<figcaption class="produit__textuel">
<h3 class="produit__textuel__titre">
<a href="$${product.permalink.toString()}">${product.name}</a>
</h3>
<p class="produit__textuel__prix">
${product.prix_maximal}
</p>
</figcaption>
</figure>
`;
return article;
};
const createNewPageDOM = (products: ReadonlyArray<Product>) => {
const fragment: DocumentFragment = document.createDocumentFragment();
// Ajoute le HTML des cartes des Produits au fragment.
pipe(
FxArray.take(products, PRODUCTS_PER_PAGE),
FxArray.forEach(product => {
const productHTML = createProductDOM(product);
fragment.append(productHTML);
}),
);
return fragment;
};
const onMoreProductedWantedHandler = Effect.fn("onMoreProductedWantedHandler")(function*() { const onMoreProductedWantedHandler = Effect.fn("onMoreProductedWantedHandler")(function*() {
yield* Console.debug("onMoreProductedWantedHandler"); yield* Console.debug("onMoreProductedWantedHandler");
const newPageNumber = yield* Ref.getAndUpdate(PageNumber, pageNumber => pageNumber + 1); /** Le numéro de page souhaitée. */
const newPageNumber = yield* Ref.updateAndGet(PageNumber, pageNumber => pageNumber + 1);
/** L'ID de la Catégorie de Produits affichée dans la page si elle existe. */
const categoryId = pipe(yield* Ref.get(ProductsCategoryId), Option.getOrUndefined); const categoryId = pipe(yield* Ref.get(ProductsCategoryId), Option.getOrUndefined);
const requestBody = yield* GetProducts.makeEffect({ const requestBody = yield* GetProducts.makeEffect({
page: newPageNumber, page: newPageNumber,
per_page: PRODUCTS_PER_PAGE, per_page: PRODUCTS_PER_PAGE,
@ -69,63 +126,27 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
}); });
// Désactive les interactions et affiche un texte de chargement le temps de la requête. // Désactive les interactions et affiche un texte de chargement le temps de la requête.
yield* setLoadingState(Elements.ShowMoreButton, true); yield* setLoadingState(ShowMoreButton, true);
yield* SubscriptionRef.set(Messages.ShowMoreButtonText, "Getting Products..."); yield* SubscriptionRef.set(ShowMoreButtonText, "Getting Products...");
const newProducts = yield* API.GetProducts(PageStates.nonce, PageStates.authString, requestBody); const newProducts = yield* API.GetProducts(nonce, requestBody);
yield* Console.debug("onMoreProductedWantedHandler", newProducts); yield* Console.debug("onMoreProductedWantedHandler", newProducts);
// Rétablis le texte du Bouton et réactive les interactions. // Rétablis le texte du Bouton et réactive les interactions.
yield* SubscriptionRef.set(Messages.ShowMoreButtonText, "Show more"); yield* SubscriptionRef.set(ShowMoreButtonText, "Show more");
yield* setLoadingState(Elements.ShowMoreButton, false); yield* setLoadingState(ShowMoreButton, false);
// Cache le bouton s'il y a moins de PRODUCTS_PER_PAGE Produits disponibles (que l'on est à la dernière page) // Cache le bouton s'il y a moins de Produits disponibles que PRODUCTS_PER_PAGE (que l'on est donc à la dernière page).
if (donnees.length < PRODUCTS_PER_PAGE) { ShowMoreButton.toggleAttribute(ATTRIBUT_HIDDEN, newProducts.length < PRODUCTS_PER_PAGE);
E.BOUTON_PLUS_DE_PRODUITS.toggleAttribute(ATTRIBUT_HIDDEN);
}
// Créé un DocumentFragment qui recevra tous les nouveaux Produits // Ajoute les nouveaux Produits dans le DOM.
const fragment: DocumentFragment = document.createDocumentFragment(); ProductsGrid.append(fragment);
ProductsGrid.setAttribute(ATTRIBUT_PAGE, String(newPageNumber));
// Créé les Éléments <article> à insérer
for (const produit of donnees.slice(0, PRODUCTS_PER_PAGE)) {
pipe(
html`
<article class="produit">
<figure>
<a href="/product/${produit.slug}">
<picture class="produit__illustration produit__illustration__principale">
${produit.image_repos ?? ""}
</picture>
<picture class="produit__illustration produit__illustration__survol">
${produit.image_survol ?? ""}
</picture>
</a>
<figcaption class="produit__textuel">
<h3 class="produit__textuel__titre">
<a href="${produit.permalink}">${produit.name}</a>
</h3>
<p class="produit__textuel__prix">
${produit.prix_maximal}
</p>
</figcaption>
</figure>
</article>
`,
tap(article => fragment.append(article)),
);
}
// Ajoute les nouveaux Produits dans le DOM
E.GRILLE_PRODUITS.append(fragment);
E.GRILLE_PRODUITS.setAttribute(ATTRIBUT_PAGE, String(nouveauNumeroPage));
}); });
const initLoadMoreProductsOnButtonClick = Effect.fn("initLoadMoreProductsOnButtonClick")(function*() { const initLoadMoreProductsOnButtonClick = Effect.fn("initLoadMoreProductsOnButtonClick")(function*() {
return yield* pipe( return yield* pipe(
Stream.fromEventListener(Elements.ShowMoreButton, "click"), Stream.fromEventListener(ShowMoreButton, "click"),
Stream.tap(onMoreProductedWantedHandler), Stream.tap(onMoreProductedWantedHandler),
Stream.runDrain, Stream.runDrain,
); );

View file

@ -6,7 +6,7 @@ class ShopPageMessages extends Context.Service<ShopPageMessages>()("haikuatelier
make: Effect.gen(function*() { make: Effect.gen(function*() {
const { ShowMoreButton } = yield* ShopPageElements; const { ShowMoreButton } = yield* ShopPageElements;
const ShowMoreButtonText = yield* SubscriptionRef.make("Add to cart"); const ShowMoreButtonText = yield* SubscriptionRef.make("Show more");
// Const ShowMoreErrorText = yield* SubscriptionRef.make<Option.Option<string>>(Option.none()); // Const ShowMoreErrorText = yield* SubscriptionRef.make<Option.Option<string>>(Option.none());
const initShowMoreButtonUpdates = Effect.fn("initShowMoreButtonUpdates")(function*() { const initShowMoreButtonUpdates = Effect.fn("initShowMoreButtonUpdates")(function*() {

View file

@ -2,7 +2,7 @@
* Scripts pour les fonctionnalités de la page Boutique. * Scripts pour les fonctionnalités de la page Boutique.
*/ */
import { Effect } from "effect"; import { Console, Effect } from "effect";
import ShopPageRuntime from "./page-boutique/runtime.ts"; import ShopPageRuntime from "./page-boutique/runtime.ts";
import ShopPageDOM from "./page-boutique/service-dom.ts"; import ShopPageDOM from "./page-boutique/service-dom.ts";
import ShopPageElements from "./page-boutique/service-elements.ts"; import ShopPageElements from "./page-boutique/service-elements.ts";
@ -18,7 +18,7 @@ document.addEventListener("DOMContentLoaded", (): void => {
yield* Effect.all([DOM.initLoadMoreProductsOnButtonClick(), Messages.initShowMoreButtonUpdates()], { yield* Effect.all([DOM.initLoadMoreProductsOnButtonClick(), Messages.initShowMoreButtonUpdates()], {
concurrency: "unbounded", concurrency: "unbounded",
}); }).pipe(Effect.tapError(Console.error));
console.debug(Elements.ProductsGrid); console.debug(Elements.ProductsGrid);
})); }));