12 Commits

25 changed files with 946 additions and 274 deletions

View File

@@ -39,6 +39,7 @@
"wpackagist-plugin/acf-extended": "*", "wpackagist-plugin/acf-extended": "*",
"wpackagist-plugin/clean-image-filenames": "*", "wpackagist-plugin/clean-image-filenames": "*",
"wpackagist-plugin/disable-comments": "*", "wpackagist-plugin/disable-comments": "*",
"wpackagist-plugin/media-focus-point": "*",
"wpackagist-plugin/seo-by-rank-math": "*", "wpackagist-plugin/seo-by-rank-math": "*",
"wpackagist-plugin/wp-graphql": "*", "wpackagist-plugin/wp-graphql": "*",
"wpackagist-plugin/wpgraphql-acf": "*" "wpackagist-plugin/wpgraphql-acf": "*"
@@ -47,4 +48,4 @@
"lewebsimple/wp-phpcs-ruleset": "*", "lewebsimple/wp-phpcs-ruleset": "*",
"squizlabs/php_codesniffer": "*" "squizlabs/php_codesniffer": "*"
} }
} }

30
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": "9673ea7f3e3f21866ae50f70e1d6a16b", "content-hash": "f563233465b6f95dac3c6b33962f6aed",
"packages": [ "packages": [
{ {
"name": "axepress/wp-graphql-plugin-boilerplate", "name": "axepress/wp-graphql-plugin-boilerplate",
@@ -419,16 +419,34 @@
"homepage": "https://wordpress.org/plugins/disable-comments/" "homepage": "https://wordpress.org/plugins/disable-comments/"
}, },
{ {
"name": "wpackagist-plugin/seo-by-rank-math", "name": "wpackagist-plugin/media-focus-point",
"version": "1.0.262", "version": "2.0.4",
"source": { "source": {
"type": "svn", "type": "svn",
"url": "https://plugins.svn.wordpress.org/seo-by-rank-math/", "url": "https://plugins.svn.wordpress.org/media-focus-point/",
"reference": "tags/1.0.262" "reference": "tags/2.0.4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://downloads.wordpress.org/plugin/seo-by-rank-math.1.0.262.zip" "url": "https://downloads.wordpress.org/plugin/media-focus-point.2.0.4.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"
},
"type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/media-focus-point/"
},
{
"name": "wpackagist-plugin/seo-by-rank-math",
"version": "1.0.263",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/seo-by-rank-math/",
"reference": "tags/1.0.263"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/seo-by-rank-math.1.0.263.zip"
}, },
"require": { "require": {
"composer/installers": "^1.0 || ^2.0" "composer/installers": "^1.0 || ^2.0"

View File

@@ -109,6 +109,102 @@
"acfe_flexible_render_script": false, "acfe_flexible_render_script": false,
"acfe_flexible_thumbnail": false, "acfe_flexible_thumbnail": false,
"acfe_flexible_category": false "acfe_flexible_category": false
},
"layout_697caf9a3e05b": {
"key": "layout_697caf9a3e05b",
"name": "hero_split",
"label": "Héro en moitié",
"display": "block",
"sub_fields": [
{
"key": "field_697cafb13e05d",
"label": "Content",
"name": "content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"tabs": "all",
"toolbar": "full",
"media_upload": 0,
"delay": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "content",
"graphql_non_null": 1
},
{
"key": "field_697cafc43e05e",
"label": "Media",
"name": "media",
"aria-label": "",
"type": "clone",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "media",
"clone": [
"group_abstract_media"
],
"display": "seamless",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large"
},
{
"key": "field_697cafdc3e05f",
"label": "Position de l'image",
"name": "reverse",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"message": "",
"default_value": 0,
"allow_in_bindings": 0,
"ui_on_text": "Gauche",
"ui_off_text": "Droite",
"ui": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "reverse",
"graphql_non_null": 1
}
],
"min": "",
"max": "",
"acfe_flexible_modal_edit_size": "",
"acfe_flexible_settings": "",
"acfe_flexible_settings_size": "large",
"acfe_flexible_render_template": false,
"acfe_flexible_render_style": false,
"acfe_flexible_render_script": false,
"acfe_flexible_thumbnail": false,
"acfe_flexible_category": false
} }
}, },
"min": "", "min": "",
@@ -152,5 +248,5 @@
"graphql_types": "", "graphql_types": "",
"acfe_meta": "", "acfe_meta": "",
"acfe_note": "", "acfe_note": "",
"modified": 1768358815 "modified": 1769779666
} }

View File

@@ -0,0 +1,123 @@
{
"key": "group_abstract_media",
"title": "Abstract - Media",
"fields": [
{
"key": "field_697caec68536d",
"label": "Image",
"name": "image",
"aria-label": "",
"type": "image",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "33",
"class": "",
"id": ""
},
"uploader": "",
"return_format": "array",
"library": "all",
"acfe_thumbnail": 0,
"min_width": "",
"min_height": "",
"min_size": "",
"max_width": "",
"max_height": "",
"max_size": "",
"mime_types": "",
"allow_in_bindings": 0,
"preview_size": "medium",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "image"
},
{
"key": "field_697caf018536e",
"label": "Ratio d'aspect",
"name": "aspect_ratio",
"aria-label": "",
"type": "button_group",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "33",
"class": "",
"id": ""
},
"choices": {
"square": "Carré (1:1)",
"video": "Vidéo (16:9)",
"portrait": "Portrait (2:3)",
"auto": "Aspect d'origine"
},
"default_value": "auto",
"return_format": "value",
"allow_null": 0,
"allow_in_bindings": 0,
"layout": "horizontal",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "aspectRatio",
"graphql_non_null": 1
},
{
"key": "field_697caf378536f",
"label": "Ajustement de l'image",
"name": "object_fit",
"aria-label": "",
"type": "button_group",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "33",
"class": "",
"id": ""
},
"choices": {
"cover": "Recadrer si nécessaire",
"contain": "Contenir sans recadrage"
},
"default_value": "cover",
"return_format": "value",
"allow_null": 0,
"allow_in_bindings": 0,
"layout": "horizontal",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "objectFit",
"graphql_non_null": 1
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "seamless",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"display_title": "",
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"show_in_graphql": 1,
"graphql_field_name": "GroupAbstractMedia",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1769779078
}

View File

@@ -0,0 +1,4 @@
<svg version="1.1" viewBox="0 0 490.3 86.763" xmlns="http://www.w3.org/2000/svg">
<path d="m10.344 1.5312a10.208 10.208 0 0 0-9.0195 15.207l36.1 64.801a10.2 10.2 0 0 0 13.9 3.9004 10.415 10.415 0 0 0 4-14l-36.201-64.701a10.208 10.208 0 0 0-8.7793-5.207zm221.33 12.51v51.84h11.52v-2.8789a16.277 16.277 0 0 0 11.232 3.959c9.576 0 17.641-7.7004 17.641-19.152 0-11.376-8.0656-19.152-17.641-19.152a16.277 16.277 0 0 0-11.232 3.9609v-18.576h-11.52zm206 0v51.84h11.52v-51.84h-11.52zm-127.3 0.070312v11.145h11.521v-11.145h-11.521zm-21.229 14.535c-8.6942-0.004836-14.866 4.5403-15.109 11.721-0.193 5.685 3.5014 9.4123 10.15 10.863l7.291 1.6875c2.645 0.594 3.5488 1.5612 3.5078 2.7852-0.054 1.583-1.7534 2.8227-4.7754 2.7207-3.094-0.105-5.8618-1.3519-6.2598-4.4629l-11.305 1.9199c0.972 7.453 8.133 10.795 16.625 11.084 9.5 0.322 16.549-3.6186 16.82-11.602 0.181-5.325-2.8478-9.5341-9.6348-11.205l-8.4316-2.0137c-2.286-0.582-2.6824-1.6003-2.6484-2.6113 0.044-1.295 1.0992-2.773 4.1992-2.668 3.526 0.12 5.6164 2.2082 5.9004 4.4512l10.574-1.7363c-1.227-6.309-7.0597-10.613-16.055-10.918-0.28559-0.009687-0.56915-0.015469-0.84961-0.015625zm-79.43 0.009766c-10.512 0-19.152 7.7764-19.152 19.152 0 11.448 8.6401 19.152 19.08 19.152 8.28 0 14.832-3.6728 17.928-11.301l-10.225-2.0879c-1.944 3.528-5.0392 4.1758-7.6992 4.1758-3.888 0-6.8414-2.6624-7.7774-6.9824h26.5v-2.957h-0.00781c-0.216-11.808-8.4225-19.152-18.646-19.152zm140.62 0a13.682 13.682 0 0 0-10.656 4.3926v-3.3125h-11.52v36.145h11.52v-17.711c0-6.048 2.7361-9.1445 6.9121-9.1445 3.456 0 6.1191 2.5912 6.1191 6.6992v20.156h11.521v-17.711c0-6.048 2.8067-9.1445 7.0547-9.1445 3.384 0 6.0488 2.5912 6.0488 6.6992v20.156h11.447v-22.607c0-8.784-6.1202-14.617-13.824-14.617a15.58 15.58 0 0 0-12.814 6.1211c-2.448-3.96-6.7686-6.1211-11.809-6.1211zm66.391 0a16.277 16.277 0 0 0-11.232 3.9609v-2.8809h-11.52v48.385h11.52v-15.119a16.277 16.277 0 0 0 11.232 3.959c9.576 0 17.639-7.7004 17.639-19.152 0-11.376-8.0627-19.152-17.639-19.152zm54.936 0c-10.512 0-19.15 7.7764-19.15 19.152 0 11.448 8.6381 19.152 19.078 19.152 8.28 0 14.834-3.6728 17.93-11.301l-10.225-2.0879c-1.944 3.528-5.0392 4.1758-7.6992 4.1758-3.888 0-6.8414-2.6624-7.7774-6.9824h26.5v-2.957h-0.00781c-0.216-11.808-8.4244-19.152-18.648-19.152zm-336.16 1.0801 11.592 36.217h10.008l6.5527-19.584 6.4805 19.584h10.008l11.576-36.217h-11.301l-5.9004 19.512-6.8398-19.512h-8.1367l-6.8398 19.441-5.8984-19.441h-11.301zm174.88 0v36.145h11.521v-36.145h-11.521zm-100.66 8.2812a7.221 7.221 0 0 1 7.2715 5.6875h-14.9a7.918 7.918 0 0 1 7.6289-5.6875zm261.94 0a7.221 7.221 0 0 1 7.2715 5.6875h-14.9a7.918 7.918 0 0 1 7.6289-5.6875zm-219.6 0.43164c5.04 0 8.7109 3.8154 8.7109 9.3594 0 5.616-3.6709 9.3613-8.7109 9.3613a8.972 8.972 0 0 1-8.8574-9.3613 9.016 9.016 0 0 1 8.8574-9.3594zm162.29 0c5.04 0 8.7129 3.8154 8.7129 9.3594 0 5.616-3.6729 9.3613-8.7129 9.3613a8.972 8.972 0 0 1-8.8555-9.3613 9.016 9.016 0 0 1 8.8555-9.3594z" fill="#212121"/>
<path d="m123.02 1.939-.7-.5a9.735 9.735 0 0 0-13.4 3.2l-29.1 47.3a2.253 2.253 0 0 1-3.9-.1l-11.3-20.3a9.82 9.82 0 0 0-13.3-3.8l-.8.4a9.82 9.82 0 0 0-3.8 13.3l21.8 39a9.983 9.983 0 0 0 8.3 5 9.83 9.83 0 0 0 9.1-4.6l40.4-65.6a9.668 9.668 0 0 0-3.3-13.3" fill="#0ad2b7" data-name="Tracé 22516"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,9 @@
fragment AcfImage on MediaItem {
src: sourceUrl
alt: altText
mediaDetails {
width
height
}
objectPosition
}

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import type { AcfImageFragment } from "#graphql/operations";
defineProps<{ image?: AcfImageFragment }>();
</script>
<template>
<NuxtImg
v-if="image"
:src="image.src"
:alt="image.alt"
:width="image.mediaDetails?.width"
:height="image.mediaDetails?.height"
:style="{ objectPosition: image.objectPosition || 'center' }"
format="avif,webp"
placeholder
/>
</template>

View File

@@ -0,0 +1,9 @@
fragment AcfMedia on GroupAbstractMedia_Fields {
image {
node {
...AcfImage
}
}
aspectRatio
objectFit
}

View File

@@ -0,0 +1,36 @@
<script setup lang="ts">
import { tv, type VariantProps } from "tailwind-variants";
import type { AcfMediaFragment } from "#graphql/operations";
const tvAcfMedia = tv({
slots: {
image: "w-full",
},
variants: {
aspectRatio: {
square: { image: "aspect-[1/1]" },
video: { image: "aspect-video" },
portrait: { image: "aspect-[2/3]" },
auto: { image: "aspect-auto" },
},
objectFit: {
cover: { image: "object-cover" },
contain: { image: "object-contain" },
},
},
defaultVariants: {
aspectRatio: "auto",
objectFit: "cover",
},
});
const props = defineProps<{ media?: AcfMediaFragment }>();
const classes = tvAcfMedia({
aspectRatio: props.media?.aspectRatio,
objectFit: props.media?.objectFit,
} as VariantProps<typeof tvAcfMedia>);
</script>
<template>
<AcfImage v-if="media?.image?.node" :image="media.image.node" :class="classes.image()" />
</template>

View File

@@ -1,8 +1,7 @@
fragment BuilderSections on GroupAbstractBuilder_Fields { fragment BuilderSections on GroupAbstractBuilder_Fields {
sections { sections {
__typename __typename
... on GroupAbstractBuilderSectionsTextBlockLayout { ... on GroupAbstractBuilderSectionsHeroSplitLayout { ... SectionHeroSplit }
... SectionTextBlock ... on GroupAbstractBuilderSectionsTextBlockLayout { ... SectionTextBlock }
}
} }
} }

View File

@@ -0,0 +1,6 @@
fragment SectionHeroSplit on GroupAbstractBuilderSectionsHeroSplitLayout {
content
reverse
...AcfMedia
}

View File

@@ -0,0 +1,40 @@
<script setup lang="ts">
import { tv, type VariantProps } from "tailwind-variants";
import type { SectionHeroSplitFragment } from "#graphql/operations";
const tvSectionHeroSplit = tv({
slots: {
base: "py-6",
container: "container flex flex-col gap-6 items-center",
content: "flex-1",
media: "w-full basis-1/2",
},
variants: {
reverse: {
false: {
container: "lg:flex-row",
},
true: {
container: "lg:flex-row-reverse",
},
},
},
defaultVariants: {
reverse: false,
},
});
const props = defineProps<SectionHeroSplitFragment>();
const classes = tvSectionHeroSplit({
reverse: props.reverse,
} as VariantProps<typeof tvSectionHeroSplit>);
</script>
<template>
<section :class="classes.base()">
<div :class="classes.container()">
<UiProse :content="content" :class="classes.content()" />
<AcfMedia :media="$props" :class="classes.media()" />
</div>
</section>
</template>

View File

@@ -1,9 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
const title = "Moonshine";
</script> </script>
<template> <template>
<UHeader :title="title"> <UHeader mode="slideover">
<template #left>
<NuxtLink to="/">
<SvgSiteLogo class="h-12 w-auto" />
</NuxtLink>
</template>
<template #right> <template #right>
<AuthConnexionButton /> <AuthConnexionButton />
</template> </template>

View File

@@ -1,10 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
// Resolve Node component from URI // Fetch node by URI and handle query errors
const { path: uri } = useRoute(); const { path: uri } = useRoute();
const { data } = await useAsyncGraphQLQuery("NodeByUri", { uri }); const { data, error } = await useAsyncGraphQLQuery("NodeByUri", { uri });
if (!data.value?.nodeByUri) { if (!data.value?.nodeByUri) {
console.error("NodeByUri query error:", error.value);
throw createError({ statusCode: 404, message: `La page demandée est introuvable: ${uri}`, fatal: true }); throw createError({ statusCode: 404, message: `La page demandée est introuvable: ${uri}`, fatal: true });
} }
// Dynamically resolve component based on node type
const componentName = `Node${data.value.nodeByUri.__typename}`; const componentName = `Node${data.value.nodeByUri.__typename}`;
if (!useNuxtApp().vueApp.component(componentName)) { if (!useNuxtApp().vueApp.component(componentName)) {
throw createError({ statusCode: 404, message: `La page demandée ne peut pas être affichée correctement: ${componentName}`, fatal: true }); throw createError({ statusCode: 404, message: `La page demandée ne peut pas être affichée correctement: ${componentName}`, fatal: true });

View File

@@ -10,4 +10,5 @@ require_once __DIR__ . '/includes/vendors/tinymce.php';
require_once __DIR__ . '/includes/vendors/wpgraphql.php'; require_once __DIR__ . '/includes/vendors/wpgraphql.php';
// WPGraphQL // WPGraphQL
require_once __DIR__ . '/includes/wpgraphql/media-focus-point.php';
require_once __DIR__ . '/includes/wpgraphql/term-connection.php'; require_once __DIR__ . '/includes/wpgraphql/term-connection.php';

View File

@@ -0,0 +1,17 @@
<?php
// Expose 'bg_pos_desktop' post meta on MediaItem type in WPGraphQL
add_action( 'graphql_register_types', 'leblanc_graphql_register_media_focus_point' );
function leblanc_graphql_register_media_focus_point() {
register_graphql_field(
'MediaItem',
'objectPosition',
array(
'type' => 'String',
'description' => 'CSS object-position value from Media Focus Point plugin',
'resolve' => static function ( $media_item ) {
return get_post_meta( $media_item->databaseId, 'bg_pos_desktop', true );
},
)
);
}

View File

@@ -1,24 +1,2 @@
<?php <?php
return array( return ['project-id-version'=>'Moonshine','report-msgid-bugs-to'=>'','pot-creation-date'=>'2026-01-13 15:52+0000','po-revision-date'=>'2026-01-29 02:55+0000','last-translator'=>'','language-team'=>'Français du Canada','language'=>'fr_CA','plural-forms'=>'nplurals=2; plural=n > 1;','mime-version'=>'1.0','content-type'=>'text/plain; charset=UTF-8','content-transfer-encoding'=>'8bit','x-generator'=>'Loco https://localise.biz/','x-loco-version'=>'2.8.1; wp-6.9; php-8.3.27','x-domain'=>'moonshine','messages'=>['Heading styles'=>'Styles de titres','Headless WordPress theme based on Nuxt.'=>'Thème Wordpress headless basé sur Nuxt.','https://websimple.com/'=>'https://websimple.com/','Inline styles'=>'Styles de caractères','Link styles'=>'Styles de liens','Main menu'=>'Menu principal','Moonshine'=>'Moonshine','Paragraph styles'=>'Styles de paragraphes','Pascal Martineau '=>'Pascal Martineau ','Semi-bold'=>'Semi-gras']];
'project-id-version' => 'Moonshine',
'report-msgid-bugs-to' => '',
'pot-creation-date' => '2026-01-13 15:52+0000',
'po-revision-date' => '2026-01-13 15:53+0000',
'last-translator' => '',
'language-team' => 'Français du Canada',
'language' => 'fr_CA',
'plural-forms' => 'nplurals=2; plural=n > 1;',
'mime-version' => '1.0',
'content-type' => 'text/plain; charset=UTF-8',
'content-transfer-encoding' => '8bit',
'x-generator' => 'Loco https://localise.biz/',
'x-loco-version' => '2.8.1; wp-6.9; php-8.3.27',
'x-domain' => 'moonshine',
'messages' => array(
'Headless WordPress theme based on Nuxt.' => 'Thème Wordpress headless basé sur Nuxt.',
'https://websimple.com/' => 'https://websimple.com/',
'Main menu' => 'Menu principal',
'Moonshine' => 'Moonshine',
'Pascal Martineau ' => 'Pascal Martineau ',
),
);

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: Moonshine\n" "Project-Id-Version: Moonshine\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-13 15:52+0000\n" "POT-Creation-Date: 2026-01-13 15:52+0000\n"
"PO-Revision-Date: 2026-01-13 15:53+0000\n" "PO-Revision-Date: 2026-01-29 02:55+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Français du Canada\n" "Language-Team: Français du Canada\n"
"Language: fr_CA\n" "Language: fr_CA\n"
@@ -15,6 +15,10 @@ msgstr ""
"X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n" "X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n"
"X-Domain: moonshine" "X-Domain: moonshine"
#: includes/vendors/tinymce.php:54
msgid "Heading styles"
msgstr "Styles de titres"
#. Description of the theme #. Description of the theme
msgid "Headless WordPress theme based on Nuxt." msgid "Headless WordPress theme based on Nuxt."
msgstr "Thème Wordpress headless basé sur Nuxt." msgstr "Thème Wordpress headless basé sur Nuxt."
@@ -23,6 +27,14 @@ msgstr "Thème Wordpress headless basé sur Nuxt."
msgid "https://websimple.com/" msgid "https://websimple.com/"
msgstr "https://websimple.com/" msgstr "https://websimple.com/"
#: includes/vendors/tinymce.php:34
msgid "Inline styles"
msgstr "Styles de caractères"
#: includes/vendors/tinymce.php:24
msgid "Link styles"
msgstr "Styles de liens"
#: includes/core/theme-setup.php:15 #: includes/core/theme-setup.php:15
msgid "Main menu" msgid "Main menu"
msgstr "Menu principal" msgstr "Menu principal"
@@ -31,6 +43,14 @@ msgstr "Menu principal"
msgid "Moonshine" msgid "Moonshine"
msgstr "Moonshine" msgstr "Moonshine"
#: includes/vendors/tinymce.php:44
msgid "Paragraph styles"
msgstr "Styles de paragraphes"
#. Author of the theme #. Author of the theme
msgid "Pascal Martineau " msgid "Pascal Martineau "
msgstr "Pascal Martineau " msgstr "Pascal Martineau "
#: includes/vendors/tinymce.php:37
msgid "Semi-bold"
msgstr "Semi-gras"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Moonshine\n" "Project-Id-Version: Moonshine\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-13 15:52+0000\n" "POT-Creation-Date: 2026-01-29 02:55+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: \n" "Language-Team: \n"
@@ -16,6 +16,10 @@ msgstr ""
"X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n" "X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n"
"X-Domain: moonshine" "X-Domain: moonshine"
#: includes/vendors/tinymce.php:54
msgid "Heading styles"
msgstr ""
#. Description of the theme #. Description of the theme
msgid "Headless WordPress theme based on Nuxt." msgid "Headless WordPress theme based on Nuxt."
msgstr "" msgstr ""
@@ -24,6 +28,14 @@ msgstr ""
msgid "https://websimple.com/" msgid "https://websimple.com/"
msgstr "" msgstr ""
#: includes/vendors/tinymce.php:34
msgid "Inline styles"
msgstr ""
#: includes/vendors/tinymce.php:24
msgid "Link styles"
msgstr ""
#: includes/core/theme-setup.php:15 #: includes/core/theme-setup.php:15
msgid "Main menu" msgid "Main menu"
msgstr "" msgstr ""
@@ -32,6 +44,14 @@ msgstr ""
msgid "Moonshine" msgid "Moonshine"
msgstr "" msgstr ""
#: includes/vendors/tinymce.php:44
msgid "Paragraph styles"
msgstr ""
#. Author of the theme #. Author of the theme
msgid "Pascal Martineau " msgid "Pascal Martineau "
msgstr "" msgstr ""
#: includes/vendors/tinymce.php:37
msgid "Semi-bold"
msgstr ""

View File

@@ -1,5 +1,7 @@
import { version } from "./package.json"; import { version } from "./package.json";
const isDev = process.env.NODE_ENV !== "production";
const siteUrl = process.env.NUXT_SITE_URL; const siteUrl = process.env.NUXT_SITE_URL;
if (!siteUrl) { if (!siteUrl) {
throw new Error(`NUXT_SITE_URL is not defined. Make sure to set it in your build environment variables.`); throw new Error(`NUXT_SITE_URL is not defined. Make sure to set it in your build environment variables.`);
@@ -9,6 +11,7 @@ const wpUrl = process.env.NUXT_WP_URL;
if (!wpUrl) { if (!wpUrl) {
throw new Error(`NUXT_WP_URL is not defined. Make sure to set it in your build environment variables.`); throw new Error(`NUXT_WP_URL is not defined. Make sure to set it in your build environment variables.`);
} }
const wpDomain = new URL(wpUrl).hostname;
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({ export default defineNuxtConfig({
@@ -16,6 +19,7 @@ export default defineNuxtConfig({
modules: [ modules: [
"@lewebsimple/nuxt-graphql", "@lewebsimple/nuxt-graphql",
"@nuxt/eslint", "@nuxt/eslint",
"@nuxt/image",
"@nuxt/ui", "@nuxt/ui",
"@nuxtjs/device", "@nuxtjs/device",
"@nuxtjs/seo", "@nuxtjs/seo",
@@ -103,6 +107,11 @@ export default defineNuxtConfig({
}, },
}, },
image: {
...isDev ? {} : { provider: "cloudflare", cloudflare: { baseURL: "/" } },
domains: [wpDomain],
},
robots: { robots: {
sitemap: `${wpUrl}/sitemap_index.xml`, sitemap: `${wpUrl}/sitemap_index.xml`,
}, },
@@ -114,5 +123,4 @@ export default defineNuxtConfig({
componentPrefix: "Svg", componentPrefix: "Svg",
defaultImport: "component", defaultImport: "component",
}, },
}); });

View File

@@ -16,7 +16,8 @@
}, },
"dependencies": { "dependencies": {
"@iconify-json/lucide": "^1.2.87", "@iconify-json/lucide": "^1.2.87",
"@lewebsimple/nuxt-graphql": "^0.6.6", "@lewebsimple/nuxt-graphql": "^0.6.7",
"@nuxt/image": "^2.0.0",
"@nuxt/ui": "4.3.0", "@nuxt/ui": "4.3.0",
"@nuxtjs/device": "4.0.0", "@nuxtjs/device": "4.0.0",
"@nuxtjs/seo": "^3.4.0", "@nuxtjs/seo": "^3.4.0",
@@ -35,7 +36,7 @@
"eslint": "^9.39.2", "eslint": "^9.39.2",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vue-tsc": "^3.2.4", "vue-tsc": "^3.2.4",
"wrangler": "^4.61.0" "wrangler": "^4.61.1"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,19 @@ interface AcfFieldGroupFields {
fieldGroupName: String @deprecated(reason: "Use __typename instead") fieldGroupName: String @deprecated(reason: "Use __typename instead")
} }
"""
Connection between the GroupAbstractBuilderSectionsHeroSplitLayout_Fields type and the MediaItem type
"""
type AcfMediaItemConnectionEdge implements Edge & MediaItemConnectionEdge & OneToOneConnection {
"""
Opaque reference to the nodes position in the connection. Value can be used with pagination args.
"""
cursor: String
"""The node of the connection, without the edges"""
node: MediaItem!
}
"""Options Page registered by ACF""" """Options Page registered by ACF"""
interface AcfOptionsPage implements Node { interface AcfOptionsPage implements Node {
"""The globally unique ID for the object""" """The globally unique ID for the object"""
@@ -3399,6 +3412,72 @@ type GroupAbstractBuilder implements AcfFieldGroup & AcfFieldGroupFields & Group
sections: [GroupAbstractBuilderSections_Layout] sections: [GroupAbstractBuilderSections_Layout]
} }
"""
The &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;.
"""
type GroupAbstractBuilderSectionsHeroSplitLayout implements AcfFieldGroup & AcfFieldGroupFields & GroupAbstractBuilderSectionsHeroSplitLayout_Fields & GroupAbstractBuilderSections_Layout & GroupAbstractMedia_Fields {
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
aspectRatio: String!
"""
Field of the &quot;wysiwyg&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
content: String!
"""The name of the field group"""
fieldGroupName: String @deprecated(reason: "Use __typename instead")
"""
Field of the &quot;image&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
image: AcfMediaItemConnectionEdge
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
objectFit: String!
"""
Field of the &quot;true_false&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
reverse: Boolean!
}
"""
Interface representing fields of the ACF &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
interface GroupAbstractBuilderSectionsHeroSplitLayout_Fields implements AcfFieldGroup & AcfFieldGroupFields & GroupAbstractBuilderSections_Layout & GroupAbstractMedia_Fields {
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
aspectRatio: String!
"""
Field of the &quot;wysiwyg&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
content: String!
"""The name of the field group"""
fieldGroupName: String @deprecated(reason: "Use __typename instead")
"""
Field of the &quot;image&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
image: AcfMediaItemConnectionEdge
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
objectFit: String!
"""
Field of the &quot;true_false&quot; Field Type added to the schema as part of the &quot;GroupAbstractBuilderSectionsHeroSplitLayout&quot; Field Group
"""
reverse: Boolean!
}
""" """
The &quot;GroupAbstractBuilderSectionsLayoutSettings&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;. The &quot;GroupAbstractBuilderSectionsLayoutSettings&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;.
""" """
@@ -3487,6 +3566,52 @@ interface GroupAbstractBuilder_Fields implements AcfFieldGroup & AcfFieldGroupFi
sections: [GroupAbstractBuilderSections_Layout] sections: [GroupAbstractBuilderSections_Layout]
} }
"""
The &quot;GroupAbstractMedia&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;.
"""
type GroupAbstractMedia implements AcfFieldGroup & AcfFieldGroupFields & GroupAbstractMedia_Fields {
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
aspectRatio: String!
"""The name of the field group"""
fieldGroupName: String @deprecated(reason: "Use __typename instead")
"""
Field of the &quot;image&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
image: AcfMediaItemConnectionEdge
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
objectFit: String!
}
"""
Interface representing fields of the ACF &quot;GroupAbstractMedia&quot; Field Group
"""
interface GroupAbstractMedia_Fields implements AcfFieldGroup & AcfFieldGroupFields {
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
aspectRatio: String!
"""The name of the field group"""
fieldGroupName: String @deprecated(reason: "Use __typename instead")
"""
Field of the &quot;image&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
image: AcfMediaItemConnectionEdge
"""
Field of the &quot;button_group&quot; Field Type added to the schema as part of the &quot;GroupAbstractMedia&quot; Field Group
"""
objectFit: String!
}
""" """
The &quot;GroupLayoutContained&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;. The &quot;GroupLayoutContained&quot; Field Group. Added to the Schema by &quot;WPGraphQL for ACF&quot;.
""" """
@@ -4602,6 +4727,9 @@ type MediaItem implements ContentNode & DatabaseIdentifier & HierarchicalContent
""" """
modifiedGmt: String modifiedGmt: String
"""CSS object-position value from Media Focus Point plugin"""
objectPosition: String
"""The parent of the node. The parent object can be of various types""" """The parent of the node. The parent object can be of various types"""
parent: HierarchicalContentNodeToParentContentNodeConnectionEdge parent: HierarchicalContentNodeToParentContentNodeConnectionEdge
@@ -15623,6 +15751,9 @@ enum UserRoleEnum {
"""User role with specific capabilities""" """User role with specific capabilities"""
SUBSCRIBER SUBSCRIBER
"""User role with specific capabilities"""
TRANSLATOR
} }
"""Connection between the User type and the Comment type""" """Connection between the User type and the Comment type"""

View File

@@ -40,15 +40,35 @@ function getAuthUser(user: AuthUserFragment): User {
}; };
} }
// Track in-flight refreshAuthToken calls to prevent duplicate requests
const refreshTokenPromises = new Map<string, Promise<string | undefined>>();
// Refresh auth token by calling remote GraphQL endpoint directly // Refresh auth token by calling remote GraphQL endpoint directly
export async function refreshAuthToken(refreshToken: string): Promise<string | undefined> { export async function refreshAuthToken(refreshToken: string): Promise<string | undefined> {
const { public: { wpUrl } } = useRuntimeConfig(); // Return existing in-flight promise if available
const endpoint = `${wpUrl}/graphql`; const inFlight = refreshTokenPromises.get(refreshToken);
const { data } = await executeGraphQLHTTP<ResultOf<"AuthRefreshToken">>({ if (inFlight) {
query: AuthRefreshTokenDocument, return inFlight;
variables: { refreshToken }, }
}, { endpoint });
return data?.refreshToken?.authToken || undefined; const refreshPromise = (async () => {
const { wpUrl } = useRuntimeConfig();
const endpoint = `${wpUrl}/graphql`;
const { data } = await executeGraphQLHTTP<ResultOf<"AuthRefreshToken">>({
query: AuthRefreshTokenDocument,
variables: { refreshToken },
}, { endpoint });
return data?.refreshToken?.authToken || undefined;
})();
refreshTokenPromises.set(refreshToken, refreshPromise);
return refreshPromise.finally(() => {
const current = refreshTokenPromises.get(refreshToken);
if (current === refreshPromise) {
refreshTokenPromises.delete(refreshToken);
}
});
} }
// Get auth token from user session (refresh if needed) // Get auth token from user session (refresh if needed)