Compare commits

..

6 commits

48 changed files with 1054 additions and 1401 deletions

View file

@ -18,162 +18,156 @@ $finder = new Finder()->in(__DIR__)->exclude([
return new Config() return new Config()
->setRiskyAllowed(true) ->setRiskyAllowed(true)
->setRules([ ->setRules([
'array_syntax' => ['syntax' => 'short'], 'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true, 'assign_null_coalescing_to_coalesce_equal' => true,
'attribute_empty_parentheses' => ['use_parentheses' => true], 'attribute_empty_parentheses' => ['use_parentheses' => true],
'blank_line_after_namespace' => true, 'blank_line_after_namespace' => true,
'blank_lines_before_namespace' => ['min_line_breaks' => 1, 'max_line_breaks' => 2], 'blank_lines_before_namespace' => ['min_line_breaks' => 1, 'max_line_breaks' => 2],
'cast_spaces' => true, 'cast_spaces' => true,
'class_attributes_separation' => ['elements' => [ 'class_attributes_separation' => [
'case' => 'none', 'elements' => [
'const' => 'none', 'case' => 'none',
'method' => 'one', 'const' => 'none',
'property' => 'one', 'method' => 'one',
'trait_import' => 'none', 'property' => 'one',
]], 'trait_import' => 'none',
'class_reference_name_casing' => true, ],
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => true,
'constant_case' => true,
'date_time_immutable' => true,
'declare_equal_normalize' => true,
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'echo_tag_syntax' => true,
'encoding' => true,
'ereg_to_preg' => true,
'error_suppression' => true,
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_class' => true,
'final_internal_class' => true,
'full_opening_tag' => true,
'fully_qualified_strict_types' => ['import_symbols' => true],
'function_to_constant' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => true,
'import_functions' => true,
], ],
'heredoc_to_nowdoc' => true, 'class_reference_name_casing' => true,
'integer_literal_case' => true, 'clean_namespace' => true,
'lambda_not_used_import' => true, 'combine_consecutive_issets' => true,
'list_syntax' => true, 'combine_consecutive_unsets' => true,
'logical_operators' => true, 'combine_nested_dirname' => true,
'long_to_shorthand_operator' => true, 'comment_to_phpdoc' => true,
'lowercase_cast' => true, 'constant_case' => true,
'lowercase_keywords' => true, 'date_time_immutable' => true,
'lowercase_static_reference' => true, 'declare_equal_normalize' => true,
'magic_constant_casing' => true, 'declare_parentheses' => true,
'magic_method_casing' => true, 'declare_strict_types' => true,
'mb_str_functions' => true, 'dir_constant' => true,
'modernize_strpos' => ['modernize_stripos' => true], 'echo_tag_syntax' => true,
'modernize_types_casting' => true, 'encoding' => true,
'modifier_keywords' => true, 'ereg_to_preg' => true,
'multiline_comment_opening_closing' => true, 'error_suppression' => true,
'native_constant_invocation' => true, 'explicit_indirect_variable' => true,
'native_function_casing' => true, 'explicit_string_variable' => true,
'native_function_invocation' => [ 'final_class' => true,
'include' => ['@compiler_optimized'], 'final_internal_class' => true,
'scope' => 'namespaced', 'full_opening_tag' => true,
'strict' => true, 'fully_qualified_strict_types' => ['import_symbols' => true],
'function_to_constant' => true,
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
'heredoc_to_nowdoc' => true,
'integer_literal_case' => true,
'lambda_not_used_import' => true,
'list_syntax' => true,
'logical_operators' => true,
'long_to_shorthand_operator' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => true,
'modernize_strpos' => ['modernize_stripos' => true],
'modernize_types_casting' => true,
'modifier_keywords' => true,
'multiline_comment_opening_closing' => true,
'native_constant_invocation' => true,
'native_function_casing' => true,
'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced', 'strict' => true],
'native_type_declaration_casing' => true,
'new_expression_parentheses' => true,
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => true,
'no_binary_string' => true,
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiple_statements_per_line' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_trailing_comma_in_singleline' => true,
'no_trailing_whitespace_in_comment' => true,
'no_unneeded_braces' => ['namespaces' => true],
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'negative_instanceof',
'others',
'return',
'switch_case',
'yield',
'yield_from',
],
], ],
'native_type_declaration_casing' => true, 'no_unneeded_final_method' => true,
'new_expression_parentheses' => true, 'no_unneeded_import_alias' => true,
'no_alias_functions' => ['sets' => ['@all']], 'no_unreachable_default_argument_value' => true,
'no_alias_language_construct_call' => true, 'no_unset_cast' => true,
'no_alternative_syntax' => true, 'no_unset_on_property' => true,
'no_binary_string' => true, 'no_unused_imports' => true,
'no_closing_tag' => true, 'no_useless_concat_operator' => true,
'no_empty_comment' => true, 'no_useless_nullsafe_operator' => true,
'no_homoglyph_names' => true, 'no_useless_printf' => true,
'no_leading_import_slash' => true, 'no_useless_return' => true,
'no_mixed_echo_print' => ['use' => 'echo'], 'no_useless_sprintf' => true,
'no_multiline_whitespace_around_double_arrow' => true, 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
'no_multiple_statements_per_line' => true, 'non_printable_character' => true,
'no_null_property_initialization' => true, 'normalize_index_brace' => true,
'no_php4_constructor' => true, 'nullable_type_declaration' => ['syntax' => 'union'],
'no_short_bool_cast' => true,
'no_trailing_comma_in_singleline' => true,
'no_trailing_whitespace_in_comment' => true,
'no_unneeded_braces' => ['namespaces' => true],
'no_unneeded_control_parentheses' => ['statements' => [
'break',
'clone',
'continue',
'echo_print',
'negative_instanceof',
'others',
'return',
'switch_case',
'yield',
'yield_from',
]],
'no_unneeded_final_method' => true,
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => true,
'no_unused_imports' => true,
'no_useless_concat_operator' => true,
'no_useless_nullsafe_operator' => true,
'no_useless_printf' => true,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
'non_printable_character' => true,
'normalize_index_brace' => true,
'nullable_type_declaration' => ['syntax' => 'union'],
'nullable_type_declaration_for_default_null_value' => true, 'nullable_type_declaration_for_default_null_value' => true,
'numeric_literal_separator' => ['override_existing' => true, 'strategy' => 'use_separator'], 'numeric_literal_separator' => ['override_existing' => true, 'strategy' => 'use_separator'],
'ordered_attributes' => true, 'ordered_attributes' => true,
'ordered_class_elements' => ['case_sensitive' => false, 'sort_algorithm' => 'alpha'], 'ordered_class_elements' => ['case_sensitive' => false, 'sort_algorithm' => 'alpha'],
'ordered_imports' => ['case_sensitive' => true], 'ordered_imports' => ['case_sensitive' => true],
'ordered_interfaces' => true, 'ordered_interfaces' => true,
'ordered_traits' => true, 'ordered_traits' => true,
'ordered_types' => ['null_adjustment' => 'always_last'], 'ordered_types' => ['null_adjustment' => 'always_last'],
'phpdoc_readonly_class_comment_to_keyword' => true, 'phpdoc_readonly_class_comment_to_keyword' => true,
'phpdoc_to_param_type' => true, 'phpdoc_to_param_type' => true,
'phpdoc_to_property_type' => true, 'phpdoc_to_property_type' => true,
'phpdoc_to_return_type' => true, 'phpdoc_to_return_type' => true,
'pow_to_exponentiation' => true, 'pow_to_exponentiation' => true,
'protected_to_private' => true, 'protected_to_private' => true,
'psr_autoloading' => true, 'psr_autoloading' => true,
'random_api_migration' => ['replacements' => [ 'random_api_migration' => [
'getrandmax' => 'mt_getrandmax', 'replacements' => ['getrandmax' => 'mt_getrandmax', 'rand' => 'mt_rand', 'srand' => 'mt_srand'],
'rand' => 'mt_rand', ],
'srand' => 'mt_srand', 'return_assignment' => true,
]], 'self_accessor' => true,
'return_assignment' => true, 'self_static_accessor' => true,
'self_accessor' => true, 'set_type_to_cast' => true,
'self_static_accessor' => true, 'short_scalar_cast' => true,
'set_type_to_cast' => true, 'simple_to_complex_string_variable' => true,
'short_scalar_cast' => true, 'simplified_null_return' => true,
'simple_to_complex_string_variable' => true, 'single_class_element_per_statement' => true,
'simplified_null_return' => true, 'single_import_per_statement' => true,
'single_class_element_per_statement' => true, 'single_line_after_imports' => true,
'single_import_per_statement' => true, 'single_line_comment_spacing' => true,
'single_line_after_imports' => true, 'single_line_comment_style' => true,
'single_line_comment_spacing' => true, 'single_line_empty_body' => true,
'single_line_comment_style' => true, 'single_trait_insert_per_statement' => true,
'single_line_empty_body' => true, 'standardize_not_equals' => true,
'single_trait_insert_per_statement' => true, 'static_lambda' => true,
'standardize_not_equals' => true, 'strict_comparison' => true,
'static_lambda' => true, 'strict_param' => true,
'strict_comparison' => true, 'string_implicit_backslashes' => true,
'strict_param' => true, 'string_length_to_empty' => true,
'string_implicit_backslashes' => true, 'switch_continue_to_break' => true,
'string_length_to_empty' => true, 'ternary_to_null_coalescing' => true,
'switch_continue_to_break' => true, 'trim_array_spaces' => true,
'ternary_to_null_coalescing' => true, 'use_arrow_functions' => true,
'trim_array_spaces' => true, 'void_return' => true,
'use_arrow_functions' => true, 'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'void_return' => true,
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
// --- // ---
// Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one. // Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.
'align_multiline_comment' => ['comment_type' => 'all_multiline'], 'align_multiline_comment' => ['comment_type' => 'all_multiline'],
@ -184,7 +178,7 @@ return new Config()
// Removes @param, @return and @var tags that don't provide any useful information. // Removes @param, @return and @var tags that don't provide any useful information.
'no_superfluous_phpdoc_tags' => [ 'no_superfluous_phpdoc_tags' => [
'allow_hidden_params' => false, 'allow_hidden_params' => false,
'allow_mixed' => false, 'allow_mixed' => false,
'allow_unused_params' => false, 'allow_unused_params' => false,
], ],
// PHPDoc should contain @param for all params. // PHPDoc should contain @param for all params.
@ -222,20 +216,22 @@ return new Config()
// The type of @return annotations of methods returning a reference to itself must the configured one. // The type of @return annotations of methods returning a reference to itself must the configured one.
'phpdoc_return_self_reference' => true, 'phpdoc_return_self_reference' => true,
// Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double. // Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double.
'phpdoc_scalar' => ['types' => [ 'phpdoc_scalar' => [
'boolean', 'types' => [
'callback', 'boolean',
'double', 'callback',
'integer', 'double',
'never-return', 'integer',
'never-returns', 'never-return',
'no-return', 'never-returns',
'real', 'no-return',
'str', 'real',
]], 'str',
],
],
// Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other. Annotations of a different type are separated by a single blank line. // Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other. Annotations of a different type are separated by a single blank line.
'phpdoc_separation' => [ 'phpdoc_separation' => [
'groups' => [ 'groups' => [
['Annotation', 'NamedArgumentConstructor', 'Target'], ['Annotation', 'NamedArgumentConstructor', 'Target'],
['author', 'copyright', 'license'], ['author', 'copyright', 'license'],
['category', 'package', 'subpackage'], ['category', 'package', 'subpackage'],

View file

@ -1,5 +1,11 @@
{ {
"$schema": "./phpactor.schema.json", "$schema": "./phpactor.schema.json",
"indexer.exclude_patterns": [
"/var/cache/**/*",
"/vendor/**/tests/**/*",
"/vendor/**/Tests/**/*",
"/vendor/composer/**/*"
],
"language_server.diagnostic_outsource_timeout": 5, "language_server.diagnostic_outsource_timeout": 5,
"language_server.diagnostics_on_save": true, "language_server.diagnostics_on_save": true,
"language_server.diagnostics_on_update": true, "language_server.diagnostics_on_update": true,

View file

@ -1,19 +0,0 @@
# :schema: https://github.com/AJenbo/phpantom_lsp/raw/main/config-schema.json
[php]
# Override the detected PHP version (default: inferred from composer.json, or 8.5).
# version = "8.5"
#
[diagnostics]
extra-arguments = true
# Report member access on subjects whose type could not be resolved.
# Useful for discovering gaps in type coverage. Off by default.
unresolved-member-access = false
[indexing]
# How PHPantom discovers classes across the workspace.
# "composer" (default) - use Composer classmap, self-scan on fallback
# "self" - always self-scan, ignore Composer classmap
# "none" - no proactive scanning, Composer classmap only
strategy = "composer"

View file

@ -9,7 +9,6 @@
"!oxc", "!oxc",
"!oxfmt", "!oxfmt",
"!oxlint", "!oxlint",
"!phptools",
"!prettier", "!prettier",
"!tailwindcss-language-server", "!tailwindcss-language-server",
"!tsgo", "!tsgo",

View file

@ -4,9 +4,6 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
time:
globals@17.6.0: 2026-05-01T16:37:48.055Z
importers: importers:
.: .:
@ -15,7 +12,7 @@ importers:
specifier: v4.0.0-rc.5 specifier: v4.0.0-rc.5
version: 4.0.0-rc.5 version: 4.0.0-rc.5
'@sentry/browser': '@sentry/browser':
specifier: ^10.51.0 specifier: ^10.50.0
version: 10.51.0 version: 10.51.0
a11y-dialog: a11y-dialog:
specifier: ^8.1.5 specifier: ^8.1.5
@ -58,7 +55,7 @@ importers:
specifier: ^0.85.1 specifier: ^0.85.1
version: 0.85.1 version: 0.85.1
'@effect/tsgo': '@effect/tsgo':
specifier: ^0.5.2 specifier: ^0.5.1
version: 0.5.2 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
@ -73,7 +70,7 @@ importers:
specifier: ^1.59.1 specifier: ^1.59.1
version: 1.59.1 version: 1.59.1
'@sentry/core': '@sentry/core':
specifier: ^10.51.0 specifier: ^10.50.0
version: 10.51.0 version: 10.51.0
'@types/bun': '@types/bun':
specifier: ^1.3.13 specifier: ^1.3.13
@ -82,8 +79,8 @@ importers:
specifier: ^25.6.0 specifier: ^25.6.0
version: 25.6.0 version: 25.6.0
'@typescript/native-preview': '@typescript/native-preview':
specifier: 7.0.0-dev.20260503.1 specifier: 7.0.0-dev.20260429.1
version: 7.0.0-dev.20260503.1 version: 7.0.0-dev.20260429.1
'@vitejs/plugin-legacy': '@vitejs/plugin-legacy':
specifier: ^8.0.1 specifier: ^8.0.1
version: 8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3)) version: 8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))
@ -97,32 +94,32 @@ importers:
specifier: ^1.0.30001791 specifier: ^1.0.30001791
version: 1.0.30001791 version: 1.0.30001791
eslint: eslint:
specifier: ^10.3.0 specifier: ^10.2.1
version: 10.3.0(jiti@2.6.1) version: 10.2.1(jiti@2.6.1)
eslint-plugin-functional: eslint-plugin-functional:
specifier: ^9.0.4 specifier: ^9.0.4
version: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) version: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsx-a11y: eslint-plugin-jsx-a11y:
specifier: ^6.10.2 specifier: ^6.10.2
version: 6.10.2(eslint@10.3.0(jiti@2.6.1)) version: 6.10.2(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-oxlint: eslint-plugin-oxlint:
specifier: ^1.62.0 specifier: ^1.62.0
version: 1.62.0(oxlint@1.62.0(oxlint-tsgolint@0.22.1)) version: 1.62.0(oxlint@1.62.0(oxlint-tsgolint@0.22.1))
eslint-plugin-perfectionist: eslint-plugin-perfectionist:
specifier: ^5.9.0 specifier: ^5.9.0
version: 5.9.0(eslint@10.3.0(jiti@2.6.1)) version: 5.9.0(eslint@10.2.1(jiti@2.6.1))
fdir: fdir:
specifier: ^6.5.0 specifier: ^6.5.0
version: 6.5.0(picomatch@4.0.4) version: 6.5.0(picomatch@4.0.4)
globals: globals:
specifier: ^17.6 specifier: ^17.5.0
version: 17.6.0 version: 17.5.0
jiti: jiti:
specifier: ^2.6.1 specifier: ^2.6.1
version: 2.6.1 version: 2.6.1
knip: knip:
specifier: ^6.11.0 specifier: ^6.8.0
version: 6.11.0 version: 6.9.0
lightningcss: lightningcss:
specifier: ^1.32.0 specifier: ^1.32.0
version: 1.32.0 version: 1.32.0
@ -185,7 +182,7 @@ importers:
version: 6.0.3 version: 6.0.3
typescript-eslint: typescript-eslint:
specifier: ^8.59.1 specifier: ^8.59.1
version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) version: 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
vite: vite:
specifier: ^8.0.10 specifier: ^8.0.10
version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3) version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3)
@ -1207,16 +1204,16 @@ packages:
typescript: '>=4.5.2' typescript: '>=4.5.2'
aliasOf: '@better-typescript-lib/webworker' aliasOf: '@better-typescript-lib/webworker'
'@typescript/native-preview-linux-x64@7.0.0-dev.20260503.1': '@typescript/native-preview-linux-x64@7.0.0-dev.20260429.1':
resolution: {integrity: sha512-M64z7LwpqNfOXYCBKmD/ObwyxYOobUk4tDv0ECNLit7pDER1sswNZjJGjgRYjQsKokmydy6p3FqtJ1uUPUP/sw==} resolution: {integrity: sha512-haAOqc0fJCZkt4RDi0/ZQGBdDfpDzr2N+mEcR+FbiYQD3Y00kOK34hXSrjZafO2kq56ZDWunvCaUTCev0fJDbA==}
engines: {node: '>=16.20.0'} engines: {node: '>=16.20.0'}
os: os:
- linux - linux
cpu: cpu:
- x64 - x64
'@typescript/native-preview@7.0.0-dev.20260503.1': '@typescript/native-preview@7.0.0-dev.20260429.1':
resolution: {integrity: sha512-gDro38CPFiBUGbaFGNt+ufOsEd1OrZrfrOPxsLSfBcvvoGaqAxV++ul/BHTOShoEkIYHiFsoDX2az1IPCDV2jQ==} resolution: {integrity: sha512-SGKnvs5EA+V1spnraYJqum/lEajE0IQ2bVVPC72hFfWjoCfQ6N7iVYxLUGreiE3VFyQWWQBPgXZrRUFnawVvpQ==}
engines: {node: '>=16.20.0'} engines: {node: '>=16.20.0'}
hasBin: true hasBin: true
@ -1694,8 +1691,8 @@ packages:
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24} engines: {node: ^20.19.0 || ^22.13.0 || >=24}
eslint@10.3.0: eslint@10.2.1:
resolution: {integrity: sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==} resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24} engines: {node: ^20.19.0 || ^22.13.0 || >=24}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -1875,10 +1872,6 @@ packages:
resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==}
engines: {node: '>=18'} engines: {node: '>=18'}
globals@17.6.0:
resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==}
engines: {node: '>=18'}
globalthis@1.0.4: globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -2183,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.11.0: knip@6.9.0:
resolution: {integrity: sha512-84PTlN8Q5smLpTbzs8smTVh8PMbTDXtw0tFksXq/m6auGFC/KSzJykKFmnYh3As38kiWDkoDBvdTTyKk5M1TAQ==} 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
@ -3865,9 +3858,9 @@ snapshots:
'@es-joy/resolve.exports@1.2.0': {} '@es-joy/resolve.exports@1.2.0': {}
'@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.6.1))': '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))':
dependencies: dependencies:
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {} '@eslint-community/regexpp@4.12.2': {}
@ -3886,9 +3879,9 @@ snapshots:
dependencies: dependencies:
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
'@eslint/js@10.0.1(eslint@10.3.0(jiti@2.6.1))': '@eslint/js@10.0.1(eslint@10.2.1(jiti@2.6.1))':
dependencies: dependencies:
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
'@eslint/object-schema@3.0.5': {} '@eslint/object-schema@3.0.5': {}
@ -3899,24 +3892,24 @@ snapshots:
'@gcch/configuration-eslint@https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45': '@gcch/configuration-eslint@https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45':
dependencies: dependencies:
'@eslint/js': 10.0.1(eslint@10.3.0(jiti@2.6.1)) '@eslint/js': 10.0.1(eslint@10.2.1(jiti@2.6.1))
astro-eslint-parser: 1.4.0 astro-eslint-parser: 1.4.0
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
eslint-plugin-functional: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) eslint-plugin-functional: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsdoc: 62.9.0(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-jsdoc: 62.9.0(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-perfectionist: 5.9.0(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-perfectionist: 5.9.0(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-sonarjs: 4.0.3(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-sonarjs: 4.0.3(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-unicorn: 64.0.0(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-unicorn: 64.0.0(eslint@10.2.1(jiti@2.6.1))
globals: 17.6.0 globals: 17.5.0
typescript-eslint: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) typescript-eslint: 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@gcch/configuration-oxlint@https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd6cb402e3c7f074b3e267632ebf4a': '@gcch/configuration-oxlint@https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd6cb402e3c7f074b3e267632ebf4a':
dependencies: dependencies:
eslint-plugin-astro: 1.7.0(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-astro: 1.7.0(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-functional: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) eslint-plugin-functional: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsx-a11y: 6.10.2(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@10.2.1(jiti@2.6.1))
eslint-plugin-perfectionist: 5.9.0(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-perfectionist: 5.9.0(eslint@10.2.1(jiti@2.6.1))
globals: 17.6.0 globals: 17.5.0
oxlint: 1.62.0(oxlint-tsgolint@0.22.1) oxlint: 1.62.0(oxlint-tsgolint@0.22.1)
oxlint-tsgolint: 0.22.1 oxlint-tsgolint: 0.22.1
@ -4098,29 +4091,29 @@ snapshots:
'@types/trusted-types@2.0.7': {} '@types/trusted-types@2.0.7': {}
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
? '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)' ? '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)'
: dependencies: : dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/parser': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/type-utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.59.1 '@typescript-eslint/visitor-keys': 8.59.1
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
ignore: 7.0.5 ignore: 7.0.5
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.59.1 '@typescript-eslint/visitor-keys': 8.59.1
debug: 4.4.3 debug: 4.4.3
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/project-service@8.59.1(typescript@6.0.3)': '@typescript-eslint/project-service@8.59.1(typescript@6.0.3)':
@ -4139,13 +4132,13 @@ snapshots:
dependencies: dependencies:
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/type-utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/type-utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
debug: 4.4.3 debug: 4.4.3
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
@ -4164,13 +4157,13 @@ snapshots:
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1))
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/visitor-keys@8.59.1': '@typescript-eslint/visitor-keys@8.59.1':
@ -4246,11 +4239,11 @@ snapshots:
dependencies: dependencies:
typescript: 6.0.3 typescript: 6.0.3
'@typescript/native-preview-linux-x64@7.0.0-dev.20260503.1': {} '@typescript/native-preview-linux-x64@7.0.0-dev.20260429.1': {}
'@typescript/native-preview@7.0.0-dev.20260503.1': '@typescript/native-preview@7.0.0-dev.20260429.1':
optionalDependencies: optionalDependencies:
'@typescript/native-preview-linux-x64': 7.0.0-dev.20260503.1 '@typescript/native-preview-linux-x64': 7.0.0-dev.20260429.1
? '@vitejs/plugin-legacy@8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))' ? '@vitejs/plugin-legacy@8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))'
: dependencies: : dependencies:
@ -4729,35 +4722,35 @@ snapshots:
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
eslint-compat-utils@0.6.5(eslint@10.3.0(jiti@2.6.1)): eslint-compat-utils@0.6.5(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
semver: 7.7.4 semver: 7.7.4
eslint-plugin-astro@1.7.0(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-astro@1.7.0(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1))
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
astro-eslint-parser: 1.4.0 astro-eslint-parser: 1.4.0
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
eslint-compat-utils: 0.6.5(eslint@10.3.0(jiti@2.6.1)) eslint-compat-utils: 0.6.5(eslint@10.2.1(jiti@2.6.1))
globals: 16.5.0 globals: 16.5.0
postcss: 8.5.12 postcss: 8.5.12
postcss-selector-parser: 7.1.1 postcss-selector-parser: 7.1.1
eslint-plugin-functional@9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3): eslint-plugin-functional@9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
deepmerge-ts: 7.1.5 deepmerge-ts: 7.1.5
escape-string-regexp: 5.0.0 escape-string-regexp: 5.0.0
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
is-immutable-type: 5.0.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) is-immutable-type: 5.0.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
ts-declaration-location: 1.0.7(typescript@6.0.3) ts-declaration-location: 1.0.7(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
eslint-plugin-jsdoc@62.9.0(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-jsdoc@62.9.0(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
'@es-joy/jsdoccomment': 0.86.0 '@es-joy/jsdoccomment': 0.86.0
'@es-joy/resolve.exports': 1.2.0 '@es-joy/resolve.exports': 1.2.0
@ -4765,7 +4758,7 @@ snapshots:
comment-parser: 1.4.6 comment-parser: 1.4.6
debug: 4.4.3 debug: 4.4.3
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
espree: 11.2.0 espree: 11.2.0
esquery: 1.7.0 esquery: 1.7.0
html-entities: 2.6.0 html-entities: 2.6.0
@ -4775,7 +4768,7 @@ snapshots:
spdx-expression-parse: 4.0.0 spdx-expression-parse: 4.0.0
to-valid-identifier: 1.0.0 to-valid-identifier: 1.0.0
eslint-plugin-jsx-a11y@6.10.2(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-jsx-a11y@6.10.2(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
aria-query: 5.3.2 aria-query: 5.3.2
array-includes: 3.1.9 array-includes: 3.1.9
@ -4785,7 +4778,7 @@ snapshots:
axobject-query: 4.1.0 axobject-query: 4.1.0
damerau-levenshtein: 1.0.8 damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2 emoji-regex: 9.2.2
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
hasown: 2.0.3 hasown: 2.0.3
jsx-ast-utils: 3.3.5 jsx-ast-utils: 3.3.5
language-tags: 1.0.9 language-tags: 1.0.9
@ -4799,18 +4792,18 @@ snapshots:
jsonc-parser: 3.3.1 jsonc-parser: 3.3.1
oxlint: 1.62.0(oxlint-tsgolint@0.22.1) oxlint: 1.62.0(oxlint-tsgolint@0.22.1)
eslint-plugin-perfectionist@5.9.0(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-perfectionist@5.9.0(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
'@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
natural-orderby: 5.0.0 natural-orderby: 5.0.0
eslint-plugin-sonarjs@4.0.3(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-sonarjs@4.0.3(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
builtin-modules: 3.3.0 builtin-modules: 3.3.0
bytes: 3.1.2 bytes: 3.1.2
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
functional-red-black-tree: 1.0.1 functional-red-black-tree: 1.0.1
globals: 17.5.0 globals: 17.5.0
jsx-ast-utils-x: 0.1.0 jsx-ast-utils-x: 0.1.0
@ -4821,15 +4814,15 @@ snapshots:
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
eslint-plugin-unicorn@64.0.0(eslint@10.3.0(jiti@2.6.1)): eslint-plugin-unicorn@64.0.0(eslint@10.2.1(jiti@2.6.1)):
dependencies: dependencies:
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1))
change-case: 5.4.4 change-case: 5.4.4
ci-info: 4.4.0 ci-info: 4.4.0
clean-regexp: 1.0.0 clean-regexp: 1.0.0
core-js-compat: 3.49.0 core-js-compat: 3.49.0
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
find-up-simple: 1.0.1 find-up-simple: 1.0.1
globals: 17.5.0 globals: 17.5.0
indent-string: 5.0.0 indent-string: 5.0.0
@ -4859,9 +4852,9 @@ snapshots:
eslint-visitor-keys@5.0.1: {} eslint-visitor-keys@5.0.1: {}
eslint@10.3.0(jiti@2.6.1): eslint@10.2.1(jiti@2.6.1):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1))
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.23.5 '@eslint/config-array': 0.23.5
'@eslint/config-helpers': 0.5.5 '@eslint/config-helpers': 0.5.5
@ -5069,8 +5062,6 @@ snapshots:
globals@17.5.0: {} globals@17.5.0: {}
globals@17.6.0: {}
globalthis@1.0.4: globalthis@1.0.4:
dependencies: dependencies:
define-properties: 1.2.1 define-properties: 1.2.1
@ -5229,10 +5220,10 @@ snapshots:
dependencies: dependencies:
is-extglob: 2.1.1 is-extglob: 2.1.1
is-immutable-type@5.0.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3): is-immutable-type@5.0.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/type-utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
ts-declaration-location: 1.0.7(typescript@6.0.3) ts-declaration-location: 1.0.7(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
@ -5340,7 +5331,7 @@ snapshots:
kind-of@6.0.3: {} kind-of@6.0.3: {}
knip@6.11.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
@ -6309,13 +6300,13 @@ snapshots:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10 reflect.getprototypeof: 1.0.10
typescript-eslint@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3): typescript-eslint@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/parser': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.3.0(jiti@2.6.1) eslint: 10.2.1(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
typescript@6.0.3: {} typescript@6.0.3: {}

View file

@ -1,17 +1,33 @@
import { defineConfig, devices, PlaywrightTestConfig } from "@playwright/test"; import { defineConfig, devices } from "@playwright/test";
const playwrightConfig: PlaywrightTestConfig = defineConfig({ export default defineConfig({
fullyParallel: true, fullyParallel: true,
projects: [ projects: [
{ {
name: "desktop-chromium-1920", name: "desktop-chromium-1920",
use: { ...devices["Desktop Chrome"], viewport: { height: 1080, width: 1920 } }, use: { ...devices["Desktop Chrome"], viewport: { height: 1080, width: 1920 } },
}, },
// {
// name: "desktop-chromium-1536",
// use: { ...devices["Desktop Chrome"], viewport: { width: 1536, height: 864 } },
// },
// {
// name: "desktop-chromium-1366",
// use: { ...devices["Desktop Chrome"], viewport: { width: 1366, height: 768 } },
// },
{ {
name: "desktop-firefox-1920", name: "desktop-firefox-1920",
use: { ...devices["Desktop Firefox"], viewport: { height: 1080, width: 1920 } }, use: { ...devices["Desktop Firefox"], viewport: { height: 1080, width: 1920 } },
}, },
// { // {
// name: "desktop-firefox-1536",
// use: { ...devices["Desktop Firefox"], viewport: { width: 1536, height: 864 } },
// },
// {
// name: "desktop-firefox-1366",
// use: { ...devices["Desktop Firefox"], viewport: { width: 1366, height: 768 } },
// },
// {
// name: "tablet-chromium-portrait", // name: "tablet-chromium-portrait",
// use: { ...devices["Galaxy Tab S9"] }, // use: { ...devices["Galaxy Tab S9"] },
// }, // },
@ -33,6 +49,7 @@ const playwrightConfig: PlaywrightTestConfig = defineConfig({
testDir: "../tests", testDir: "../tests",
timeout: 10_000, timeout: 10_000,
use: { use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "https://haikuatelier.gcch.local", baseURL: "https://haikuatelier.gcch.local",
clientCertificates: [ clientCertificates: [
{ {
@ -44,7 +61,5 @@ const playwrightConfig: PlaywrightTestConfig = defineConfig({
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
trace: "retry-with-trace", trace: "retry-with-trace",
}, },
workers: "50%", workers: "100%",
}); });
export default playwrightConfig;

View file

@ -1,10 +1,19 @@
{ {
"$schema": "https://getcomposer.org/schema.json", "authors": [
"authors": [], {
"email": "scott.walkinshaw@gmail.com",
"homepage": "https://github.com/swalkinshaw",
"name": "Scott Walkinshaw"
},
{
"email": "ben@benword.com",
"homepage": "https://github.com/retlehs",
"name": "Ben Word"
}
],
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/", "HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/"
"WooCommerce\\": "web/app/plugins/woocommerce"
} }
}, },
"config": { "config": {
@ -15,12 +24,11 @@
"phpstan/extension-installer": true, "phpstan/extension-installer": true,
"roots/wordpress-core-installer": true "roots/wordpress-core-installer": true
}, },
"classmap-authoritative": true,
"optimize-autoloader": true, "optimize-autoloader": true,
"preferred-install": "dist", "preferred-install": "dist",
"sort-packages": true "sort-packages": true
}, },
"description": "", "description": "WordPress boilerplate with Composer, easier configuration, and an improved folder structure",
"extra": { "extra": {
"installer-paths": { "installer-paths": {
"web/app/mu-plugins/{$name}/": [ "web/app/mu-plugins/{$name}/": [
@ -38,8 +46,18 @@
}, },
"wordpress-install-dir": "web/wp" "wordpress-install-dir": "web/wp"
}, },
"minimum-stability": "stable", "homepage": "https://roots.io/bedrock/",
"name": "gcch/haiku-atelier", "keywords": [
"bedrock",
"composer",
"roots",
"wordpress",
"wp",
"wp-config"
],
"license": "MIT",
"minimum-stability": "dev",
"name": "roots/bedrock",
"prefer-stable": true, "prefer-stable": true,
"repositories": [ "repositories": [
{ {
@ -93,5 +111,9 @@
"szepeviktor/phpstan-wordpress": "2.x-dev", "szepeviktor/phpstan-wordpress": "2.x-dev",
"vincentlanglet/twig-cs-fixer": "^3.14" "vincentlanglet/twig-cs-fixer": "^3.14"
}, },
"support": {
"forum": "https://discourse.roots.io/category/bedrock",
"issues": "https://github.com/roots/bedrock/issues"
},
"type": "project" "type": "project"
} }

79
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b81b62efbedadf3c57fb437e86ef6766", "content-hash": "3144138aa029c01a516e9b6ce664271b",
"packages": [ "packages": [
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@ -3176,16 +3176,16 @@
}, },
{ {
"name": "symfony/uid", "name": "symfony/uid",
"version": "v8.0.9", "version": "v8.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/uid.git", "url": "https://github.com/symfony/uid.git",
"reference": "4d9d6510bbe88ebb4608b7200d18606cdf80825c" "reference": "f63fa6096a24147283bce4d29327d285326438e0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/uid/zipball/4d9d6510bbe88ebb4608b7200d18606cdf80825c", "url": "https://api.github.com/repos/symfony/uid/zipball/f63fa6096a24147283bce4d29327d285326438e0",
"reference": "4d9d6510bbe88ebb4608b7200d18606cdf80825c", "reference": "f63fa6096a24147283bce4d29327d285326438e0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3230,7 +3230,7 @@
"uuid" "uuid"
], ],
"support": { "support": {
"source": "https://github.com/symfony/uid/tree/v8.0.9" "source": "https://github.com/symfony/uid/tree/v8.0.8"
}, },
"funding": [ "funding": [
{ {
@ -3250,7 +3250,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-30T16:10:06+00:00" "time": "2026-03-30T15:14:47+00:00"
}, },
{ {
"name": "timber/timber", "name": "timber/timber",
@ -4532,11 +4532,11 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "2.1.54", "version": "2.1.53",
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8be50c3992107dc837b17da4d140fbbdf9a5c5bd", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ef67586798c003274797b288a68b221e4270dca7",
"reference": "8be50c3992107dc837b17da4d140fbbdf9a5c5bd", "reference": "ef67586798c003274797b288a68b221e4270dca7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4581,7 +4581,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2026-04-29T13:31:09+00:00" "time": "2026-04-28T16:09:00+00:00"
}, },
{ {
"name": "psr/event-dispatcher", "name": "psr/event-dispatcher",
@ -5215,18 +5215,18 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git", "url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a" "reference": "87a281378fdad8f5926efe259f6ca72e7a395e68"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/2221f6ef09e87784e78e188aadd8f7e3a50e679a", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/87a281378fdad8f5926efe259f6ca72e7a395e68",
"reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a", "reference": "87a281378fdad8f5926efe259f6ca72e7a395e68",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
"3f/pygmentize": "<1.2", "3f/pygmentize": "<1.2",
"adaptcms/adaptcms": "<=1.3", "adaptcms/adaptcms": "<=1.3",
"admidio/admidio": "<=5.0.8", "admidio/admidio": "<5.0.8",
"adodb/adodb-php": "<=5.22.9", "adodb/adodb-php": "<=5.22.9",
"aheinze/cockpit": "<2.2", "aheinze/cockpit": "<2.2",
"aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2",
@ -5335,7 +5335,7 @@
"cesnet/simplesamlphp-module-proxystatistics": "<3.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1",
"chriskacerguis/codeigniter-restserver": "<=2.7.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1",
"chrome-php/chrome": "<1.14", "chrome-php/chrome": "<1.14",
"ci4-cms-erp/ci4ms": "<=0.31.6", "ci4-cms-erp/ci4ms": "<0.31.5",
"civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3",
"ckeditor/ckeditor": "<4.25", "ckeditor/ckeditor": "<4.25",
"clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3",
@ -5540,7 +5540,7 @@
"geshi/geshi": "<=1.0.9.1", "geshi/geshi": "<=1.0.9.1",
"getformwork/formwork": "<=2.3.3", "getformwork/formwork": "<=2.3.3",
"getgrav/grav": "<1.11.0.0-beta1", "getgrav/grav": "<1.11.0.0-beta1",
"getkirby/cms": "<4.9|>=5,<5.4", "getkirby/cms": "<5.4",
"getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1",
"getkirby/panel": "<2.5.14", "getkirby/panel": "<2.5.14",
"getkirby/starterkit": "<=3.7.0.2", "getkirby/starterkit": "<=3.7.0.2",
@ -5600,7 +5600,7 @@
"intelliants/subrion": "<4.2.2", "intelliants/subrion": "<4.2.2",
"inter-mediator/inter-mediator": "==5.5", "inter-mediator/inter-mediator": "==5.5",
"invoiceninja/invoiceninja": "<5.13.4", "invoiceninja/invoiceninja": "<5.13.4",
"ipl/web": "<=0.13", "ipl/web": "<0.10.1",
"islandora/crayfish": "<4.1", "islandora/crayfish": "<4.1",
"islandora/islandora": ">=2,<2.4.1", "islandora/islandora": ">=2,<2.4.1",
"ivankristianto/phpwhois": "<=4.3", "ivankristianto/phpwhois": "<=4.3",
@ -5870,7 +5870,7 @@
"prestashop/gamification": "<2.3.2", "prestashop/gamification": "<2.3.2",
"prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1", "prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1",
"prestashop/productcomments": "<5.0.2", "prestashop/productcomments": "<5.0.2",
"prestashop/ps_checkout": "<5.3", "prestashop/ps_checkout": "<4.4.1|>=5,<5.0.5",
"prestashop/ps_contactinfo": "<=3.3.2", "prestashop/ps_contactinfo": "<=3.3.2",
"prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_emailsubscription": "<2.6.1",
"prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_facetedsearch": "<3.4.1",
@ -5907,7 +5907,6 @@
"rhukster/dom-sanitizer": "<1.0.10", "rhukster/dom-sanitizer": "<1.0.10",
"rmccue/requests": ">=1.6,<1.8", "rmccue/requests": ">=1.6,<1.8",
"roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9", "roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9",
"roadiz/openid": "<2.3.43|>=2.5,<2.5.45|>=2.6,<2.6.31|>=2.7,<2.7.18",
"robrichards/xmlseclibs": "<3.1.5", "robrichards/xmlseclibs": "<3.1.5",
"roots/soil": "<4.1", "roots/soil": "<4.1",
"roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11|>=1.7.0.0-beta,<1.7.0.0-RC5-dev", "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11|>=1.7.0.0-beta,<1.7.0.0-RC5-dev",
@ -6265,7 +6264,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-30T21:24:12+00:00" "time": "2026-04-28T23:21:55+00:00"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
@ -6348,16 +6347,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v8.0.9", "version": "v8.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "7113778e2e91f4709cb3194a75dfa9c0d028d94d" "reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/7113778e2e91f4709cb3194a75dfa9c0d028d94d", "url": "https://api.github.com/repos/symfony/console/zipball/5b66d385dc58f69652e56f78a4184615e3f2b7f7",
"reference": "7113778e2e91f4709cb3194a75dfa9c0d028d94d", "reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6414,7 +6413,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v8.0.9" "source": "https://github.com/symfony/console/tree/v8.0.8"
}, },
"funding": [ "funding": [
{ {
@ -6434,20 +6433,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-29T15:02:55+00:00" "time": "2026-03-30T15:14:47+00:00"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v8.0.9", "version": "v8.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "0c3c1a17604c4dbbec4b93fe162c538482096e1f" "reference": "f662acc6ab22a3d6d716dcb44c381c6002940df6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0c3c1a17604c4dbbec4b93fe162c538482096e1f", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f662acc6ab22a3d6d716dcb44c381c6002940df6",
"reference": "0c3c1a17604c4dbbec4b93fe162c538482096e1f", "reference": "f662acc6ab22a3d6d716dcb44c381c6002940df6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6499,7 +6498,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v8.0.9" "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.8"
}, },
"funding": [ "funding": [
{ {
@ -6519,7 +6518,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-18T13:51:42+00:00" "time": "2026-03-30T15:14:47+00:00"
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
@ -6599,16 +6598,16 @@
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v8.0.9", "version": "v8.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40" "reference": "66b769ae743ce2d13e435528fbef4af03d623e5a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40", "url": "https://api.github.com/repos/symfony/filesystem/zipball/66b769ae743ce2d13e435528fbef4af03d623e5a",
"reference": "d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40", "reference": "66b769ae743ce2d13e435528fbef4af03d623e5a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6645,7 +6644,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v8.0.9" "source": "https://github.com/symfony/filesystem/tree/v8.0.8"
}, },
"funding": [ "funding": [
{ {
@ -6665,7 +6664,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-18T13:51:42+00:00" "time": "2026-03-30T15:14:47+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
@ -7566,7 +7565,7 @@
} }
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "dev",
"stability-flags": { "stability-flags": {
"roave/security-advisories": 20, "roave/security-advisories": 20,
"szepeviktor/phpstan-wordpress": 20 "szepeviktor/phpstan-wordpress": 20

View file

@ -170,6 +170,3 @@ pull-images:
export_production_db: export_production_db:
fish "scripts/déclenche-sauvegarde-bdd-production.fish" fish "scripts/déclenche-sauvegarde-bdd-production.fish"
ui_tests:
aube x playwright test --config cfg/playwright.config.ts --ui

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,6 @@ threads = 0
no-else-clause = { enabled = false } no-else-clause = { enabled = false }
[analyzer] [analyzer]
allow-implicit-pipe-callable-types = false
allow-possibly-undefined-array-keys = false allow-possibly-undefined-array-keys = false
allow-side-effects-in-conditions = true allow-side-effects-in-conditions = true
analyze-dead-code = true analyze-dead-code = true

View file

@ -1,2 +0,0 @@
[tools]
"github:AJenbo/phpantom_lsp" = "latest"

View file

@ -13,7 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@mobily/ts-belt": "v4.0.0-rc.5", "@mobily/ts-belt": "v4.0.0-rc.5",
"@sentry/browser": "^10.51.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", "html-template-tag": "^5.0.0",
@ -24,28 +24,28 @@
}, },
"devDependencies": { "devDependencies": {
"@effect/language-service": "^0.85.1", "@effect/language-service": "^0.85.1",
"@effect/tsgo": "^0.5.2", "@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",
"@playwright/test": "^1.59.1", "@playwright/test": "^1.59.1",
"@sentry/core": "^10.51.0", "@sentry/core": "^10.50.0",
"@types/bun": "^1.3.13", "@types/bun": "^1.3.13",
"@types/node": "^25.6.0", "@types/node": "^25.6.0",
"@typescript/native-preview": "7.0.0-dev.20260503.1", "@typescript/native-preview": "7.0.0-dev.20260429.1",
"@vitejs/plugin-legacy": "^8.0.1", "@vitejs/plugin-legacy": "^8.0.1",
"better-typescript-lib": "^2.12.0", "better-typescript-lib": "^2.12.0",
"browserslist": "^4.28.2", "browserslist": "^4.28.2",
"caniuse-lite": "^1.0.30001791", "caniuse-lite": "^1.0.30001791",
"eslint": "^10.3.0", "eslint": "^10.2.1",
"eslint-plugin-functional": "^9.0.4", "eslint-plugin-functional": "^9.0.4",
"eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-oxlint": "^1.62.0", "eslint-plugin-oxlint": "^1.62.0",
"eslint-plugin-perfectionist": "^5.9.0", "eslint-plugin-perfectionist": "^5.9.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
"globals": "^17.6", "globals": "^17.5.0",
"jiti": "^2.6.1", "jiti": "^2.6.1",
"knip": "^6.11.0", "knip": "^6.8.0",
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"lightningcss-cli": "^1.32.0", "lightningcss-cli": "^1.32.0",
"oxlint": "^1.62.0", "oxlint": "^1.62.0",

View file

@ -236,21 +236,6 @@
"default": 1610612736, "default": 1610612736,
"description": "Ensure that PHP has a memory_limit of at least this amount in bytes" "description": "Ensure that PHP has a memory_limit of at least this amount in bytes"
}, },
"core.project_config_candidates": {
"default": [],
"description": "(internal) list of potential project-level configuration files"
},
"core.trust": {
"default": {
"path": null,
"trust": []
},
"description": "(internal) map of trusted project directories"
},
"core.trusted": {
"default": false,
"description": "(internal) if the configuration is trusted"
},
"file_path_resolver.app_name": { "file_path_resolver.app_name": {
"default": "phpactor", "default": "phpactor",
"description": null "description": null
@ -293,8 +278,7 @@
"default": [ "default": [
"/vendor/**/tests/**/*", "/vendor/**/tests/**/*",
"/vendor/**/Tests/**/*", "/vendor/**/Tests/**/*",
"/vendor/composer/**/*", "/vendor/composer/**/*"
"/vendor/rector/rector/stubs-rector"
], ],
"description": "Glob patterns to exclude while indexing", "description": "Glob patterns to exclude while indexing",
"type": [ "type": [
@ -332,13 +316,6 @@
"string" "string"
] ]
}, },
"indexer.max_filesize_to_index": {
"default": 1000000,
"description": "Files larger than this will not be indexed. (Size in bytes)",
"type": [
"integer"
]
},
"indexer.poll_time": { "indexer.poll_time": {
"default": 5000, "default": 5000,
"description": "For polling indexers only: the time, in milliseconds, between polls (e.g. filesystem scans)", "description": "For polling indexers only: the time, in milliseconds, between polls (e.g. filesystem scans)",
@ -360,13 +337,6 @@
"boolean" "boolean"
] ]
}, },
"indexer.search_include_patterns": {
"default": [],
"description": "When searching the index exclude records whose fully qualified names match any of these regex patterns (use to exclude suggestions from search results). Namespace separators must be escaped as `\\\\\\\\` for example `^Foo\\\\\\\\` to include all namespaces whose first segment is `Foo`",
"type": [
"object"
]
},
"indexer.stub_paths": { "indexer.stub_paths": {
"default": [], "default": [],
"description": "Paths to external folders to index. They will be indexed only once, if you want to take any changes into account you will have to reindex your project manually.", "description": "Paths to external folders to index. They will be indexed only once, if you want to take any changes into account you will have to reindex your project manually.",
@ -392,10 +362,6 @@
"default": [], "default": [],
"description": "List of paths to exclude from diagnostics, e.g. `vendor/**/*`" "description": "List of paths to exclude from diagnostics, e.g. `vendor/**/*`"
}, },
"language_server.diagnostic_ignore_codes": {
"default": [],
"description": "Ignore diagnostics that have the codes listed here, e.g. [\"fix_namespace_class_name\"]. The codes match those shown in the LSP client."
},
"language_server.diagnostic_outsource": { "language_server.diagnostic_outsource": {
"default": true, "default": true,
"description": "If applicable diagnostics should be \"outsourced\" to a different process" "description": "If applicable diagnostics should be \"outsourced\" to a different process"
@ -423,10 +389,6 @@
"default": true, "default": true,
"description": "Perform diagnostics when the text document is updated" "description": "Perform diagnostics when the text document is updated"
}, },
"language_server.enable_trust_check": {
"default": true,
"description": "Check to see if project path is trusted before loading configurations from it"
},
"language_server.enable_workspace": { "language_server.enable_workspace": {
"default": true, "default": true,
"description": "If workspace management / text synchronization should be enabled (this isn't required for some language server implementations, e.g. static analyzers)" "description": "If workspace management / text synchronization should be enabled (this isn't required for some language server implementations, e.g. static analyzers)"
@ -488,17 +450,6 @@
"boolean" "boolean"
] ]
}, },
"language_server_highlight.enabled": {
"default": true,
"description": "Enable or disable the highlighter (can be expensive on large documents)"
},
"language_server_indexer.optimiser_timeout": {
"default": 3600,
"description": "Optimise the index every N seconds",
"type": [
"integer"
]
},
"language_server_indexer.reindex_timeout": { "language_server_indexer.reindex_timeout": {
"default": 300, "default": 300,
"description": "Unconditionally reindex modified files every N seconds" "description": "Unconditionally reindex modified files every N seconds"
@ -516,17 +467,15 @@
}, },
"language_server_php_cs_fixer.env": { "language_server_php_cs_fixer.env": {
"default": { "default": {
"PHP_CS_FIXER_IGNORE_ENV": true,
"XDEBUG_MODE": "off" "XDEBUG_MODE": "off"
}, },
"description": "Environment for PHP CS Fixer" "description": "Environment for PHP CS Fixer (e.g. to set PHP_CS_FIXER_IGNORE_ENV)"
}, },
"language_server_php_cs_fixer.show_diagnostics": { "language_server_php_cs_fixer.show_diagnostics": {
"default": true, "default": true,
"description": "Whether PHP CS Fixer diagnostics are shown" "description": "Whether PHP CS Fixer diagnostics are shown"
}, },
"language_server_php_cs_fixer.version": {
"description": "Arbitrary version (if not provided, phpactor tries to detect it - only to run it on unsupported PHP versions)"
},
"language_server_phpstan.bin": { "language_server_phpstan.bin": {
"default": "%project_root%/vendor/bin/phpstan", "default": "%project_root%/vendor/bin/phpstan",
"description": "Path to the PHPStan executable" "description": "Path to the PHPStan executable"
@ -534,24 +483,12 @@
"language_server_phpstan.config": { "language_server_phpstan.config": {
"description": "Override the PHPStan configuration file" "description": "Override the PHPStan configuration file"
}, },
"language_server_phpstan.editor_mode": {
"default": false,
"description": "DEPRECATED. Editor mode of Phpstan is used automatically when it's supported."
},
"language_server_phpstan.level": { "language_server_phpstan.level": {
"description": "Override the PHPStan level" "description": "Override the PHPStan level"
}, },
"language_server_phpstan.mem_limit": { "language_server_phpstan.mem_limit": {
"description": "Override the PHPStan memory limit" "description": "Override the PHPStan memory limit"
}, },
"language_server_phpstan.severity": {
"default": 1,
"description": "Severity at which PHPStan diagnostics should be reported. Ranges from 1 (error) to 4 (hint)."
},
"language_server_phpstan.tmp_file_disabled": {
"default": false,
"description": "Disable the use of temporary files when. This prevents as-you-type diagnostics, but ensures paths in phpstan config are respected. See https://github.com/phpactor/phpactor/issues/2763"
},
"language_server_psalm.bin": { "language_server_psalm.bin": {
"default": "%project_root%/vendor/bin/psalm", "default": "%project_root%/vendor/bin/psalm",
"description": "Path to psalm if different from vendor/bin/psalm", "description": "Path to psalm if different from vendor/bin/psalm",
@ -559,13 +496,6 @@
"string" "string"
] ]
}, },
"language_server_psalm.config": {
"default": "",
"description": "Path to psalm config. Like %project_root%/psalm.xml",
"type": [
"string"
]
},
"language_server_psalm.error_level": { "language_server_psalm.error_level": {
"description": "Override level at which Psalm should report errors (lower => more errors)" "description": "Override level at which Psalm should report errors (lower => more errors)"
}, },
@ -597,10 +527,6 @@
"boolean" "boolean"
] ]
}, },
"language_server_reference_finder.soft_timeout": {
"default": 10,
"description": "Interupt and ask for confirmation to continue after this timeout (in seconds)"
},
"language_server_reference_reference_finder.reference_timeout": { "language_server_reference_reference_finder.reference_timeout": {
"default": 60, "default": 60,
"description": "Stop searching for references after this time (in seconds) has expired" "description": "Stop searching for references after this time (in seconds) has expired"
@ -732,10 +658,6 @@
"default": "%project_root%/var/cache/dev/App_KernelDevDebugContainer.xml", "default": "%project_root%/var/cache/dev/App_KernelDevDebugContainer.xml",
"description": "Path to the Symfony container XML dump file" "description": "Path to the Symfony container XML dump file"
}, },
"worse_reflection.additive_stubs": {
"default": [],
"description": "Additive stubs files relative to the project root. These stubs augment existing defininitions."
},
"worse_reflection.cache_dir": { "worse_reflection.cache_dir": {
"default": "%cache%/worse-reflection", "default": "%cache%/worse-reflection",
"description": "Cache directory for stubs" "description": "Cache directory for stubs"

View file

@ -16,7 +16,7 @@ $wp_postmeta = "{$wpdb->prefix}postmeta";
try { try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Error Handling // Error Handling
$sql = "UPDATE {$wp_postmeta} SET meta_value = REPLACE(meta_value,'-scaled.jpg','.jpg') WHERE meta_key='_wp_attached_file' AND meta_value LIKE '%-scaled.jpg%'"; $sql = "UPDATE {$wp_postmeta} SET meta_value = REPLACE(meta_value,'-scaled.jpg','.jpg') WHERE meta_key='_wp_attached_file' AND meta_value LIKE '%-scaled.jpg%'";
$result = $pdo->exec($sql); $result = $pdo->exec($sql);
print_r($result); print_r($result);
} catch (PDOException $e) { } catch (PDOException $e) {
@ -29,12 +29,12 @@ $image_metas = [];
try { try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Error Handling // Error Handling
$sql = "SELECT * FROM {$wp_postmeta} WHERE meta_value LIKE '%-scaled.jpg%' AND meta_key='_wp_attachment_metadata'"; $sql = "SELECT * FROM {$wp_postmeta} WHERE meta_value LIKE '%-scaled.jpg%' AND meta_key='_wp_attachment_metadata'";
$statement = $pdo->query($sql); $statement = $pdo->query($sql);
$image_metas = $statement->fetchAll(); $image_metas = $statement->fetchAll();
foreach ($image_metas as $meta) { foreach ($image_metas as $meta) {
$meta_value = unserialize($meta['meta_value']); $meta_value = unserialize($meta['meta_value']);
$file = $meta_value['file']; $file = $meta_value['file'];
$meta_value['file'] = str_replace('-scaled.jpg', '.jpg', $file); $meta_value['file'] = str_replace('-scaled.jpg', '.jpg', $file);
update_post_meta($meta['post_id'], $meta['meta_key'], $meta_value); update_post_meta($meta['post_id'], $meta['meta_key'], $meta_value);
$result = get_post_meta($meta['post_id'], $meta['meta_key']); $result = get_post_meta($meta['post_id'], $meta['meta_key']);

View file

@ -1,4 +1,3 @@
/** @effect-diagnostics asyncFunction:skip-file */
import type { APIRequestContext, Locator, Page, Response } from "@playwright/test"; import type { APIRequestContext, Locator, Page, Response } from "@playwright/test";
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import type { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products"; import type { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products";
@ -11,7 +10,7 @@ test("can scroll to the end of the grid", async ({ page }): Promise<void> => {
await scrollToGridsEnd(page); await scrollToGridsEnd(page);
}); });
test("can access all Products' pages", async ({ page, request }): Promise<void> => { test.skip("can access all Products' pages", async ({ page, request }): Promise<void> => {
await page["goto"]("https://haikuatelier.gcch.local/shop/"); await page["goto"]("https://haikuatelier.gcch.local/shop/");
const links = await getAllProductsLinks(page, request); const links = await getAllProductsLinks(page, request);

View file

@ -14,7 +14,7 @@ use Timber\Timber;
use function add_action; use function add_action;
$context = Timber::context(); $context = Timber::context();
$templates = ['404.twig']; $templates = ['404.twig'];
/** /**
@ -25,7 +25,7 @@ $templates = ['404.twig'];
function load_page_resources(): void { function load_page_resources(): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-a-propos', handle: 'haiku-atelier-2024-styles-page-a-propos',
path : '/assets/css/pages/page-modele-simple.css', path: '/assets/css/pages/page-modele-simple.css',
); );
} }

View file

@ -22,13 +22,13 @@ use function wc_get_products;
use function wp_create_nonce; use function wp_create_nonce;
use function wp_json_encode; use function wp_json_encode;
$context = Timber::context(); $context = Timber::context();
$templates = ['boutique.twig']; $templates = ['boutique.twig'];
/** @var list<WC_Product> $wc_products Les informations brutes des Produits. */ /** @var list<WC_Product> $wc_products Les informations brutes des Produits. */
$wc_products = wc_get_products(['limit' => 12, 'order' => 'DESC', 'orderby' => 'date', 'status' => 'publish']); $wc_products = wc_get_products(['limit' => 12, 'order' => 'DESC', 'orderby' => 'date', 'status' => 'publish']);
$products = array_map(callback: Product::from_wc_product(...), array: $wc_products); $products = array_map(callback: Product::from_wc_product(...), array: $wc_products);
$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.
@ -40,14 +40,14 @@ $context['page_states'] = $page_states;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-boutique', handle: 'haiku-atelier-2024-styles-page-boutique',
path : '/assets/css/pages/page-boutique.css', path: '/assets/css/pages/page-boutique.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-boutique', id: 'haiku-atelier-2024-scripts-page-boutique',
path: '/assets/js/scripts-page-boutique.js', path: '/assets/js/scripts-page-boutique.js',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-menu-categories', id: 'haiku-atelier-2024-scripts-menu-categories',
path: '/assets/js/scripts-menu-categories.js', path: '/assets/js/scripts-menu-categories.js',
); );
}); });

View file

@ -13,17 +13,17 @@ use Timber\Timber;
use function add_action; use function add_action;
$context = Timber::context(); $context = Timber::context();
$templates = ['accueil.twig']; $templates = ['accueil.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-accueil', id: 'haiku-atelier-2024-scripts-page-accueil',
path: '/assets/js/scripts-page-accueil.js', path: '/assets/js/scripts-page-accueil.js',
); );
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-accueil', handle: 'haiku-atelier-2024-styles-page-accueil',
path : '/assets/css/pages/page-accueil.css', path: '/assets/css/pages/page-accueil.css',
); );
}); });

View file

@ -24,21 +24,21 @@ Timber::$dirname = ['views'];
// Charge les Scripts du thème (report d'erreurs) // Charge les Scripts du thème (report d'erreurs)
function load_scripts(): void { function load_scripts(): void {
wp_enqueue_script_module( wp_enqueue_script_module(
id : 'haiku-atelier-2024-bouton-panier', id: 'haiku-atelier-2024-bouton-panier',
deps : [], deps: [],
src : get_template_directory_uri() . '/assets/js/scripts-bouton-panier.js', src: get_template_directory_uri() . '/assets/js/scripts-bouton-panier.js',
version: filemtime(get_template_directory() . '/assets/js/scripts-bouton-panier.js'), version: filemtime(get_template_directory() . '/assets/js/scripts-bouton-panier.js'),
); );
wp_enqueue_script_module( wp_enqueue_script_module(
id : 'haiku-atelier-2024-menu-mobile', id: 'haiku-atelier-2024-menu-mobile',
deps : [], deps: [],
src : get_template_directory_uri() . '/assets/js/scripts-menu-mobile.js', src: get_template_directory_uri() . '/assets/js/scripts-menu-mobile.js',
version: filemtime(get_template_directory() . '/assets/js/scripts-menu-mobile.js'), version: filemtime(get_template_directory() . '/assets/js/scripts-menu-mobile.js'),
); );
wp_enqueue_script_module( wp_enqueue_script_module(
id : 'haiku-atelier-2024-bouton-retour-sommet', id: 'haiku-atelier-2024-bouton-retour-sommet',
deps : [], deps: [],
src : get_template_directory_uri() . '/assets/js/scripts-bouton-retour-sommet.js', src: get_template_directory_uri() . '/assets/js/scripts-bouton-retour-sommet.js',
version: filemtime(get_template_directory() . '/assets/js/scripts-bouton-retour-sommet.js'), version: filemtime(get_template_directory() . '/assets/js/scripts-bouton-retour-sommet.js'),
); );
} }
@ -49,10 +49,10 @@ add_action('wp_enqueue_scripts', 'load_scripts');
function charge_styles_haiku_atelier_2024(): void { function charge_styles_haiku_atelier_2024(): void {
wp_enqueue_style( wp_enqueue_style(
handle: 'haiku-atelier-2024-styles', handle: 'haiku-atelier-2024-styles',
src : get_template_directory_uri() . '/assets/css/main.css', src: get_template_directory_uri() . '/assets/css/main.css',
deps : [], deps: [],
ver : filemtime(get_template_directory() . '/assets/css/main.css'), ver: filemtime(get_template_directory() . '/assets/css/main.css'),
media : 'all', media: 'all',
); );
} }
@ -67,70 +67,70 @@ new StarterSite();
function enregistre_personnalisations_theme(mixed $wp_customize): void { function enregistre_personnalisations_theme(mixed $wp_customize): void {
// Section « Réseaux sociaux » // Section « Réseaux sociaux »
$wp_customize->add_section('liens_reseaux_sociaux', [ $wp_customize->add_section('liens_reseaux_sociaux', [
'title' => __('Liens des réseaux sociaux'), 'title' => __('Liens des réseaux sociaux'),
'description' => __("Liens des réseaux sociaux s'affichant dans le pied de page."), 'description' => __("Liens des réseaux sociaux s'affichant dans le pied de page."),
]); ]);
// Instagram // Instagram
$wp_customize->add_setting('lien_instagram', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']); $wp_customize->add_setting('lien_instagram', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']);
$wp_customize->add_control('lien_instagram', [ $wp_customize->add_control('lien_instagram', [
'type' => 'url', 'type' => 'url',
'section' => 'liens_reseaux_sociaux', 'section' => 'liens_reseaux_sociaux',
'label' => __('Profil Instagram'), 'label' => __('Profil Instagram'),
]); ]);
// Facebook // Facebook
$wp_customize->add_setting('lien_facebook', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']); $wp_customize->add_setting('lien_facebook', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']);
$wp_customize->add_control('lien_facebook', [ $wp_customize->add_control('lien_facebook', [
'type' => 'url', 'type' => 'url',
'section' => 'liens_reseaux_sociaux', 'section' => 'liens_reseaux_sociaux',
'label' => __('Profil Facebook'), 'label' => __('Profil Facebook'),
]); ]);
// Pinterest // Pinterest
$wp_customize->add_setting('lien_pinterest', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']); $wp_customize->add_setting('lien_pinterest', ['type' => 'theme_mod', 'capability' => 'edit_theme_options']);
$wp_customize->add_control('lien_pinterest', [ $wp_customize->add_control('lien_pinterest', [
'type' => 'url', 'type' => 'url',
'section' => 'liens_reseaux_sociaux', 'section' => 'liens_reseaux_sociaux',
'label' => __('Profil Pinterest'), 'label' => __('Profil Pinterest'),
]); ]);
// Section « Descriptions Produits » // Section « Descriptions Produits »
$wp_customize->add_section('descriptions_produits', [ $wp_customize->add_section('descriptions_produits', [
'title' => __('Textes des descriptions Produits'), 'title' => __('Textes des descriptions Produits'),
'description' => __('Textes des descriptions apparaissant sur les pages Produit.'), 'description' => __('Textes des descriptions apparaissant sur les pages Produit.'),
]); ]);
$wp_customize->add_setting('texte_conditions_livraison', [ $wp_customize->add_setting('texte_conditions_livraison', [
'capability' => 'edit_theme_options', 'capability' => 'edit_theme_options',
'default' => '', 'default' => '',
'sanitize_callback' => 'wp_kses_post', 'sanitize_callback' => 'wp_kses_post',
'transport' => 'postMessage', 'transport' => 'postMessage',
'type' => 'theme_mod', 'type' => 'theme_mod',
]); ]);
$wp_customize->add_control(new Controle_Personnalise_TinyMCE($wp_customize, 'texte_conditions_livraison', [ $wp_customize->add_control(new Controle_Personnalise_TinyMCE($wp_customize, 'texte_conditions_livraison', [
'label' => __('Conditions de livraison'), 'label' => __('Conditions de livraison'),
'description' => __('Descriptif des conditions de livraison.'), 'description' => __('Descriptif des conditions de livraison.'),
'section' => 'descriptions_produits', 'section' => 'descriptions_produits',
'input_attrs' => [ 'input_attrs' => [
'toolbar1' => 'bold italic bullist numlist alignleft aligncenter alignright link', 'toolbar1' => 'bold italic bullist numlist alignleft aligncenter alignright link',
'mediaButtons' => true, 'mediaButtons' => true,
], ],
])); ]));
$wp_customize->add_setting('texte_entretien_produit', [ $wp_customize->add_setting('texte_entretien_produit', [
'capability' => 'edit_theme_options', 'capability' => 'edit_theme_options',
'default' => '', 'default' => '',
'sanitize_callback' => 'wp_kses_post', 'sanitize_callback' => 'wp_kses_post',
'transport' => 'postMessage', 'transport' => 'postMessage',
'type' => 'theme_mod', 'type' => 'theme_mod',
]); ]);
$wp_customize->add_control(new Controle_Personnalise_TinyMCE($wp_customize, 'texte_entretien_produit', [ $wp_customize->add_control(new Controle_Personnalise_TinyMCE($wp_customize, 'texte_entretien_produit', [
'label' => __('Entretien du Produit'), 'label' => __('Entretien du Produit'),
'description' => __("Descriptif des bonnes pratiques pour l'entretien du Produit."), 'description' => __("Descriptif des bonnes pratiques pour l'entretien du Produit."),
'section' => 'descriptions_produits', 'section' => 'descriptions_produits',
'input_attrs' => [ 'input_attrs' => [
'toolbar1' => 'bold italic bullist numlist alignleft aligncenter alignright link', 'toolbar1' => 'bold italic bullist numlist alignleft aligncenter alignright link',
'mediaButtons' => true, 'mediaButtons' => true,
], ],
])); ]));

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
use Timber\Timber; use Timber\Timber;
$context = Timber::context(); $context = Timber::context();
$templates = ['base.twig']; $templates = ['base.twig'];
Timber::render(data: $context, filenames: $templates); Timber::render(data: $context, filenames: $templates);

View file

@ -17,7 +17,7 @@ use function get_template_directory;
use function getimagesize; use function getimagesize;
use function is_bool; use function is_bool;
$context = Timber::context(); $context = Timber::context();
$templates = ['a-propos.twig']; $templates = ['a-propos.twig'];
/** Les dimensions de l'image du storytelling. */ /** Les dimensions de l'image du storytelling. */
@ -32,10 +32,10 @@ $context['image_dimensions'] = $image_dimensions;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-a-propos', handle: 'haiku-atelier-2024-styles-page-a-propos',
path : '/assets/css/pages/page-a-propos.css', path: '/assets/css/pages/page-a-propos.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-a-propos', id: 'haiku-atelier-2024-scripts-page-a-propos',
path: '/assets/js/scripts-page-a-propos.js', path: '/assets/js/scripts-page-a-propos.js',
); );
}); });

View file

@ -20,7 +20,7 @@ use function collect;
use function Crell\fp\pipe; use function Crell\fp\pipe;
use function WC; use function WC;
$context = Timber::context(); $context = Timber::context();
$templates = ['panier.twig']; $templates = ['panier.twig'];
// Récupère les informations affichés des Produits du Panier // Récupère les informations affichés des Produits du Panier
@ -47,60 +47,60 @@ $shipping_subtotal = Cart::parse_cart_value($cart_totals['shipping_total'] ?? 0)
// TODO: Nettoyer ça. // TODO: Nettoyer ça.
foreach (WC()->cart->get_cart() as $cle_panier => $article_panier) { foreach (WC()->cart->get_cart() as $cle_panier => $article_panier) {
$cart[$cle_panier] = [ $cart[$cle_panier] = [
'attributs' => $article_panier['data']?->get_type() === 'variation' 'attributs' => $article_panier['data']?->get_type() === 'variation'
? Product::recupere_et_formate_attributs_produit($article_panier['data']?->get_attributes()) ? Product::recupere_et_formate_attributs_produit($article_panier['data']?->get_attributes())
: [], : [],
'cle' => $cle_panier, 'cle' => $cle_panier,
'id_produit' => $article_panier['product_id'], 'id_produit' => $article_panier['product_id'],
'id_variation' => $article_panier['variation_id'], 'id_variation' => $article_panier['variation_id'],
'image' => pipe($article_panier['data']?->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag( 'image' => pipe($article_panier['data']?->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag(
id : (string) $id, id: (string) $id,
lazy: true, lazy: true,
)), )),
'prix' => $article_panier['data']?->get_price(), 'prix' => $article_panier['data']?->get_price(),
'quantite' => $article_panier['quantity'], 'quantite' => $article_panier['quantity'],
'url' => $article_panier['data']?->get_permalink(), 'url' => $article_panier['data']?->get_permalink(),
'titre' => $article_panier['data']?->get_title(), 'titre' => $article_panier['data']?->get_title(),
]; ];
} }
// Récupère les Adresses de l'Utilisateur // Récupère les Adresses de l'Utilisateur
$email = WC()->customer->get_billing_email(); $email = WC()->customer->get_billing_email();
$adresse_livraison = WC()->customer->get_shipping(); $adresse_livraison = WC()->customer->get_shipping();
$adresse_facturation = WC()->customer->get_billing(); $adresse_facturation = WC()->customer->get_billing();
$adresse_renseignee = $adresse_livraison['city'] !== ''; $adresse_renseignee = $adresse_livraison['city'] !== '';
// TODO: Déplacer ça dans une fonction statique de Cart. // TODO: Déplacer ça dans une fonction statique de Cart.
$allowed_countries = collect(WC()->countries->get_countries())->only(Cart::get_allowed_countries())->toArray(); $allowed_countries = collect(WC()->countries->get_countries())->only(Cart::get_allowed_countries())->toArray();
// TODO: Nettoyer ça. // TODO: Nettoyer ça.
$methodes_livraison = collect(WC()->session->get('shipping_for_package_0')['rates']) $methodes_livraison = collect(WC()->session->get('shipping_for_package_0')['rates'])
->values() ->values()
->map(static fn(WC_Shipping_Rate $methode): array => [ ->map(static fn(WC_Shipping_Rate $methode): array => [
'id' => $methode->get_method_id(), 'id' => $methode->get_method_id(),
'prix' => Number::format((int) $methode->get_cost(), precision: 2), 'prix' => Number::format((int) $methode->get_cost(), precision: 2),
'selectionnee' => collect(WC()->session->get('chosen_shipping_methods'))->first() === $methode->get_id(), 'selectionnee' => collect(WC()->session->get('chosen_shipping_methods'))->first() === $methode->get_id(),
'titre' => $methode->get_label(), 'titre' => $methode->get_label(),
]); ]);
$context['email'] = $email; $context['email'] = $email;
$context['adresse_livraison'] = $adresse_livraison; $context['adresse_livraison'] = $adresse_livraison;
$context['adresse_facturation'] = $adresse_facturation; $context['adresse_facturation'] = $adresse_facturation;
$context['adresse_renseignee'] = $adresse_renseignee; $context['adresse_renseignee'] = $adresse_renseignee;
$context['sous_total_panier'] = $cart_subtotal; $context['sous_total_panier'] = $cart_subtotal;
$context['code_promo'] = $promo_code; $context['code_promo'] = $promo_code;
$context['sous_total_reduction'] = $cart_subtotal_with_discount; $context['sous_total_reduction'] = $cart_subtotal_with_discount;
$context['total_panier'] = $cart_total; $context['total_panier'] = $cart_total;
$context['produits_panier'] = $cart; $context['produits_panier'] = $cart;
$context['pays_livraison'] = $allowed_countries; $context['pays_livraison'] = $allowed_countries;
$context['sous_total_livraison'] = $shipping_subtotal; $context['sous_total_livraison'] = $shipping_subtotal;
$context['methodes_livraison'] = $methodes_livraison; $context['methodes_livraison'] = $methodes_livraison;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-panier', handle: 'haiku-atelier-2024-styles-page-panier',
path : '/assets/css/pages/page-panier.css', path: '/assets/css/pages/page-panier.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-panier', id: 'haiku-atelier-2024-scripts-page-panier',
path: '/assets/js/scripts-page-panier.js', path: '/assets/js/scripts-page-panier.js',
); );
}); });

View file

@ -44,9 +44,9 @@ $session_wc = WC()->session;
/** @var array<string,string> $urls URLs utilisables pour rediriger l'Utilisateur. */ /** @var array<string,string> $urls URLs utilisables pour rediriger l'Utilisateur. */
$urls = [ $urls = [
'accueil' => get_page_link(get_page_by_path('home')), 'accueil' => get_page_link(get_page_by_path('home')),
'succes_commande' => get_page_link(get_page_by_path('successful-order')), 'succes_commande' => get_page_link(get_page_by_path('successful-order')),
'echec_commande' => get_page_link(get_page_by_path('failed-order')), 'echec_commande' => get_page_link(get_page_by_path('failed-order')),
]; ];
// Redirige à la page d'accueil si le Panier est vide // Redirige à la page d'accueil si le Panier est vide
@ -97,14 +97,14 @@ $articles = collect($panier->get_cart())
return [ return [
'price_data' => [ 'price_data' => [
'currency' => 'EUR', 'currency' => 'EUR',
'product_data' => [ 'product_data' => [
'name' => $titre_produit, 'name' => $titre_produit,
'images' => [wp_get_attachment_image_url($article_panier['data']?->get_image_id())], 'images' => [wp_get_attachment_image_url($article_panier['data']?->get_image_id())],
], ],
'unit_amount' => $article_panier['data']?->get_price() * 100, 'unit_amount' => $article_panier['data']?->get_price() * 100,
], ],
'quantity' => $article_panier['quantity'], 'quantity' => $article_panier['quantity'],
]; ];
}) })
->values() ->values()
@ -126,13 +126,13 @@ Stripe::setApiKey(Config::get('STRIPE_API_SECRET'));
// Met à jour les Codes promos // Met à jour les Codes promos
$coupons_stripe = collect(Coupon::all()->data); $coupons_stripe = collect(Coupon::all()->data);
$coupons_wc = collect(WC()->cart->get_coupons()) $coupons_wc = collect(WC()->cart->get_coupons())
->map(static fn(WC_Coupon $coupon): array => [ ->map(static fn(WC_Coupon $coupon): array => [
'currency' => 'EUR', 'currency' => 'EUR',
'duration' => get_discount_duration($coupon), 'duration' => get_discount_duration($coupon),
'fixed_cart' === $coupon->get_discount_type() ? 'amount_off' : 'percent_off' => get_discount_amount($coupon), 'fixed_cart' === $coupon->get_discount_type() ? 'amount_off' : 'percent_off' => get_discount_amount($coupon),
'id' => $coupon->get_code(), 'id' => $coupon->get_code(),
'name' => $coupon->get_code(), 'name' => $coupon->get_code(),
]) ])
->each(static function (array $item) use ($coupons_stripe): void { ->each(static function (array $item) use ($coupons_stripe): void {
// Si le code promo n'existe pas, le créer // Si le code promo n'existe pas, le créer
@ -147,19 +147,19 @@ $reductions_stripe = $coupons_wc
/** @var Session $session_checkout_stripe */ /** @var Session $session_checkout_stripe */
$session_checkout_stripe = Session::create([ $session_checkout_stripe = Session::create([
'cancel_url' => $urls['echec_commande'], 'cancel_url' => $urls['echec_commande'],
'customer_email' => $email_client, 'customer_email' => $email_client,
'discounts' => $reductions_stripe, 'discounts' => $reductions_stripe,
'line_items' => $articles, 'line_items' => $articles,
'mode' => 'payment', 'mode' => 'payment',
'success_url' => $urls['succes_commande'] . '?session_id={CHECKOUT_SESSION_ID}', 'success_url' => $urls['succes_commande'] . '?session_id={CHECKOUT_SESSION_ID}',
'metadata' => ['order_id' => $order_id, 'order_key' => $order_key], 'metadata' => ['order_id' => $order_id, 'order_key' => $order_key],
'shipping_options' => [[ 'shipping_options' => [[
'shipping_rate_data' => [ 'shipping_rate_data' => [
'display_name' => $methode_livraison['nom'], 'display_name' => $methode_livraison['nom'],
'fixed_amount' => ['amount' => $methode_livraison['cout'], 'currency' => 'EUR'], 'fixed_amount' => ['amount' => $methode_livraison['cout'], 'currency' => 'EUR'],
'tax_behavior' => 'inclusive', 'tax_behavior' => 'inclusive',
'type' => 'fixed_amount', 'type' => 'fixed_amount',
], ],
]], ]],
], ['idempotency_key' => Uuid::v4()]); ], ['idempotency_key' => Uuid::v4()]);

View file

@ -13,13 +13,13 @@ use Timber\Timber;
use function add_action; use function add_action;
$context = Timber::context(); $context = Timber::context();
$templates = ['contact.twig']; $templates = ['contact.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-contact', handle: 'haiku-atelier-2024-styles-page-contact',
path : '/assets/css/pages/page-contact.min.css', path: '/assets/css/pages/page-contact.min.css',
); );
}); });

View file

@ -13,13 +13,13 @@ use Timber\Timber;
use function add_action; use function add_action;
$context = Timber::context(); $context = Timber::context();
$templates = ['echec-commande.twig']; $templates = ['echec-commande.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-modele-simple', handle: 'haiku-atelier-2024-styles-page-modele-simple',
path : '/assets/css/pages/page-modele-simple.css', path: '/assets/css/pages/page-modele-simple.css',
); );
}); });

View file

@ -61,7 +61,7 @@ try {
$panier->empty_cart(); $panier->empty_cart();
} }
$context = Timber::context(); $context = Timber::context();
$templates = ['succes-commande.twig']; $templates = ['succes-commande.twig'];
// Récupère les données des Produits // Récupère les données des Produits
@ -76,7 +76,7 @@ try {
// Récupère le nom et la valeur de l'attribut du Produit // Récupère le nom et la valeur de l'attribut du Produit
$attribut = $produit->is_type('variable') $attribut = $produit->is_type('variable')
? collect($produit->get_attributes())->mapWithKeys(static function ($_atr, $cle) use ($produit_commande) { ? collect($produit->get_attributes())->mapWithKeys(static function ($_atr, $cle) use ($produit_commande) {
$nom_attribut = wc_attribute_label($cle, $produit_commande->get_product()); $nom_attribut = wc_attribute_label($cle, $produit_commande->get_product());
$valeur_attribut = $produit_commande->get_product()->get_attribute($cle); $valeur_attribut = $produit_commande->get_product()->get_attribute($cle);
return [['nom' => $nom_attribut, 'valeur' => $valeur_attribut]]; return [['nom' => $nom_attribut, 'valeur' => $valeur_attribut]];
@ -84,16 +84,16 @@ try {
: []; : [];
return [ return [
'attribut' => $attribut, 'attribut' => $attribut,
'id_produit' => $id_produit, 'id_produit' => $id_produit,
'image' => pipe($produit->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag( 'image' => pipe($produit->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag(
id : $id, id: $id,
lazy: true, lazy: true,
)), )),
'permalien' => $produit->get_permalink(), 'permalien' => $produit->get_permalink(),
'prix' => $produit_commande->get_data()['total'], 'prix' => $produit_commande->get_data()['total'],
'quantite' => $produit_commande->get_quantity(), 'quantite' => $produit_commande->get_quantity(),
'titre' => $produit->get_title(), 'titre' => $produit->get_title(),
]; ];
}); });
@ -103,10 +103,10 @@ try {
function charge_scripts_styles_page_succes_commande(): void { function charge_scripts_styles_page_succes_commande(): void {
wp_enqueue_style( wp_enqueue_style(
handle: 'haiku-atelier-2024-styles-page-succes-commande', handle: 'haiku-atelier-2024-styles-page-succes-commande',
src : get_template_directory_uri() . '/assets/css/pages/page-succes-commande.css', src: get_template_directory_uri() . '/assets/css/pages/page-succes-commande.css',
deps : [], deps: [],
ver : filemtime(get_template_directory() . '/assets/css/pages/page-succes-commande.css'), ver: filemtime(get_template_directory() . '/assets/css/pages/page-succes-commande.css'),
media : 'all', media: 'all',
); );
} }

View file

@ -13,13 +13,13 @@ use Timber\Timber;
use function add_action; use function add_action;
$context = Timber::context(); $context = Timber::context();
$templates = ['cgv.twig']; $templates = ['cgv.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: '/assets/css/pages/page-modele-simple.css', handle: '/assets/css/pages/page-modele-simple.css',
path : '/assets/css/pages/page-modele-simple.css', path: '/assets/css/pages/page-modele-simple.css',
); );
}); });

View file

@ -27,7 +27,7 @@ use function wc_get_product;
use function wp_create_nonce; use function wp_create_nonce;
use function wp_json_encode; use function wp_json_encode;
$context = Timber::context(); $context = Timber::context();
$templates = ['produit.twig']; $templates = ['produit.twig'];
$raw_product = wc_get_product(); $raw_product = wc_get_product();
@ -55,13 +55,13 @@ $same_collection_products = Product::get_same_collection_products($product->coll
Product::from_wc_product(...), Product::from_wc_product(...),
)); ));
$context['product'] = $product; $context['product'] = $product;
$context['product_json'] = wp_json_encode($product); $context['product_json'] = wp_json_encode($product);
$context['maximum_price'] = $maximum_price; $context['maximum_price'] = $maximum_price;
$context['same_collection_products'] = $same_collection_products; $context['same_collection_products'] = $same_collection_products;
$product_tags = $raw_product->get_tag_ids() $product_tags = $raw_product->get_tag_ids()
|> (static fn($tags_ids) => Arr::map($tags_ids, static fn($id) => Term::get_term_by_id( |> (static fn($tags_ids) => Arr::map($tags_ids, static fn($id) => Term::get_term_by_id(
id : $id, id: $id,
taxonomy: 'product_tag', taxonomy: 'product_tag',
))) )))
|> (static fn(/** @var list<Option<WC_Term>> */ $tags) => Arr::reject($tags, static fn($tag) => $tag->isNone())) |> (static fn(/** @var list<Option<WC_Term>> */ $tags) => Arr::reject($tags, static fn($tag) => $tag->isNone()))
@ -70,11 +70,11 @@ $tags = get_terms(['taxonomy' => 'product_tag', 'hide_empty' => true]);
// 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 = [
'nonce' => wp_create_nonce('wc_store_api'), 'nonce' => wp_create_nonce('wc_store_api'),
'product' => [ 'product' => [
'attributes' => $product->attributes, 'attributes' => $product->attributes,
'id' => $product->id, 'id' => $product->id,
'price' => $product->price, 'price' => $product->price,
'variations' => $product->variations, 'variations' => $product->variations,
], ],
] ]
@ -84,11 +84,11 @@ $context['page_states'] = $page_states;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-produit', id: 'haiku-atelier-2024-scripts-page-produit',
path: '/assets/js/scripts-page-produit.js', path: '/assets/js/scripts-page-produit.js',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-menu-categories', id: 'haiku-atelier-2024-scripts-menu-categories',
path: '/assets/js/scripts-menu-categories.js', path: '/assets/js/scripts-menu-categories.js',
); );
}); });

View file

@ -51,8 +51,8 @@ final class StarterSite extends Site {
// Récupère les liens des réseaux sociaux définis dans la personnalisation du thème // Récupère les liens des réseaux sociaux définis dans la personnalisation du thème
$personnalisations_theme = get_theme_mods(); $personnalisations_theme = get_theme_mods();
$liens_reseaux_sociaux = [ $liens_reseaux_sociaux = [
'facebook' => ['nom' => 'Facebook', 'url' => $personnalisations_theme['lien_facebook'] ?? ''], 'facebook' => ['nom' => 'Facebook', 'url' => $personnalisations_theme['lien_facebook'] ?? ''],
'instagram' => ['nom' => 'Instagram', 'url' => $personnalisations_theme['lien_instagram'] ?? ''], 'instagram' => ['nom' => 'Instagram', 'url' => $personnalisations_theme['lien_instagram'] ?? ''],
'pinterest' => ['nom' => 'Pinterest', 'url' => $personnalisations_theme['lien_pinterest'] ?? ''], 'pinterest' => ['nom' => 'Pinterest', 'url' => $personnalisations_theme['lien_pinterest'] ?? ''],
]; ];
@ -61,14 +61,14 @@ final class StarterSite extends Site {
// Récupère les textes apparaissant sur les pages Produits // Récupère les textes apparaissant sur les pages Produits
$descriptions_produits = [ $descriptions_produits = [
'texte_conditions_livraison' => wpautop($personnalisations_theme['texte_conditions_livraison']) ?? '', 'texte_conditions_livraison' => wpautop($personnalisations_theme['texte_conditions_livraison']) ?? '',
'texte_entretien_produit' => wpautop($personnalisations_theme['texte_entretien_produit']) ?? '', 'texte_entretien_produit' => wpautop($personnalisations_theme['texte_entretien_produit']) ?? '',
]; ];
$context['descriptions_produits'] = $descriptions_produits; $context['descriptions_produits'] = $descriptions_produits;
// Logo personnalisée // Logo personnalisée
$context['logo'] = pipe(get_theme_mod('custom_logo'), static fn($id) => wp_get_attachment_image_src( $context['logo'] = pipe(get_theme_mod('custom_logo'), static fn($id) => wp_get_attachment_image_src(
attachment_id: $id, attachment_id: $id,
size : 'full', size: 'full',
)); ));
// Informations des Pages // Informations des Pages
@ -80,27 +80,28 @@ final class StarterSite extends Site {
// Pages spécifiques // Pages spécifiques
$context['pages'] = (object) [ $context['pages'] = (object) [
'about' => $recupere_informations_page('about'), 'about' => $recupere_informations_page('about'),
'account' => $recupere_informations_page('account'), 'account' => $recupere_informations_page('account'),
'cart' => $recupere_informations_page('cart'), 'cart' => $recupere_informations_page('cart'),
'checkout' => $recupere_informations_page('checkout'), 'checkout' => $recupere_informations_page('checkout'),
'contact' => $recupere_informations_page('contact'), 'contact' => $recupere_informations_page('contact'),
'failed_order' => $recupere_informations_page('failed_order'), 'failed_order' => $recupere_informations_page('failed_order'),
'home' => $recupere_informations_page('home'), 'home' => $recupere_informations_page('home'),
'shop' => $recupere_informations_page('shop'), 'shop' => $recupere_informations_page('shop'),
'successful_order' => $recupere_informations_page('successful_order'), 'successful_order' => $recupere_informations_page('successful_order'),
]; ];
// Récupère la Page courante // Récupère la Page courante
$url_courante = URLHelper::get_current_url(); $url_courante = URLHelper::get_current_url();
$context['page_courante'] = $url_courante; $context['page_courante'] = $url_courante;
$context['est_page_tous_produits'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante); $context['est_page_tous_produits'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante);
$context['est_page_boutique'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante) $context['est_page_boutique'] =
|| preg_match(pattern: '/(\bproduct\b)/', subject: $url_courante) preg_match(pattern: '/(\bshop\b)/', subject: $url_courante)
|| preg_match(pattern: '/(\bproduct-category\b)/', subject: $url_courante); || preg_match(pattern: '/(\bproduct\b)/', subject: $url_courante)
|| preg_match(pattern: '/(\bproduct-category\b)/', subject: $url_courante);
// Politique de confidentialité // Politique de confidentialité
$politique_confidentialite_lien = pipe(get_privacy_policy_url(), esc_url(...)); $politique_confidentialite_lien = pipe(get_privacy_policy_url(), esc_url(...));
$context['lien_politique_confidentialite'] = $politique_confidentialite_lien; $context['lien_politique_confidentialite'] = $politique_confidentialite_lien;
// Chemin de base pour une Catégorie de Produit (p. ex. /product-category/<produit>) // Chemin de base pour une Catégorie de Produit (p. ex. /product-category/<produit>)
@ -108,7 +109,7 @@ final class StarterSite extends Site {
// Récupère les Catégories de Produits // Récupère les Catégories de Produits
$cree_entree_menu = static fn($categorie): array => [ $cree_entree_menu = static fn($categorie): array => [
'nom' => $categorie->name, 'nom' => $categorie->name,
'slug' => $categorie->slug, 'slug' => $categorie->slug,
// Détermine si l'URL courante est celle de la Page d'Archive d'une Catégorie de Produits // Détermine si l'URL courante est celle de la Page d'Archive d'une Catégorie de Produits
'courante' => preg_match( 'courante' => preg_match(
@ -124,16 +125,16 @@ final class StarterSite extends Site {
$context['categories_produits'] = $entrees_menu_categories; $context['categories_produits'] = $entrees_menu_categories;
// Récupère le Panier de l'Utilisateur // Récupère le Panier de l'Utilisateur
$panier = WC()?->cart?->get_cart(); $panier = WC()?->cart?->get_cart();
$quantite_articles = WC()?->cart?->get_cart_contents_count(); $quantite_articles = WC()?->cart?->get_cart_contents_count();
$articles_presents = $quantite_articles > 0 ? 'true' : 'false'; $articles_presents = $quantite_articles > 0 ? 'true' : 'false';
$context['panier'] = $panier; $context['panier'] = $panier;
$context['quantite_articles'] = $quantite_articles; $context['quantite_articles'] = $quantite_articles;
$context['articles_presents'] = $articles_presents; $context['articles_presents'] = $articles_presents;
// Nonce WooCommerce pour l'API Rest // Nonce WooCommerce pour l'API Rest
$nonce_wc = wp_create_nonce('wc_store_api'); $nonce_wc = wp_create_nonce('wc_store_api');
$context['nonce_wc'] = $nonce_wc; $context['nonce_wc'] = $nonce_wc;
// TODO: Utiliser des variables d'environnement // TODO: Utiliser des variables d'environnement
$auth_string = base64_encode( $auth_string = base64_encode(

View file

@ -28,9 +28,9 @@ function cree_champs_personnalises_produit(): void {
function cree_champ_personnalise_commande($order): void { function cree_champ_personnalise_commande($order): void {
woocommerce_wp_text_input([ woocommerce_wp_text_input([
'id' => 'tracking_number', 'id' => 'tracking_number',
'label' => 'Tracking Number:', 'label' => 'Tracking Number:',
'value' => $order->get_meta('tracking_number'), 'value' => $order->get_meta('tracking_number'),
'wrapper_class' => 'form-field-wide', 'wrapper_class' => 'form-field-wide',
]); ]);
} }

View file

@ -27,10 +27,10 @@ function enregistre_controle_personnalise_tinymce(): void {
public function enqueue(): void { public function enqueue(): void {
wp_enqueue_script( wp_enqueue_script(
handle: 'controle-personnalise-tinymce', handle: 'controle-personnalise-tinymce',
src : get_template_directory_uri() . '/assets/vendor/controle-personnalise-tinymce.js', src: get_template_directory_uri() . '/assets/vendor/controle-personnalise-tinymce.js',
deps : ['jquery'], deps: ['jquery'],
ver : '1.3', ver: '1.3',
args : true, args: true,
); );
wp_enqueue_editor(); wp_enqueue_editor();
} }

View file

@ -17,7 +17,7 @@ final readonly class Attribute {
public function __construct( public function __construct(
public string $name, public string $name,
public string $slug, public string $slug,
public array $options, public array $options,
) {} ) {}
/** /**
@ -26,10 +26,8 @@ final readonly class Attribute {
public static function new(WC_Product_Attribute $attribute): self { public static function new(WC_Product_Attribute $attribute): self {
$name = wc_attribute_label($attribute->get_name()); $name = wc_attribute_label($attribute->get_name());
$slug = $attribute->get_name(); $slug = $attribute->get_name();
/** @var list<WP_Term> */ /** @var list<WP_Term> */
$terms = $attribute->get_terms() ?? []; $terms = $attribute->get_terms() ?? [];
/** @var list<AttributeOption> */ /** @var list<AttributeOption> */
$options = Arr::map($terms, AttributeOption::new(...)) $options = Arr::map($terms, AttributeOption::new(...))
|> (static fn($options) => Arr::sort($options, static fn($attribute) => $attribute->id)) |> (static fn($options) => Arr::sort($options, static fn($attribute) => $attribute->id))

View file

@ -8,7 +8,7 @@ use WP_Term;
final readonly class AttributeOption { final readonly class AttributeOption {
public function __construct( public function __construct(
public int $id, public int $id,
public string $name, public string $name,
public string $slug, public string $slug,
) {} ) {}
@ -17,7 +17,7 @@ final readonly class AttributeOption {
* Créé une nouvelle instance de `AttributeOption` depuis un `WP_Term`. * Créé une nouvelle instance de `AttributeOption` depuis un `WP_Term`.
*/ */
public static function new(WP_Term $term): self { public static function new(WP_Term $term): self {
$id = $term->term_taxonomy_id; $id = $term->term_taxonomy_id;
$name = $term->name; $name = $term->name;
$slug = $term->slug; $slug = $term->slug;

View file

@ -112,10 +112,10 @@ final readonly class Cart {
private static function format_number(int|float $number): string { private static function format_number(int|float $number): string {
$formatted_number = Number::format( $formatted_number = Number::format(
number : $number, number: $number,
// precision et max_precision sont mutuellement exclusifs. // precision et max_precision sont mutuellement exclusifs.
precision: 2, precision: 2,
locale : 'fr', locale: 'fr',
); );
return is_bool($formatted_number) ? self::DEFAULT_VALUE : $formatted_number; return is_bool($formatted_number) ? self::DEFAULT_VALUE : $formatted_number;

View file

@ -18,31 +18,28 @@ use function Psl\Option\from_nullable;
use function wc_get_products; use function wc_get_products;
use function wpautop; use function wpautop;
/**
* Représente un **Produit** (selon _WooCommerce_) avec de nombreuses données d'intérêt pour les opérations courantes.
*/
final readonly class Product { final readonly class Product {
/** /**
* @param list<Attribute> $attributes La liste des `Attribute` appliquées. * @param list<Attribute> $attributes
* @param list<string> $left_column_photos * @param list<string> $left_column_photos
* @param list<string> $right_column_photos * @param list<string> $right_column_photos
* @param array<ProductVariation> $variations * @param array<ProductVariation> $variations
*/ */
private function __construct( private function __construct(
public array $attributes, public array $attributes,
public string $category, public string $category,
public string $collection, public string $collection,
public string $details, public string $details,
public int $id, public int $id,
public string $name, public string $name,
public string $price, public string $price,
public array $left_column_photos, public array $left_column_photos,
public array $right_column_photos, public array $right_column_photos,
public string $default_photo, public string $default_photo,
public string $hover_photo, public string $hover_photo,
public string $slug, public string $slug,
public int $stock, public int $stock,
public array $variations, public array $variations,
public string $url, public string $url,
) {} ) {}
@ -62,17 +59,17 @@ final readonly class Product {
/** @var string */ /** @var string */
$details = $product->get_description() |> wpautop(...); $details = $product->get_description() |> wpautop(...);
$id = $product->get_id(); $id = $product->get_id();
$name = $product->get_name(); $name = $product->get_name();
$price = $product->get_price(); $price = $product->get_price();
/** @var list<string> */ /** @var list<string> */
$left_column_photos = HaikuProduct::get_left_column_photos($id); $left_column_photos = HaikuProduct::get_left_column_photos($id);
/** @var list<string> */ /** @var list<string> */
$right_column_photos = HaikuProduct::get_right_column_photos($id); $right_column_photos = HaikuProduct::get_right_column_photos($id);
$default_photo = $left_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1'); $default_photo = $left_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1');
$hover_photo = $right_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1', true); $hover_photo = $right_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1', true);
$slug = $product->get_slug(); $slug = $product->get_slug();
$stock = $product->get_stock_quantity() ?? 1; $stock = $product->get_stock_quantity() ?? 1;
/** @var array<ProductVariation> */ /** @var array<ProductVariation> */
$variations = $product->get_children() $variations = $product->get_children()
|> (static fn(/** @var list<int> */ array $ids): array => Arr::map($ids, wc_get_product(...))) |> (static fn(/** @var list<int> */ array $ids): array => Arr::map($ids, wc_get_product(...)))
@ -83,21 +80,21 @@ final readonly class Product {
$url = $product->get_permalink(); $url = $product->get_permalink();
return new self( return new self(
attributes : $attributes, attributes: $attributes,
category : $category, category: $category,
collection : $collection, collection: $collection,
details : $details, details: $details,
id : $id, id: $id,
name : $name, name: $name,
price : $price, price: $price,
left_column_photos : $left_column_photos, left_column_photos: $left_column_photos,
right_column_photos: $right_column_photos, right_column_photos: $right_column_photos,
default_photo : $default_photo, default_photo: $default_photo,
hover_photo : $hover_photo, hover_photo: $hover_photo,
slug : $slug, slug: $slug,
stock : $stock, stock: $stock,
variations : $variations, variations: $variations,
url : $url, url: $url,
); );
} }
@ -118,21 +115,21 @@ final readonly class Product {
*/ */
public static function get_same_collection_products(string $slug_collection): callable { public static function get_same_collection_products(string $slug_collection): callable {
return static fn(int $id_produit): array|stdClass => wc_get_products([ return static fn(int $id_produit): array|stdClass => wc_get_products([
'exclude' => [$id_produit], 'exclude' => [$id_produit],
'limit' => 4, 'limit' => 4,
'order' => 'DESC', 'order' => 'DESC',
'orderby' => 'date', 'orderby' => 'date',
'status' => 'publish', 'status' => 'publish',
'tax_query' => [['taxonomy' => 'collection', 'field' => 'slug', 'terms' => $slug_collection]], 'tax_query' => [['taxonomy' => 'collection', 'field' => 'slug', 'terms' => $slug_collection]],
]); ]);
} }
public static function recupere_et_formate_attributs_produit(mixed $attributs_produit): mixed { public static function recupere_et_formate_attributs_produit(mixed $attributs_produit): mixed {
return [ return [
'cote' => ['nom' => 'Side', 'valeur' => $attributs_produit['pa_side'] ?? false], 'cote' => ['nom' => 'Side', 'valeur' => $attributs_produit['pa_side'] ?? false],
'materiel' => ['nom' => 'Material', 'valeur' => $attributs_produit['pa_material-workshop'] ?? false], 'materiel' => ['nom' => 'Material', 'valeur' => $attributs_produit['pa_material-workshop'] ?? false],
'pierre' => ['nom' => 'Stone', 'valeur' => $attributs_produit['pa_stone'] ?? false], 'pierre' => ['nom' => 'Stone', 'valeur' => $attributs_produit['pa_stone'] ?? false],
'taille' => ['nom' => 'Size', 'valeur' => $attributs_produit['pa_size'] ?? false], 'taille' => ['nom' => 'Size', 'valeur' => $attributs_produit['pa_size'] ?? false],
]; ];
} }
} }

View file

@ -13,16 +13,16 @@ final readonly class ProductVariation {
* @param list<ProductVariationAttribute> $attributes Les attributs appliqués à la Variation * @param list<ProductVariationAttribute> $attributes Les attributs appliqués à la Variation
*/ */
private function __construct( private function __construct(
public int $id, public int $id,
public string $price, public string $price,
public array $attributes, public array $attributes,
) {} ) {}
/** /**
* Créé une nouvelle instance de `ProductVariation` depuis un `WC_Product`. * Créé une nouvelle instance de `ProductVariation` depuis un `WC_Product`.
*/ */
public static function new(WC_Product $product): self { public static function new(WC_Product $product): self {
$id = $product->get_id(); $id = $product->get_id();
$price = $product->get_price(); $price = $product->get_price();
/** @var list<ProductVariationAttribute> */ /** @var list<ProductVariationAttribute> */
$attributes = array_map( $attributes = array_map(

View file

@ -40,7 +40,7 @@ function desactive_transformation_contenu_tinymce(array $configuration): array {
* @return array<string, string> le même tableau avec SVG en plus * @return array<string, string> le même tableau avec SVG en plus
*/ */
function autorise_import_svg_mediatheque(array $file_types): array { function autorise_import_svg_mediatheque(array $file_types): array {
$new_filetypes = []; $new_filetypes = [];
$new_filetypes['svg'] = 'image/svg+xml'; $new_filetypes['svg'] = 'image/svg+xml';
return [...$file_types, ...$new_filetypes]; return [...$file_types, ...$new_filetypes];
@ -58,9 +58,6 @@ function retire_styles_core_block(): void {
add_filter('async_update_translation', '__return_false'); add_filter('async_update_translation', '__return_false');
add_filter('auto_update_translation', '__return_false'); add_filter('auto_update_translation', '__return_false');
// Désactive la génération automatique de sitemaps.
add_filter('wp_sitemaps_enabled', '__return_false');
add_action('init', desactive_wpautop(...)); add_action('init', desactive_wpautop(...));
add_filter('tiny_mce_before_init', desactive_transformation_contenu_tinymce(...)); add_filter('tiny_mce_before_init', desactive_transformation_contenu_tinymce(...));
add_filter('upload_mimes', autorise_import_svg_mediatheque(...)); add_filter('upload_mimes', autorise_import_svg_mediatheque(...));

View file

@ -143,11 +143,11 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
$response->data['image_repos'] = pipe( $response->data['image_repos'] = pipe(
$response->data['meta_data'], $response->data['meta_data'],
static fn($metadata): array => array_filter( static fn($metadata): array => array_filter(
array : $metadata, array: $metadata,
callback: static fn($entree): bool => '_photos_colonne_gauche|||0|value' === $entree->key, callback: static fn($entree): bool => '_photos_colonne_gauche|||0|value' === $entree->key,
), ),
static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag( static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag(
id : $entree?->value, id: $entree?->value,
lazy: true, lazy: true,
)), )),
static fn($image) => array_values(array: $image)[0], static fn($image) => array_values(array: $image)[0],
@ -157,11 +157,11 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
$response->data['image_survol'] = pipe( $response->data['image_survol'] = pipe(
$response->data['meta_data'], $response->data['meta_data'],
static fn($metadata): array => array_filter( static fn($metadata): array => array_filter(
array : $metadata, array: $metadata,
callback: static fn($entree): bool => '_photos_colonne_droite|||0|value' === $entree->key, callback: static fn($entree): bool => '_photos_colonne_droite|||0|value' === $entree->key,
), ),
static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag( static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag(
id : $entree?->value, id: $entree?->value,
lazy: true, lazy: true,
)), )),
static fn($image) => array_values(array: $image)[0], static fn($image) => array_values(array: $image)[0],

View file

@ -16,27 +16,27 @@ use function register_taxonomy;
*/ */
function enregistre_taxonomie_collection(): void { function enregistre_taxonomie_collection(): void {
$labels = [ $labels = [
'add_new_item' => __('Add New Collection'), 'add_new_item' => __('Add New Collection'),
'all_items' => __('All Collections'), 'all_items' => __('All Collections'),
'edit_item' => __('Edit Collection'), 'edit_item' => __('Edit Collection'),
'menu_name' => __('Collections'), 'menu_name' => __('Collections'),
'name' => __('Collections'), 'name' => __('Collections'),
'new_item_name' => __('New Collection Name'), 'new_item_name' => __('New Collection Name'),
'search_items' => __('Search Collections'), 'search_items' => __('Search Collections'),
'singular_name' => __('Collection'), 'singular_name' => __('Collection'),
'update_item' => __('Update Collection'), 'update_item' => __('Update Collection'),
]; ];
$args = [ $args = [
'description' => __('An ensemble of pieces thematically or chronologically grouped together.'), 'description' => __('An ensemble of pieces thematically or chronologically grouped together.'),
'hierarchical' => false, 'hierarchical' => false,
'labels' => $labels, 'labels' => $labels,
'publicly_queryable' => false, 'publicly_queryable' => false,
'query_var' => true, 'query_var' => true,
'rewrite' => ['slug' => 'collection'], 'rewrite' => ['slug' => 'collection'],
'show_admin_column' => true, 'show_admin_column' => true,
'show_in_menu' => true, 'show_in_menu' => true,
'show_in_quick_edit' => true, 'show_in_quick_edit' => true,
'show_ui' => true, 'show_ui' => true,
]; ];
register_taxonomy('collection', ['product'], $args); register_taxonomy('collection', ['product'], $args);

View file

@ -21,7 +21,7 @@ final readonly class Resource {
public static function enqueue_script_module_file(string $path, string $id): void { public static function enqueue_script_module_file(string $path, string $id): void {
$file_uri = get_template_directory_uri() . $path; $file_uri = get_template_directory_uri() . $path;
$file_path = get_template_directory() . $path; $file_path = get_template_directory() . $path;
$file_mtime = filemtime($file_path); $file_mtime = filemtime($file_path);
if (is_bool($file_mtime)) { if (is_bool($file_mtime)) {
@ -39,7 +39,7 @@ final readonly class Resource {
public static function enqueue_style_file(string $path, string $handle): void { public static function enqueue_style_file(string $path, string $handle): void {
$file_uri = get_template_directory_uri() . $path; $file_uri = get_template_directory_uri() . $path;
$file_path = get_template_directory() . $path; $file_path = get_template_directory() . $path;
$file_mtime = filemtime($file_path); $file_mtime = filemtime($file_path);
if (is_bool($file_mtime)) { if (is_bool($file_mtime)) {
@ -66,29 +66,30 @@ final readonly class Resource {
return ''; return '';
} }
$url = wp_get_attachment_image_url($int_id, 'full'); $url = wp_get_attachment_image_url($int_id, 'full');
$chemin = realpath(get_attached_file($int_id)) ?: realpath(get_attached_file($int_id)); $chemin = realpath(get_attached_file($int_id)) ?: realpath(get_attached_file($int_id));
$alt = get_post_meta($int_id, '_wp_attachment_image_alt', true); $alt = get_post_meta($int_id, '_wp_attachment_image_alt', true);
$dimensions = $chemin ? getimagesize($chemin) : ['', '']; $dimensions = $chemin ? getimagesize($chemin) : ['', ''];
$avif = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.avif') : false; $avif = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.avif') : false;
$jxl = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.jxl') : false; $jxl = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.jxl') : false;
// Génère un tableau avec les différents formats valides // Génère un tableau avec les différents formats valides
$formats = pipe( $formats = pipe(
[$avif, $jxl], [$avif, $jxl],
static fn($tableau): array => array_filter( static fn($tableau): array => array_filter(
array : $tableau, array: $tableau,
callback: static fn($chemin_format): bool => false !== $chemin_format, callback: static fn($chemin_format): bool => false !== $chemin_format,
), ),
static fn($tableau): array => array_map(array: $tableau, callback: static fn($chemin_format): array => [ static fn($tableau): array => array_map(array: $tableau, callback: static fn($chemin_format): array => [
'format' => pathinfo((string) $chemin_format)['extension'], 'format' => pathinfo((string) $chemin_format)['extension'],
'taille' => filesize($chemin_format), 'taille' => filesize($chemin_format),
'url' => pathinfo($url)['dirname'] 'url' =>
. '/' pathinfo($url)['dirname']
. pathinfo($url)['filename'] . '/'
. '.' . pathinfo($url)['filename']
. pathinfo((string) $chemin_format)['extension'], . '.'
. pathinfo((string) $chemin_format)['extension'],
]), ]),
); );
usort(array: $formats, callback: static fn($a, $b): int => $a['taille'] <=> $b['taille']); usort(array: $formats, callback: static fn($a, $b): int => $a['taille'] <=> $b['taille']);
@ -96,8 +97,8 @@ final readonly class Resource {
// Construis les balises <source> avec les formats valides // Construis les balises <source> avec les formats valides
$sources = ''; $sources = '';
foreach ($formats as $format) { foreach ($formats as $format) {
$height = $dimensions[0]; $height = $dimensions[0];
$width = $dimensions[1]; $width = $dimensions[1];
$sources .= "<source height='{$height}' srcset='{$format['url']}' type='image/{$format['format']}' width='{$width}' />\n"; $sources .= "<source height='{$height}' srcset='{$format['url']}' type='image/{$format['format']}' width='{$width}' />\n";
} }

View file

@ -142,8 +142,8 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
HttpClientRequest.setHeader("Nonce", nonce), HttpClientRequest.setHeader("Nonce", nonce),
// TODO: Utiliser l'environnement // TODO: Utiliser l'environnement
HttpClientRequest.basicAuth( HttpClientRequest.basicAuth(
"ck_ed966a2265099a6dfe9915db692cbd2450cceed6", "ck_eded693107df0dbc19dab937e0c71325db810a4a",
"cs_a046c91647af95188a3e39a736ebe02f2024e430", "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),

View file

@ -69,9 +69,6 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
// 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);
/**
* Créé le `DOM` d'une Carte de Produit sous forme de `<article>`.
*/
const createProductDOM = (product: Product): HTMLElement => { const createProductDOM = (product: Product): HTMLElement => {
const article = document.createElement("article"); const article = document.createElement("article");
article.classList.add("produit"); article.classList.add("produit");
@ -98,14 +95,10 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
`; `;
return article; return article;
}; };
/**
* Créé le `DOM` des Cartes d'une nouvelle page de Produits sous forme d'un `DocumentFragment`.
*/
const createNewPageDOM = (products: ReadonlyArray<Product>) => { const createNewPageDOM = (products: ReadonlyArray<Product>) => {
const fragment: DocumentFragment = document.createDocumentFragment(); const fragment: DocumentFragment = document.createDocumentFragment();
// Ajoute le HTML des Produits au fragment. // Ajoute le HTML des cartes des Produits au fragment.
pipe( pipe(
FxArray.take(products, PRODUCTS_PER_PAGE), FxArray.take(products, PRODUCTS_PER_PAGE),
FxArray.forEach(product => { FxArray.forEach(product => {
@ -117,8 +110,8 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
return fragment; return fragment;
}; };
const onMoreProductsWantedHandler = Effect.fn("onMoreProductsWantedHandler")(function*() { const onMoreProductedWantedHandler = Effect.fn("onMoreProductedWantedHandler")(function*() {
yield* Console.debug("onMoreProductsWantedHandler"); yield* Console.debug("onMoreProductedWantedHandler");
/** Le numéro de page souhaitée. */ /** Le numéro de page souhaitée. */
const newPageNumber = yield* Ref.updateAndGet(PageNumber, pageNumber => pageNumber + 1); const newPageNumber = yield* Ref.updateAndGet(PageNumber, pageNumber => pageNumber + 1);
@ -137,7 +130,7 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
yield* SubscriptionRef.set(ShowMoreButtonText, "Getting Products..."); yield* SubscriptionRef.set(ShowMoreButtonText, "Getting Products...");
const newProducts = yield* API.GetProducts(nonce, requestBody); const newProducts = yield* API.GetProducts(nonce, requestBody);
yield* Console.debug("onMoreProductsWantedHandler", 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(ShowMoreButtonText, "Show more"); yield* SubscriptionRef.set(ShowMoreButtonText, "Show more");
@ -147,25 +140,21 @@ class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/S
ShowMoreButton.toggleAttribute(ATTRIBUT_HIDDEN, newProducts.length < PRODUCTS_PER_PAGE); ShowMoreButton.toggleAttribute(ATTRIBUT_HIDDEN, newProducts.length < PRODUCTS_PER_PAGE);
// Ajoute les nouveaux Produits dans le DOM. // Ajoute les nouveaux Produits dans le DOM.
const newProductsFragment = createNewPageDOM(newProducts); ProductsGrid.append(fragment);
ProductsGrid.append(newProductsFragment);
ProductsGrid.setAttribute(ATTRIBUT_PAGE, String(newPageNumber)); ProductsGrid.setAttribute(ATTRIBUT_PAGE, String(newPageNumber));
}); });
/** const initLoadMoreProductsOnButtonClick = Effect.fn("initLoadMoreProductsOnButtonClick")(function*() {
* Initialise l'écouteur d'événements de clic sur le bouton de chargement d'une nouvelle page de Produits (« Show more »).
*/
const initMoreProductsOnButtonClick = Effect.fn("initMoreProductsOnButtonClick")(function*() {
return yield* pipe( return yield* pipe(
Stream.fromEventListener(ShowMoreButton, "click"), Stream.fromEventListener(ShowMoreButton, "click"),
Stream.tap(onMoreProductsWantedHandler), Stream.tap(onMoreProductedWantedHandler),
Stream.runDrain, Stream.runDrain,
); );
}); });
return { return {
ProductsCategoryId, ProductsCategoryId,
initMoreProductsOnButtonClick, initLoadMoreProductsOnButtonClick,
}; };
}), }),
}) { }) {

View file

@ -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.tapCause(Console.error)); }).pipe(Effect.tapError(Console.error));
console.debug(Elements.ProductsGrid); console.debug(Elements.ProductsGrid);
})); }));

View file

@ -26,7 +26,7 @@ use function wc_get_products;
use function wp_create_nonce; use function wp_create_nonce;
use function wp_json_encode; use function wp_json_encode;
$context = Timber::context(); $context = Timber::context();
$templates = ['boutique.twig']; $templates = ['boutique.twig'];
/** @var WP_Term La Catégorie affichée. */ /** @var WP_Term La Catégorie affichée. */
@ -35,10 +35,10 @@ $current_term = get_queried_object();
/** @var list<Product> Les Produits de la Catégorie affichée. */ /** @var list<Product> Les Produits de la Catégorie affichée. */
$products = wc_get_products([ $products = wc_get_products([
'category' => [$current_term->slug], 'category' => [$current_term->slug],
'limit' => 12, 'limit' => 12,
'order' => 'DESC', 'order' => 'DESC',
'orderby' => 'date', 'orderby' => 'date',
'status' => 'publish', 'status' => 'publish',
]) ])
|> function (/** @var list<WC_Product>|stdClass */ mixed $products): array { |> function (/** @var list<WC_Product>|stdClass */ mixed $products): array {
assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.'); assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.');
@ -50,12 +50,12 @@ $products = wc_get_products([
Product::from_wc_product(...), Product::from_wc_product(...),
)); ));
$context['products'] = $products; $context['products'] = $products;
$context['category_id'] = $current_term->term_id; $context['category_id'] = $current_term->term_id;
// 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 = [
'nonce' => wp_create_nonce('wc_store_api'), 'nonce' => wp_create_nonce('wc_store_api'),
'authString' => base64_encode( 'authString' => base64_encode(
Config::get('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . Config::get('WOOCOMMERCE_API_CONSUMER_SECRET'), Config::get('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . Config::get('WOOCOMMERCE_API_CONSUMER_SECRET'),
), ),
@ -67,14 +67,14 @@ $context['page_states'] = $page_states;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-boutique', handle: 'haiku-atelier-2024-styles-page-boutique',
path : '/assets/css/pages/page-boutique.css', path: '/assets/css/pages/page-boutique.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-page-boutique', id: 'haiku-atelier-2024-scripts-page-boutique',
path: '/assets/js/scripts-page-boutique.js', path: '/assets/js/scripts-page-boutique.js',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id : 'haiku-atelier-2024-scripts-menu-categories', id: 'haiku-atelier-2024-scripts-menu-categories',
path: '/assets/js/scripts-menu-categories.js', path: '/assets/js/scripts-menu-categories.js',
); );
}); });

View file

@ -20,7 +20,7 @@ Timber::init();
// Sélectionne le répertoire contenant les modèles Twig // Sélectionne le répertoire contenant les modèles Twig
Timber::$dirname = ['views']; Timber::$dirname = ['views'];
$context = Timber::context(); $context = Timber::context();
$templates = ['email-commande-envoyee.twig']; $templates = ['email-commande-envoyee.twig'];
/** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */ /** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */
@ -30,7 +30,7 @@ $commande = $order;
$date = new Carbon($commande->get_date_created()); $date = new Carbon($commande->get_date_created());
$email = [ $email = [
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()], 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'livraison' => [ 'livraison' => [
'transporteur' => Str::of($commande->get_shipping_method())->replace(' (Free)', ''), 'transporteur' => Str::of($commande->get_shipping_method())->replace(' (Free)', ''),
'numero_suivi' => blank($commande->get_meta('tracking_number')) 'numero_suivi' => blank($commande->get_meta('tracking_number'))

View file

@ -21,7 +21,7 @@ Timber::init();
// Sélectionne le répertoire contenant les modèles Twig // Sélectionne le répertoire contenant les modèles Twig
Timber::$dirname = ['views']; Timber::$dirname = ['views'];
$context = Timber::context(); $context = Timber::context();
$templates = ['email-base.twig']; $templates = ['email-base.twig'];
/** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */ /** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */
@ -31,17 +31,14 @@ $commande = $order;
$date = new Carbon($commande->get_date_created()); $date = new Carbon($commande->get_date_created());
$email = [ $email = [
'adresses' => [ 'adresses' => ['facturation' => $commande->get_address('billing'), 'livraison' => $commande->get_address('shipping')],
'facturation' => $commande->get_address('billing'), 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'livraison' => $commande->get_address('shipping'),
],
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'livraison' => [ 'livraison' => [
'methode' => $commande->get_shipping_method(), 'methode' => $commande->get_shipping_method(),
'numero_suivi' => $commande->get_meta('tracking_number'), 'numero_suivi' => $commande->get_meta('tracking_number'),
], ],
'paiement' => ['methode' => ''], 'paiement' => ['methode' => ''],
'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) { 'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) {
$produit = $article->get_product(); $produit = $article->get_product();
if (is_bool($produit) || $produit === null) { if (is_bool($produit) || $produit === null) {
@ -50,31 +47,31 @@ $email = [
return [ return [
// Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide // Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide
'attribut' => $produit->is_type('variable') 'attribut' => $produit->is_type('variable')
? collect($produit->get_attributes()) ? collect($produit->get_attributes())
->mapWithKeys(static fn($_atr, $cle): array => [ ->mapWithKeys(static fn($_atr, $cle): array => [
'nom' => Str::lower(wc_attribute_label($cle, $produit)), 'nom' => Str::lower(wc_attribute_label($cle, $produit)),
'valeur' => $produit->get_attribute($cle), 'valeur' => $produit->get_attribute($cle),
]) ])
->toArray() ->toArray()
: [], : [],
'lien' => $produit->get_permalink(), 'lien' => $produit->get_permalink(),
'nom' => $produit->get_title(), 'nom' => $produit->get_title(),
'prix_total' => $article->get_total(), 'prix_total' => $article->get_total(),
'quantite' => $article->get_quantity(), 'quantite' => $article->get_quantity(),
]; ];
}), }),
'totaux' => [ 'totaux' => [
'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€', 'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€',
'sous_total_produits' => $commande->get_subtotal() . '€', 'sous_total_produits' => $commande->get_subtotal() . '€',
'sous_total_reduction' => '0.00' === $commande->get_discount_total() 'sous_total_reduction' => '0.00' === $commande->get_discount_total()
? '0' ? '0'
: Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€', : Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€',
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€', 'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€',
], ],
]; ];
// Transforme les codes de pays en noms de pays // Transforme les codes de pays en noms de pays
$email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()]; $email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()];
$email['adresses']['facturation']['country'] = WC()->countries->countries[$commande->get_billing_country()]; $email['adresses']['facturation']['country'] = WC()->countries->countries[$commande->get_billing_country()];
$context['commande'] = $email; $context['commande'] = $email;

View file

@ -21,7 +21,7 @@ Timber::init();
// Sélectionne le répertoire contenant les modèles Twig // Sélectionne le répertoire contenant les modèles Twig
Timber::$dirname = ['views']; Timber::$dirname = ['views'];
$context = Timber::context(); $context = Timber::context();
$templates = ['email-commande-recue.twig']; $templates = ['email-commande-recue.twig'];
/** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */ /** @var Order $commande La Commande issue du contexte contenu dans la variable $order. */
@ -43,31 +43,31 @@ $email = [
return [ return [
// Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide // Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide
'attribut' => $article->is_type('variable') 'attribut' => $article->is_type('variable')
? collect($produit->get_attributes()) ? collect($produit->get_attributes())
->mapWithKeys(static fn($_atr, $cle): array => [ ->mapWithKeys(static fn($_atr, $cle): array => [
'nom' => Str::lower(wc_attribute_label($cle, $produit)), 'nom' => Str::lower(wc_attribute_label($cle, $produit)),
'valeur' => $produit->get_attribute($cle), 'valeur' => $produit->get_attribute($cle),
]) ])
->toArray() ->toArray()
: [], : [],
'lien' => $produit->get_permalink(), 'lien' => $produit->get_permalink(),
'nom' => $produit->get_title(), 'nom' => $produit->get_title(),
'prix_total' => $article->get_total(), 'prix_total' => $article->get_total(),
'quantite' => $article->get_quantity(), 'quantite' => $article->get_quantity(),
]; ];
}), }),
'totaux' => [ 'totaux' => [
'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€', 'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€',
'sous_total_produits' => $commande->get_subtotal() . '€', 'sous_total_produits' => $commande->get_subtotal() . '€',
'sous_total_reduction' => '0.00' === $commande->get_discount_total() 'sous_total_reduction' => '0.00' === $commande->get_discount_total()
? '0' ? '0'
: Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€', : Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€',
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€', 'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€',
], ],
]; ];
// Transforme les codes de pays en noms de pays // Transforme les codes de pays en noms de pays
$email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()]; $email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()];
$email['adresses']['facturation']['country'] = WC()->countries->countries[$commande->get_billing_country()]; $email['adresses']['facturation']['country'] = WC()->countries->countries[$commande->get_billing_country()];
$context['commande'] = $email; $context['commande'] = $email;