74 Commits

Author SHA1 Message Date
193b357d9c chore(release): v0.1.14
All checks were successful
Deployment / wordpress (push) Successful in 7s
Deployment / nuxt (push) Successful in 1m5s
2026-02-11 09:56:09 -05:00
470857305b minor: update editor-style.css 2026-02-11 09:55:51 -05:00
431433a3a0 minor: format code 2026-02-11 09:53:54 -05:00
b0c5e4c20f fix: Abstract social profiles should not be non-null
All checks were successful
Deployment / wordpress (push) Successful in 9s
Deployment / nuxt (push) Successful in 1m7s
2026-02-11 09:53:31 -05:00
2304d855b7 minor: site footer, auth connextion, input w-full 2026-02-11 09:26:21 -05:00
b45d3a02f0 chore: update deps 2026-02-11 09:25:29 -05:00
e9d6ca2f96 feat: UiLoadMore 2026-02-11 09:24:41 -05:00
fc6168e5a4 feat: auth middleware 2026-02-11 09:24:19 -05:00
3ec98fdc2d feat: useLayoutWrapper 2026-02-11 09:24:05 -05:00
71a48de945 feat: project.code-workspace 2026-02-11 09:11:11 -05:00
289b777cad chore: update plugins 2026-02-11 09:05:46 -05:00
18306c28b9 chore: update plugins / deps
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 1m0s
2026-02-04 21:53:39 -05:00
36e7d8ad8b chore: update oxlint / oxfmt settings 2026-02-04 13:31:08 -05:00
fdf32bbc78 feat: VSCode launch configurations 2026-02-03 09:19:08 -05:00
2c44d8137c chore: update deps
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 57s
2026-02-03 08:03:05 -05:00
db831700f0 fix: Wrangler config
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 56s
2026-02-01 22:47:21 -05:00
9bb09b89d9 feat: Replace eslint => oxlint + oxfmt
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 58s
2026-02-01 22:06:16 -05:00
58dbcdd25a chore(release): v0.1.13
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 57s
2026-02-01 21:17:39 -05:00
8ae6dafb62 feat: TinyMCE list style
Some checks failed
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Has been cancelled
2026-02-01 21:17:21 -05:00
faf39ca182 fix: wrangler.json needed for wrangler types before build
All checks were successful
Deployment / wordpress (push) Successful in 7s
Deployment / nuxt (push) Successful in 1m2s
2026-02-01 21:09:51 -05:00
8d350bb092 chore(release): v0.1.12
Some checks failed
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Failing after 9s
2026-01-30 16:31:44 -05:00
4338028c60 feat: Event context type for Cloudflare environment
Some checks failed
Deployment / wordpress (push) Successful in 5s
Deployment / nuxt (push) Has been cancelled
2026-01-30 16:31:29 -05:00
ab563a7b37 feat: parseAcfMedia
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 1m1s
2026-01-30 15:50:06 -05:00
2cfc1a0047 feat: parseAcfLink 2026-01-30 15:43:49 -05:00
98e8d971e8 feat: showLabel 2026-01-30 15:43:37 -05:00
87be06ecea feat: connexionButton 2026-01-30 15:39:32 -05:00
28f6e1ae7c fix: UApp in app.vue 2026-01-30 15:39:19 -05:00
27380290e1 chore(release): v0.1.11
All checks were successful
Deployment / wordpress (push) Successful in 5s
Deployment / nuxt (push) Successful in 56s
2026-01-30 14:38:25 -05:00
7e44554767 chore: Update deps
Some checks failed
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Has been cancelled
2026-01-30 14:38:11 -05:00
9c3dceef84 fix: ENABLE_CLOUDFLARE_IMAGE
All checks were successful
Deployment / wordpress (push) Successful in 5s
Deployment / nuxt (push) Successful in 53s
2026-01-30 14:35:21 -05:00
ba8d8e00a8 chore: Update README.md
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 59s
2026-01-30 14:29:26 -05:00
8f037b5950 fix: wrangler project name
All checks were successful
Deployment / wordpress (push) Successful in 6s
Deployment / nuxt (push) Successful in 57s
2026-01-30 14:13:21 -05:00
291fa6eaa4 fix: Cloudflare image provider only in production 2026-01-30 12:20:30 -05:00
4079e4ecfb minor: configure image formats in nuxt.config.ts 2026-01-30 12:10:30 -05:00
eea020b136 fix: remove unneeded wrangler main / assets 2026-01-30 11:51:03 -05:00
5161bff624 minor: typo in component name 2026-01-30 11:50:37 -05:00
3199835e83 feat: AcfSocial / parseAcfSocial 2026-01-30 11:45:39 -05:00
6dd13ead91 feat: mapSocialIcon 2026-01-30 11:18:10 -05:00
980c5271ac chore(release): v0.1.10 2026-01-30 10:42:03 -05:00
115a5d2d38 feat: AcfLink / AcfLinkButton components 2026-01-30 10:24:06 -05:00
6b17201f60 feat: AcfPhone component 2026-01-30 10:05:49 -05:00
ad3c53c5dd feat: GroupSiteOptions.phoneNumber 2026-01-30 10:03:27 -05:00
fefa98021b refactor: OptionsSite => SiteOptions for clearer naming 2026-01-30 08:58:28 -05:00
1e58b1f1e7 chore(release): v0.1.9 2026-01-30 08:50:31 -05:00
0bafc3a9dd feat: HeroSplit section 2026-01-30 08:49:03 -05:00
8bd544b5c3 feat: AcfMedia component (image + aspect + object-fit) 2026-01-30 08:48:45 -05:00
4918c638ab feat: AcfImage component based on @nuxt/image 2026-01-30 08:48:27 -05:00
bff7bce1f1 feat: Media Focus Point plugin integration 2026-01-30 08:48:00 -05:00
0fbd2bf7ac feat: Initial Media / HeroSplit acf groups 2026-01-30 08:24:33 -05:00
238aa29bd4 feat: Default site-logo.svg 2026-01-30 08:24:14 -05:00
f268bdc3c3 chore: update deps 2026-01-30 08:14:03 -05:00
11641a00d1 minor: Cleaner [...uri].vue error handling 2026-01-29 08:32:41 -05:00
6a5d60e34c chore: Update theme translations 2026-01-28 21:55:55 -05:00
80e6555c88 chore: update seo-by-rank-math 2026-01-28 21:53:48 -05:00
ff866e2078 chore: update nuxt-graphql 0.6.7 2026-01-28 21:51:45 -05:00
5e39b53a44 feat: enhance refreshAuthToken to prevent duplicate requests 2026-01-28 21:50:58 -05:00
2d93d44a93 chore(release): v0.1.8
Some checks failed
Deployment / wordpress (push) Failing after 2s
Deployment / nuxt (push) Failing after 9s
2026-01-28 21:14:24 -05:00
ec64a42c2e chore: update pnpm-lock.yaml
Some checks failed
Deployment / wordpress (push) Failing after 2s
Deployment / nuxt (push) Has been cancelled
2026-01-28 21:14:12 -05:00
5f9c29c39a feat: Configure nuxt-svgo module 2026-01-28 21:13:49 -05:00
27f4f73148 fix: update nuxt-graphql and extractNodes typing (maybe => undefined instead of null) 2026-01-28 21:13:31 -05:00
21a7036ef5 feat: all of wrangler config in nuxt.config.ts 2026-01-28 21:12:43 -05:00
b1b1aa47c9 feat: graphql cache keyPrefix from package.json version 2026-01-28 21:11:48 -05:00
54fea5f64a minor: placeholder include for rankmath logic 2026-01-28 21:10:43 -05:00
a27e6af5db fix: term_order and default WPGraphQL settings 2026-01-28 21:10:26 -05:00
2c86905c91 fix: use public wpUrl runtime config for auth refresh token mutation 2026-01-28 21:09:37 -05:00
065b729a2f minor: better wp remote executor hooks 2026-01-28 21:08:58 -05:00
c82bf47e98 feat: useResponsive with device detection on SSR 2026-01-28 21:08:27 -05:00
51f594baa5 fix: headless_home_url needs to be in mu-plugins 2026-01-28 21:07:51 -05:00
3e56ba7eb3 minor: update schema.graphql 2026-01-28 08:34:44 -05:00
aaea0b062a chore(release): v0.1.7
Some checks failed
Deployment / wordpress (push) Failing after 1s
Deployment / nuxt (push) Failing after 8s
2026-01-27 20:25:04 -05:00
b886585be1 feat: Display theme version in admin footer
Some checks failed
Deployment / wordpress (push) Failing after 1s
Deployment / nuxt (push) Has been cancelled
2026-01-27 20:24:55 -05:00
c6dfbeb247 feat: Deploy to Cloudflare workers
Some checks failed
Deployment / wordpress (push) Failing after 1s
Deployment / nuxt (push) Failing after 7s
2026-01-27 19:59:34 -05:00
a1a8114f49 chore: update wp-graphql 2.7.0 2026-01-27 18:56:12 -05:00
63f8e443cf feat: Configure sitemap URL in robots.txt 2026-01-26 12:06:20 -05:00
121 changed files with 4765 additions and 19776 deletions

View File

@@ -0,0 +1,56 @@
name: Deployment
run-name: ${{ gitea.actor }} deploying ${{ gitea.repository.name }}
on: [push]
env:
NUXT_PROJECT_PATH: wp-content/themes/moonshine
PNPM_STORE_DIR: /cache/wp-scripts/pnpm
jobs:
wordpress:
runs-on: ubuntu-websimple
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install WordPress scripts
env:
TEMPLATES_REPO_TOKEN: ${{ secrets.TEMPLATES_REPO_TOKEN }}
run: |
git clone https://$TEMPLATES_REPO_TOKEN@gitea.websimple.com/templates/wp-scripts.git /tmp/wp-scripts
- name: Run deployment script
env:
REMOTE_HOST: ${{ vars.REMOTE_HOST }}
REMOTE_PORT: ${{ vars.REMOTE_PORT }}
REMOTE_USER: ${{ vars.REMOTE_USER }}
REMOTE_PATH: ${{ vars.REMOTE_PATH }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: /tmp/wp-scripts/wp-deploy.sh --skip-node
nuxt:
runs-on: ubuntu-websimple
defaults:
run:
working-directory: ${{ env.NUXT_PROJECT_PATH }}
env:
NUXT_SITE_ENV: ${{ vars.NUXT_SITE_ENV }}
NUXT_SITE_URL: ${{ vars.NUXT_SITE_URL }}
NUXT_WP_URL: ${{ vars.NUXT_WP_URL }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Node.js dependencies
run: pnpm install --frozen-lockfile --store-dir $PNPM_STORE_DIR
- name: Build Nuxt project
run: pnpm build
- name: Deploy to Cloudflare Workers
run: pnpm wrangler deploy
env:
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@
!/README.md !/README.md
!/composer.* !/composer.*
!/phpcs.xml !/phpcs.xml
!/project.code-workspace
!/wp-content/ !/wp-content/
/wp-content/* /wp-content/*

20
.vscode/settings.json vendored
View File

@@ -1,20 +0,0 @@
{
"editor.quickSuggestions": {
"strings": "on"
},
"files.associations": {
"*.css": "tailwindcss"
},
"graphql-config.load.rootDir": "wp-content/themes/moonshine",
"tailwindCSS.classAttributes": [
"class",
"ui"
],
"tailwindCSS.experimental.classRegex": [
[
"ui:\\s*{([^)]*)\\s*}",
"(?:'|\"|`)([^']*)(?:'|\"|`)"
]
],
"typescript.tsdk": "wp-content/themes/moonshine/node_modules/typescript/lib"
}

View File

@@ -3,4 +3,3 @@
Headless WordPress project boilerplate using Nuxt. Headless WordPress project boilerplate using Nuxt.
[✨  Release notes](/wp-content/themes/moonshine/CHANGELOG.md) [✨  Release notes](/wp-content/themes/moonshine/CHANGELOG.md)

View File

@@ -33,12 +33,14 @@
}, },
"require": { "require": {
"axepress/wp-graphql-rank-math": "*", "axepress/wp-graphql-rank-math": "*",
"lewebsimple/acf-phone": "*",
"lewebsimple/advanced-custom-fields-pro": "*", "lewebsimple/advanced-custom-fields-pro": "*",
"lewebsimple/kaliroots": "*", "lewebsimple/kaliroots": "*",
"lewebsimple/wp-graphql-headless-login": "*", "lewebsimple/wp-graphql-headless-login": "*",
"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": "*"

85
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": "e3ce417e8c09ed84502559af141f6530",
"packages": [ "packages": [
{ {
"name": "axepress/wp-graphql-plugin-boilerplate", "name": "axepress/wp-graphql-plugin-boilerplate",
@@ -313,6 +313,43 @@
], ],
"time": "2024-06-24T20:46:46+00:00" "time": "2024-06-24T20:46:46+00:00"
}, },
{
"name": "lewebsimple/acf-phone",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/lewebsimple/acf-phone.git",
"reference": "f9cb86eacb26eb92a40eb5e4366cff3e58e01f47"
},
"dist": {
"type": "zip",
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/acf-phone/lewebsimple-acf-phone-f9cb86eacb26eb92a40eb5e4366cff3e58e01f47-zip-606a09.zip",
"reference": "f9cb86eacb26eb92a40eb5e4366cff3e58e01f47",
"shasum": "2bbbc7d7f917e278d7d913bcb9da07a30f4662e6"
},
"require-dev": {
"lewebsimple/wp-phpcs-ruleset": "*",
"php-stubs/acf-pro-stubs": "*",
"squizlabs/php_codesniffer": "*"
},
"type": "wordpress-plugin",
"scripts": {
"post-create-project-cmd": [
"./scripts/post-create.sh"
],
"lint": [
"vendor/bin/phpcs"
],
"lintfix": [
"vendor/bin/phpcbf"
]
},
"support": {
"source": "https://github.com/lewebsimple/acf-phone/tree/v3.1.1",
"issues": "https://github.com/lewebsimple/acf-phone/issues"
},
"time": "2026-02-10T17:56:38+00:00"
},
{ {
"name": "lewebsimple/advanced-custom-fields-pro", "name": "lewebsimple/advanced-custom-fields-pro",
"version": "v6.7.0.2", "version": "v6.7.0.2",
@@ -332,20 +369,20 @@
}, },
{ {
"name": "lewebsimple/kaliroots", "name": "lewebsimple/kaliroots",
"version": "v0.9.18", "version": "v0.9.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "ssh://git@gitea.websimple.com:222/wp-themes/kaliroots.git", "url": "ssh://git@gitea.websimple.com:222/wp-themes/kaliroots.git",
"reference": "720554dff6ea45216b52187b7e8d5b87200d55a4" "reference": "40789468328e126cec9bd2f85a6a9923663a8d91"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/kaliroots/lewebsimple-kaliroots-v0.9.18-77d6cf.zip", "url": "https://satis.ledevsimple.ca/dist/lewebsimple/kaliroots/lewebsimple-kaliroots-v0.9.19-12b0b3.zip",
"reference": "720554dff6ea45216b52187b7e8d5b87200d55a4", "reference": "40789468328e126cec9bd2f85a6a9923663a8d91",
"shasum": "fd6aea0ef1bc160bc183eb7239cc9adf2fd88169" "shasum": "0a4cadbbc7719ee7de94b5cff4b2bb9c436f6416"
}, },
"type": "wordpress-theme", "type": "wordpress-theme",
"time": "2025-10-10T12:11:22+00:00" "time": "2026-02-09T15:07:56+00:00"
}, },
{ {
"name": "lewebsimple/wp-graphql-headless-login", "name": "lewebsimple/wp-graphql-headless-login",
@@ -419,16 +456,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.5",
"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.5"
}, },
"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.5.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.264",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/seo-by-rank-math/",
"reference": "tags/1.0.264"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/seo-by-rank-math.1.0.264.zip"
}, },
"require": { "require": {
"composer/installers": "^1.0 || ^2.0" "composer/installers": "^1.0 || ^2.0"
@@ -438,15 +493,15 @@
}, },
{ {
"name": "wpackagist-plugin/wp-graphql", "name": "wpackagist-plugin/wp-graphql",
"version": "2.6.0", "version": "2.8.0",
"source": { "source": {
"type": "svn", "type": "svn",
"url": "https://plugins.svn.wordpress.org/wp-graphql/", "url": "https://plugins.svn.wordpress.org/wp-graphql/",
"reference": "tags/2.6.0" "reference": "tags/2.8.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://downloads.wordpress.org/plugin/wp-graphql.2.6.0.zip" "url": "https://downloads.wordpress.org/plugin/wp-graphql.2.8.0.zip"
}, },
"require": { "require": {
"composer/installers": "^1.0 || ^2.0" "composer/installers": "^1.0 || ^2.0"

30
project.code-workspace Normal file
View File

@@ -0,0 +1,30 @@
{
"folders": [
{
"name": "Nuxt",
"path": "wp-content/themes/moonshine"
},
{
"name": "WordPress",
"path": "."
}
],
"settings": {
"files.associations": {
"*.css": "tailwindcss"
},
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.classAttributes": [
"class",
"ui"
],
"tailwindCSS.experimental.classRegex": [
[
"ui:\\s*{([^)]*)\\s*}",
"(?:'|\"|`)([^']*)(?:'|\"|`)"
]
]
}
}

View File

@@ -0,0 +1,20 @@
<?php
// Customize home URL for headless WordPress
add_filter( 'home_url', 'headless_home_url', 10, 4 );
function headless_home_url( $url, $path, $orig_scheme, $blog_id ) {
// Exclude specific patterns from rewriting
$excluded_patterns = array(
'#/wp-json(/|$)#i', // WP REST API
'#\.(xsl|xml)$#i', // Sitemap and XSLT files
);
foreach ( $excluded_patterns as $pattern ) {
if ( preg_match( $pattern, $url ) ) {
return get_site_url( $blog_id, $path, $orig_scheme );
}
}
// Rewrite URL protocol to match original home scheme
$scheme = wp_parse_url( get_option( 'home' ) )['scheme'] ?? 'https';
return preg_replace( '#^https:#i', "$scheme:", $url );
}

View File

@@ -22,3 +22,7 @@ logs
.env .env
.env.* .env.*
!.env.example !.env.example
# Wrangler files
.wrangler
server/types/cloudflare.d.ts

View File

@@ -0,0 +1,19 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"experimentalSortImports": {
"groups": [
["side-effect"],
["builtin"],
["external", "type-external"],
["internal", "type-internal"],
["parent", "type-parent"],
["sibling", "type-sibling"],
["index", "type-index"]
]
},
"experimentalTailwindcss": {
"attributes": ["class"],
"functions": ["tv"],
"stylesheet": "./app/assets/css/_main.css"
}
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"categories": {},
"env": {
"builtin": true,
"browser": true,
"node": true
},
"globals": {},
"ignorePatterns": [],
"plugins": ["import", "vue"],
"rules": {
"vue/define-emits-declaration": ["error", "type-based"],
"vue/define-props-declaration": ["error", "type-based"],
"vue/require-typed-ref": "error"
},
"settings": {
"vitest": {
"typecheck": false
}
}
}

View File

@@ -0,0 +1,3 @@
{
"recommendations": ["oxc.oxc-vscode"]
}

View File

@@ -0,0 +1,25 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Nuxt server",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/nuxt/bin/nuxt.mjs",
"runtimeArgs": ["--inspect"],
"args": ["dev"],
"autoAttachChildProcesses": true,
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Nuxt client",
"type": "chrome",
"request": "launch",
"sourceMaps": true,
"trace": false,
"url": "http://localhost:3000",
"userDataDir": "${env:HOME}/.vscode/chromium-profile"
}
]
}

View File

@@ -0,0 +1,35 @@
{
"[css]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[json]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[postcss]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[scss]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[vue]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll": "always"
},
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true,
"editor.quickSuggestions": {
"strings": "on"
},
"eslint.enable": false
}

View File

@@ -1,5 +1,123 @@
# Changelog # Changelog
## v0.1.14
[compare changes](https://gitea.websimple.com/wp-sites/wp-headless/compare/v0.1.13...v0.1.14)
### 🚀 Enhancements
- Replace eslint => oxlint + oxfmt (9bb09b8)
- VSCode launch configurations (fdf32bb)
- Project.code-workspace (71a48de)
- UseLayoutWrapper (3ec98fd)
- Auth middleware (fc6168e)
- UiLoadMore (e9d6ca2)
### 🩹 Fixes
- Wrangler config (db83170)
- Abstract social profiles should not be non-null (b0c5e4c)
## v0.1.13
[compare changes](https://gitea.websimple.com/wp-sites/wp-headless/compare/v0.1.12...v0.1.13)
### 🚀 Enhancements
- TinyMCE list style (8ae6daf)
### 🩹 Fixes
- Wrangler.json needed for wrangler types before build (faf39ca)
## v0.1.12
[compare changes](https://gitea.websimple.com/wp-sites/wp-headless/compare/v0.1.11...v0.1.12)
### 🚀 Enhancements
- ConnexionButton (87be06e)
- ShowLabel (98e8d97)
- ParseAcfLink (2cfc1a0)
- ParseAcfMedia (ab563a7)
- Event context type for Cloudflare environment (4338028)
### 🩹 Fixes
- UApp in app.vue (28f6e1a)
## v0.1.11
[compare changes](https://gitea.websimple.com/wp-sites/wp-headless/compare/v0.1.10...v0.1.11)
### 🚀 Enhancements
- MapSocialIcon (6dd13ea)
- AcfSocial / parseAcfSocial (3199835)
### 🩹 Fixes
- Remove unneeded wrangler main / assets (eea020b)
- Cloudflare image provider only in production (291fa6e)
- Wrangler project name (8f037b5)
- ENABLE_CLOUDFLARE_IMAGE (9c3dcee)
## v0.1.10
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.9...v0.1.10)
### 🚀 Enhancements
- GroupSiteOptions.phoneNumber (ad3c53c)
- AcfPhone component (6b17201)
- AcfLink / AcfLinkButton components (115a5d2)
### 💅 Refactors
- OptionsSite => SiteOptions for clearer naming (fefa980)
## v0.1.9
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.8...v0.1.9)
### 🚀 Enhancements
- Enhance refreshAuthToken to prevent duplicate requests (5e39b53)
- Default site-logo.svg (238aa29)
- Initial Media / HeroSplit acf groups (0fbd2bf)
- Media Focus Point plugin integration (bff7bce)
- AcfImage component based on @nuxt/image (4918c63)
- AcfMedia component (image + aspect + object-fit) (8bd544b)
- HeroSplit section (0bafc3a)
## v0.1.8
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.7...v0.1.8)
### 🚀 Enhancements
- UseResponsive with device detection on SSR (c82bf47)
- Graphql cache keyPrefix from package.json version (b1b1aa4)
- All of wrangler config in nuxt.config.ts (21a7036)
- Configure nuxt-svgo module (5f9c29c)
### 🩹 Fixes
- Headless_home_url needs to be in mu-plugins (51f594b)
- Use public wpUrl runtime config for auth refresh token mutation (2c86905)
- Term_order and default WPGraphQL settings (a27e6af)
- Update nuxt-graphql and extractNodes typing (maybe => undefined instead of null) (27f4f73)
## v0.1.7
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.6...v0.1.7)
### 🚀 Enhancements
- Configure sitemap URL in robots.txt (63f8e44)
- Deploy to Cloudflare workers (c6dfbeb)
- Display theme version in admin footer (b886585)
## v0.1.6 ## v0.1.6
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.5...v0.1.6) [compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.5...v0.1.6)
@@ -90,7 +208,6 @@
## v0.1.1 ## v0.1.1
### 🚀 Enhancements ### 🚀 Enhancements
- Initial Moonshine theme - Headless WordPress theme based on Nuxt (b3134fe) - Initial Moonshine theme - Headless WordPress theme based on Nuxt (b3134fe)

View File

@@ -2,11 +2,18 @@
Thème WordPress en headless basé sur Nuxt. Thème WordPress en headless basé sur Nuxt.
## Varaibles d'environnement ## Variables d'environnement
| Nom | Description | Exemple | Requise | | Nom | Description | Exemple | Requise |
|-----|-------------|---------|---------| | --------------- | ------------------------ | ----------------------- | ------- |
| `NUXT_SESSION_PASSWORD` | Clé secrète pour l'authentification | `date \| md5sum` | ✅ |
| `NUXT_WP_URL` | URL du backend WordPress | https://wp.exemple.com | ✅ |
| `NUXT_SITE_URL` | URL du frontend Nuxt | https://www.example.com | |
| `NUXT_SITE_ENV` | Environnement | staging \| production | | | `NUXT_SITE_ENV` | Environnement | staging \| production | |
| `NUXT_SITE_URL` | URL du frontend Nuxt | https://www.example.com | |
| `NUXT_WP_URL` | URL du backend WordPress | https://wp.exemple.com | ✅ |
## Secrets
Configurer les secrets nécessaires au projet:
```sh
pnpm wrangler secret put NUXT_SESSION_PASSWORD
```

View File

@@ -24,11 +24,7 @@
"acfe_flexible_layouts_placeholder": 0, "acfe_flexible_layouts_placeholder": 0,
"acfe_flexible_layouts_thumbnails": 0, "acfe_flexible_layouts_thumbnails": 0,
"acfe_flexible_async": [], "acfe_flexible_async": [],
"acfe_flexible_add_actions": [ "acfe_flexible_add_actions": ["copy", "title", "toggle"],
"copy",
"title",
"toggle"
],
"acfe_flexible_remove_button": [], "acfe_flexible_remove_button": [],
"acfe_flexible_remove_top_actions": [], "acfe_flexible_remove_top_actions": [],
"acfe_flexible_modal_edit": { "acfe_flexible_modal_edit": {
@@ -101,7 +97,9 @@
"max": "", "max": "",
"acfe_flexible_modal_edit_size": "", "acfe_flexible_modal_edit_size": "",
"acfe_flexible_settings": [ "acfe_flexible_settings": [
"group_layout_contained" "group_layout_colored",
"group_layout_contained",
"group_layout_padded"
], ],
"acfe_flexible_settings_size": "large", "acfe_flexible_settings_size": "large",
"acfe_flexible_render_template": false, "acfe_flexible_render_template": false,
@@ -109,6 +107,100 @@
"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": ["group_layout_colored", "group_layout_padded"],
"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": "",
@@ -135,16 +227,12 @@
"style": "seamless", "style": "seamless",
"label_placement": "top", "label_placement": "top",
"instruction_placement": "label", "instruction_placement": "label",
"hide_on_screen": [ "hide_on_screen": ["the_content"],
"the_content"
],
"active": true, "active": true,
"description": "", "description": "",
"show_in_rest": 0, "show_in_rest": 0,
"display_title": "", "display_title": "",
"acfe_autosync": [ "acfe_autosync": ["json"],
"json"
],
"acfe_form": 0, "acfe_form": 0,
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_field_name": "GroupAbstractBuilder", "graphql_field_name": "GroupAbstractBuilder",
@@ -152,5 +240,5 @@
"graphql_types": "", "graphql_types": "",
"acfe_meta": "", "acfe_meta": "",
"acfe_note": "", "acfe_note": "",
"modified": 1768358815 "modified": 1770740697
} }

View File

@@ -0,0 +1,121 @@
{
"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,84 @@
{
"key": "group_abstract_social",
"title": "Abstract - Social",
"fields": [
{
"key": "field_6855a1d643408",
"label": "Médias sociaux",
"name": "profiles",
"aria-label": "",
"type": "repeater",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"acfe_repeater_stylised_button": 0,
"layout": "table",
"pagination": 0,
"min": 0,
"max": 0,
"collapsed": "",
"button_label": "Ajouter un élément",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "profiles",
"graphql_non_null": 0,
"rows_per_page": 20,
"sub_fields": [
{
"key": "field_6855a7e143409",
"label": "URL",
"name": "url",
"aria-label": "",
"type": "url",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"placeholder": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "url",
"graphql_non_null": 1,
"parent_repeater": "field_6855a1d643408"
}
]
}
],
"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": "GroupAbstractSocial",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1770821599
}

View File

@@ -0,0 +1,64 @@
{
"key": "group_layout_colored",
"title": "Layout - Colored",
"fields": [
{
"key": "field_693c8c945ce51",
"label": "Variante de couleur",
"name": "color",
"aria-label": "",
"type": "button_group",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"default": "Par défaut",
"muted": "Atténué",
"elevated": "Surélevé",
"accented": "Accentué",
"inverted": "Inversé",
"primary": "Couleur principale"
},
"default_value": "default",
"return_format": "value",
"allow_null": 0,
"allow_in_bindings": 0,
"layout": "horizontal",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "color",
"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": "GroupLayoutColored",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1770132035
}

View File

@@ -4,10 +4,10 @@
"fields": [ "fields": [
{ {
"key": "field_68dc29d78941c", "key": "field_68dc29d78941c",
"label": "Conteneur", "label": "Largeur du contenu",
"name": "container", "name": "container",
"aria-label": "", "aria-label": "",
"type": "select", "type": "button_group",
"instructions": "", "instructions": "",
"required": 1, "required": 1,
"conditional_logic": 0, "conditional_logic": 0,
@@ -21,101 +21,17 @@
"xl": "1280px", "xl": "1280px",
"lg": "1024px", "lg": "1024px",
"fluid": "Largeur fluide", "fluid": "Largeur fluide",
"none": "Pleine largeur" "fullbleed": "Pleine largeur"
}, },
"default_value": "default", "default_value": "default",
"return_format": "value", "return_format": "value",
"multiple": 0,
"max": "",
"prepend": "",
"append": "",
"required_message": "",
"allow_null": 0, "allow_null": 0,
"allow_in_bindings": 0, "allow_in_bindings": 0,
"ui": 0, "layout": "horizontal",
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_description": "", "graphql_description": "",
"graphql_field_name": "container", "graphql_field_name": "container",
"graphql_non_null": 1, "graphql_non_null": 1
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": "",
"min": ""
},
{
"key": "field_693c8c3b5ce50",
"label": "Espacement vertical",
"name": "vertical_padding",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"sm": "Petit (12px)",
"md": "Medium (24px)",
"lg": "Grand (48px)"
},
"default_value": "md",
"return_format": "value",
"multiple": 0,
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "verticalPadding",
"graphql_non_null": 1,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": ""
},
{
"key": "field_693c8c945ce51",
"label": "Couleur d'arrière-plan",
"name": "bg_color",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"default": "Par défaut",
"muted": "Atténué",
"inverted": "Inversé"
},
"default_value": "default",
"return_format": "value",
"multiple": 0,
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "bgColor",
"graphql_non_null": 1,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": ""
} }
], ],
"location": [ "location": [
@@ -135,9 +51,7 @@
"description": "", "description": "",
"show_in_rest": 0, "show_in_rest": 0,
"display_title": "", "display_title": "",
"acfe_autosync": [ "acfe_autosync": ["json"],
"json"
],
"acfe_form": 0, "acfe_form": 0,
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_field_name": "GroupLayoutContained", "graphql_field_name": "GroupLayoutContained",
@@ -145,5 +59,5 @@
"graphql_types": "", "graphql_types": "",
"acfe_meta": "", "acfe_meta": "",
"acfe_note": "", "acfe_note": "",
"modified": 1768358794 "modified": 1770740626
} }

View File

@@ -0,0 +1,62 @@
{
"key": "group_layout_padded",
"title": "Layout - Padded",
"fields": [
{
"key": "field_693c8c3b5ce50",
"label": "Espacement intérieur vertical",
"name": "vertical_padding",
"aria-label": "",
"type": "button_group",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"none": "Aucun",
"sm": "Petit (12px)",
"md": "Medium (24px)",
"lg": "Grand (48px)"
},
"default_value": "md",
"return_format": "value",
"allow_null": 0,
"allow_in_bindings": 0,
"layout": "horizontal",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "verticalPadding",
"graphql_non_null": 1
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "left",
"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": "GroupLayoutPadded",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1770740636
}

View File

@@ -4,7 +4,7 @@
"fields": [ "fields": [
{ {
"key": "field_697220310aaaf", "key": "field_697220310aaaf",
"label": "Email", "label": "Courriel",
"name": "email", "name": "email",
"aria-label": "", "aria-label": "",
"type": "email", "type": "email",
@@ -25,6 +25,102 @@
"graphql_description": "", "graphql_description": "",
"graphql_field_name": "email", "graphql_field_name": "email",
"graphql_non_null": 1 "graphql_non_null": 1
},
{
"key": "field_697cbf414fdd5",
"label": "Numéro de téléphone",
"name": "phone_number",
"aria-label": "",
"type": "phone",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"initial_country": "CA",
"return_format": "national",
"allow_in_bindings": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "phoneNumber",
"graphql_non_null": 1
},
{
"key": "field_697cd4c5fc56a",
"label": "Médias sociaux",
"name": "social",
"aria-label": "",
"type": "clone",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "social",
"clone": ["group_abstract_social"],
"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_697cc921234cc",
"label": "Liens globaux",
"name": "links",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "row",
"acfe_seamless_style": 0,
"acfe_group_modal": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "links",
"graphql_non_null": 0,
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large",
"sub_fields": [
{
"key": "field_697cc93e234cd",
"label": "Contact",
"name": "contact",
"aria-label": "",
"type": "link",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"return_format": "array",
"allow_in_bindings": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "contact",
"graphql_non_null": 1
}
]
} }
], ],
"location": [ "location": [
@@ -46,15 +142,13 @@
"description": "", "description": "",
"show_in_rest": 0, "show_in_rest": 0,
"display_title": "", "display_title": "",
"acfe_autosync": [ "acfe_autosync": ["json"],
"json"
],
"acfe_form": 0, "acfe_form": 0,
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_field_name": "GroupSite", "graphql_field_name": "GroupSiteOptions",
"map_graphql_types_from_location_rules": 0, "map_graphql_types_from_location_rules": 0,
"graphql_types": "", "graphql_types": "",
"acfe_meta": "", "acfe_meta": "",
"acfe_note": "", "acfe_note": "",
"modified": 1769087407 "modified": 1770820358
} }

View File

@@ -17,9 +17,7 @@
"id": "" "id": ""
}, },
"graphql_field_name": "builder", "graphql_field_name": "builder",
"clone": [ "clone": ["group_abstract_builder"],
"group_abstract_builder"
],
"display": "seamless", "display": "seamless",
"layout": "block", "layout": "block",
"prefix_label": 0, "prefix_label": 0,
@@ -45,16 +43,12 @@
"style": "seamless", "style": "seamless",
"label_placement": "top", "label_placement": "top",
"instruction_placement": "label", "instruction_placement": "label",
"hide_on_screen": [ "hide_on_screen": ["the_content"],
"the_content"
],
"active": true, "active": true,
"description": "", "description": "",
"show_in_rest": 0, "show_in_rest": 0,
"display_title": "", "display_title": "",
"acfe_autosync": [ "acfe_autosync": ["json"],
"json"
],
"acfe_form": 0, "acfe_form": 0,
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_field_name": "GroupPostPage", "graphql_field_name": "GroupPostPage",

View File

@@ -20,6 +20,6 @@
"post_id": "", "post_id": "",
"autoload": 0, "autoload": 0,
"show_in_graphql": 1, "show_in_graphql": 1,
"graphql_type_name": "OptionsSite", "graphql_type_name": "SiteOptions",
"modified": 1769086997 "modified": 1769693948
} }

View File

@@ -9,5 +9,15 @@ export default defineAppConfig({
base: "cursor-pointer", base: "cursor-pointer",
}, },
}, },
input: {
slots: {
root: "w-full",
},
},
textarea: {
slots: {
root: "w-full",
},
},
}, },
}); });

View File

@@ -1,9 +1,13 @@
<script setup lang="ts">
import { fr } from "@nuxt/ui/locale";
</script>
<template> <template>
<div> <UApp :locale="fr">
<NuxtRouteAnnouncer /> <NuxtRouteAnnouncer />
<NuxtLoadingIndicator /> <NuxtLoadingIndicator />
<NuxtLayout> <NuxtLayout>
<NuxtPage /> <NuxtPage />
</NuxtLayout> </NuxtLayout>
</div> </UApp>
</template> </template>

View File

@@ -4,6 +4,7 @@
@import "./a11y.css"; @import "./a11y.css";
@import "./containers.css"; @import "./containers.css";
@import "./links.css"; @import "./links.css";
@import "./lists.css";
@import "./prose.css"; @import "./prose.css";
@import "./typography.css"; @import "./typography.css";

View File

@@ -8,13 +8,27 @@
} }
/* Container sizes */ /* Container sizes */
@utility container { @apply mx-auto px-container max-w-(--breakpoint-2xl); } @utility container {
@utility container-xl { @apply container max-w-(--breakpoint-xl); } @apply mx-auto px-container max-w-(--breakpoint-2xl);
@utility container-lg { @apply container max-w-(--breakpoint-lg); } }
@utility container-md { @apply container max-w-(--breakpoint-md); } @utility container-xl {
@utility container-sm { @apply container max-w-(--breakpoint-sm); } @apply container max-w-(--breakpoint-xl);
@utility container-fluid { @apply container max-w-screen; } }
@utility container-none { @apply w-full max-w-screen; } @utility container-lg {
@apply container max-w-(--breakpoint-lg);
}
@utility container-md {
@apply container max-w-(--breakpoint-md);
}
@utility container-sm {
@apply container max-w-(--breakpoint-sm);
}
@utility container-fluid {
@apply container max-w-screen;
}
@utility container-none {
@apply w-full max-w-screen;
}
/* Split containers */ /* Split containers */
:root { :root {
@@ -42,6 +56,12 @@
} }
} }
@utility container-left { @apply ml-(--container-outside-margin) px-container;} @utility container-left {
@utility container-right { @apply mr-(--container-outside-margin) px-container;} @apply ml-(--container-outside-margin) px-container;
@utility container-half { width: calc(var(--container-width) / 2);} }
@utility container-right {
@apply mr-(--container-outside-margin) px-container;
}
@utility container-half {
width: calc(var(--container-width) / 2);
}

View File

@@ -2,6 +2,12 @@
@custom-variant links (& a:not([class*='link-']):not([class*='button-'])); @custom-variant links (& a:not([class*='link-']):not([class*='button-']));
/* Link styles */ /* Link styles */
@utility link-base { @apply cursor-pointer disabled-default transition; } @utility link-base {
@utility link-underline { @apply link-base underline hover:decoration-primary; } @apply cursor-pointer disabled-default transition;
@utility link-opacity { @apply link-base hover:opacity-80; } }
@utility link-underline {
@apply link-base underline hover:decoration-primary;
}
@utility link-opacity {
@apply link-base hover:opacity-80;
}

View File

@@ -0,0 +1,3 @@
@utility list-horizontal {
@apply list-none flex flex-wrap items-center gap-3;
}

View File

@@ -1,15 +1,25 @@
@utility prose { @utility prose {
/* Headings (allow class overrides) */ /* Headings (allow class overrides) */
h1:not([class*="heading-"]) { @apply heading-1; } h1:not([class*="heading-"]) {
h2:not([class*="heading-"]) { @apply heading-2; } @apply heading-1;
h3:not([class*="heading-"]) { @apply heading-3; } }
h4:not([class*="heading-"]) { @apply heading-4; } h2:not([class*="heading-"]) {
@apply heading-2;
}
h3:not([class*="heading-"]) {
@apply heading-3;
}
h4:not([class*="heading-"]) {
@apply heading-4;
}
/* Links */ /* Links */
@apply links:link-underline; @apply links:link-underline;
/* Paragraphs */ /* Paragraphs */
p:not([class*="paragraph-"]) { @apply paragraph-base; } p:not([class*="paragraph-"]) {
@apply paragraph-base;
}
/* Spacing */ /* Spacing */
@apply space-y-2; @apply space-y-2;

View File

@@ -1,10 +1,24 @@
/* Heading styles */ /* Heading styles */
@utility heading-base { @apply font-bold tracking-tight }; @utility heading-base {
@utility heading-1 { @apply heading-base text-4xl; } @apply font-bold tracking-tight;
@utility heading-2 { @apply heading-base text-3xl; } }
@utility heading-3 { @apply heading-base text-2xl; } @utility heading-1 {
@utility heading-4 { @apply heading-base text-xl; } @apply heading-base text-4xl;
}
@utility heading-2 {
@apply heading-base text-3xl;
}
@utility heading-3 {
@apply heading-base text-2xl;
}
@utility heading-4 {
@apply heading-base text-xl;
}
/* Paragraph styles */ /* Paragraph styles */
@utility paragraph-base { @apply font-sans; } @utility paragraph-base {
@utility paragraph-lead { @apply paragraph-base text-2xl; } @apply font-sans;
}
@utility paragraph-lead {
@apply paragraph-base text-2xl;
}

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,17 @@
<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' }"
placeholder
/>
</template>

View File

@@ -0,0 +1,5 @@
fragment AcfLink on AcfLink {
title
url
target
}

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import type { AcfLinkFragment } from "#graphql/operations";
import type { LinkProps } from "@nuxt/ui";
type AcfLinkProps = Omit<LinkProps, "to" | "target" | "href"> & {
link?: AcfLinkFragment;
};
const { link, ...linkProps } = defineProps<AcfLinkProps>();
</script>
<template>
<ULink
v-if="link?.url && link?.title"
v-bind="linkProps"
:to="link.url"
:target="link.target"
:external="link.target === '_blank'"
:rel="link.target === '_blank' ? 'noopener noreferrer' : undefined"
>
<slot>{{ link.title }}</slot>
</ULink>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { AcfLinkFragment } from "#graphql/operations";
import type { ButtonProps } from "@nuxt/ui";
type AcfLinkButtonProps = Omit<ButtonProps, "to" | "target" | "href"> & {
link?: AcfLinkFragment;
showLabel?: boolean;
};
const { link, showLabel, ...buttonProps } = defineProps<AcfLinkButtonProps>();
</script>
<template>
<UButton
v-if="link?.url && link?.title"
v-bind="buttonProps"
:to="link.url"
:target="link.target"
:external="link.target === '_blank'"
:rel="link.target === '_blank' ? 'noopener noreferrer' : undefined"
>
<slot>{{ showLabel ? link.title : "" }}</slot>
</UButton>
</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

@@ -0,0 +1,5 @@
fragment AcfPhone on AcfPhone {
national
e164
extension
}

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
import type { AcfPhoneFragment } from "#graphql/operations";
defineProps<{
phone?: AcfPhoneFragment;
link?: boolean;
}>();
</script>
<template>
<Component :is="link ? 'a' : 'span'" v-if="phone" :href="link ? `tel:${phone.e164}` : undefined">
{{ phone.national }}{{ phone.extension ? ` ext. ${phone.extension}` : "" }}
</Component>
</template>

View File

@@ -0,0 +1,5 @@
fragment AcfSocial on GroupAbstractSocial_Fields {
profiles {
url
}
}

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
defineProps<{ social?: AcfSocialOutput }>();
</script>
<template>
<div v-if="social?.profiles" class="flex gap-1.5">
<a
v-for="({ url, icon }, key) in social.profiles"
:key="key"
:href="url"
target="_blank"
rel="noopener noreferrer"
class="flex"
>
<UIcon :name="icon" />
</a>
</div>
</template>

View File

@@ -1,20 +0,0 @@
<script setup lang="ts">
const { isLoggedIn } = useAuth();
const attrs = computed(() => {
return isLoggedIn.value
? {
label: "Déconnexion",
icon: "i-lucide-log-out",
}
: {
label: "Connexion",
icon: "i-lucide-log-in",
};
});
</script>
<template>
<AuthState>
<UButton to="/connexion" v-bind="attrs" color="neutral" />
</AuthState>
</template>

View File

@@ -7,7 +7,8 @@ const fields = [
label: "Courriel", label: "Courriel",
placeholder: "Entrez votre courriel", placeholder: "Entrez votre courriel",
required: true, required: true,
}, { },
{
name: "password", name: "password",
label: "Mot de passe", label: "Mot de passe",
type: "password" as const, type: "password" as const,

View File

@@ -5,12 +5,8 @@ const { logout } = useAuthConnexion();
<template> <template>
<div class="w-full space-y-6"> <div class="w-full space-y-6">
<div class="flex flex-col text-center"> <div class="flex flex-col text-center">
<div class="text-xl text-pretty font-semibold text-highlighted"> <div class="text-xl font-semibold text-pretty text-highlighted">Déconnexion</div>
Déconnexion <div class="mt-1 text-base text-pretty text-muted">Veuillez confirmer la déconnexion.</div>
</div>
<div class="mt-1 text-base text-pretty text-muted">
Veuillez confirmer la déconnexion.
</div>
</div> </div>
<UButton <UButton
icon="i-lucide-log-out" icon="i-lucide-log-out"

View File

@@ -1,12 +1,8 @@
<template> <template>
<div class="w-full space-y-6"> <div class="w-full space-y-6">
<div class="flex flex-col text-center"> <div class="flex flex-col text-center">
<div class="text-xl text-pretty font-semibold text-highlighted"> <div class="text-xl font-semibold text-pretty text-highlighted">Redirection en cours</div>
Redirection en cours <div class="mt-1 text-base text-pretty text-muted">Veuillez patienter...</div>
</div>
<div class="mt-1 text-base text-pretty text-muted">
Veuillez patienter...
</div>
</div> </div>
</div> </div>
</template> </template>

View File

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

View File

@@ -0,0 +1,3 @@
fragment LayoutColored on GroupLayoutColored_Fields {
color
}

View File

@@ -1,5 +1,3 @@
fragment LayoutContained on GroupLayoutContained_Fields { fragment LayoutContained on GroupLayoutContained_Fields {
container container
verticalPadding
bgColor
} }

View File

@@ -1,50 +0,0 @@
<script setup lang="ts">
import type { LayoutContainedFragment } from "#graphql/operations";
import { tv, type VariantProps } from "tailwind-variants";
const props = defineProps<LayoutContainedFragment>();
const layoutWrapperVariants = tv({
slots: {
base: "",
inner: "",
},
variants: {
container: {
default: { inner: "container" },
lg: { inner: "container-lg" },
xl: { inner: "container-xl" },
fluid: { inner: "container-fluid" },
none: { inner: "container-none" },
},
verticalPadding: {
sm: { base: "py-3" },
md: { base: "py-6" },
lg: { base: "py-12" },
},
bgColor: {
default: { base: "bg-default" },
muted: { base: "bg-muted" },
inverted: { base: "bg-inverted text-inverted" },
},
},
defaultVariants: {
container: "default",
verticalPadding: "md",
bgColor: "default",
},
});
const { base, inner } = layoutWrapperVariants({
container: props.container[0],
verticalPadding: props.verticalPadding[0],
bgColor: props.bgColor[0],
} as VariantProps<typeof layoutWrapperVariants>);
</script>
<template>
<section :class="base()">
<div :class="inner()">
<slot />
</div>
</section>
</template>

View File

@@ -0,0 +1,3 @@
fragment LayoutPadded on GroupLayoutPadded_Fields {
verticalPadding
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
const props = defineProps<{ layoutSettings?: LayoutSettings }>();
const { base, inner } = useLayoutWrapper(props.layoutSettings);
</script>
<template>
<section :class="base()">
<div :class="inner()">
<slot />
</div>
</section>
</template>

View File

@@ -6,9 +6,7 @@ defineProps<NodePageFragment>();
<template> <template>
<div id="node-page"> <div id="node-page">
<h1 v-if="!isFrontPage" class="font-bold text-4xl"> <PageHeader v-if="!isFrontPage" :title="title"></PageHeader>
{{ title }}
</h1>
<BuilderSections :sections="groupPostPage?.sections || []" /> <BuilderSections :sections="groupPostPage?.sections || []" />
</div> </div>
</template> </template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
defineProps<{
title?: string;
}>();
</script>
<template>
<header v-if="title" class="bg-accented py-6">
<div class="container">
<h1 class="heading-1">
{{ title }}
</h1>
</div>
</header>
</template>

View File

@@ -1,11 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
const { isLoggedIn } = useAuth(); const { isLoggedIn } = useAuth();
const { isRedirecting } = useAuthConnexion(); const { isRedirecting } = useAuthConnexion();
const layoutSettings: LayoutWrapperProps = {
container: "lg",
};
</script> </script>
<template> <template>
<section data-section-name="auth-connexion" class="py-12"> <LayoutWrapper data-section-name="auth-connexion" :layout-settings="layoutSettings">
<div class="container-sm">
<AuthState> <AuthState>
<AuthRedirecting v-if="isRedirecting" /> <AuthRedirecting v-if="isRedirecting" />
<template v-else> <template v-else>
@@ -13,6 +15,5 @@ const { isRedirecting } = useAuthConnexion();
<AuthLoginForm v-else /> <AuthLoginForm v-else />
</template> </template>
</AuthState> </AuthState>
</div> </LayoutWrapper>
</section>
</template> </template>

View File

@@ -0,0 +1,9 @@
fragment SectionHeroSplit on GroupAbstractBuilderSectionsHeroSplitLayout {
content
reverse
...AcfMedia
layoutSettings {
...LayoutColored
...LayoutPadded
}
}

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import { tv, type VariantProps } from "tailwind-variants";
import type { SectionHeroSplitFragment } from "#graphql/operations";
const tvSectionHeroSplit = tv({
extend: tvLayoutWrapper,
slots: {
container: "container flex flex-col items-center gap-6",
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,
...props.layoutSettings,
} as VariantProps<typeof tvSectionHeroSplit>);
</script>
<template>
<section :class="classes.base()">
<div :class="classes.container()">
<UiProse :content="content" :class="classes.content()" />
<AcfMedia :media="parseAcfMedia(props)" :class="classes.media()" />
</div>
</section>
</template>

View File

@@ -1,6 +1,8 @@
fragment SectionTextBlock on GroupAbstractBuilderSectionsTextBlockLayout { fragment SectionTextBlock on GroupAbstractBuilderSectionsTextBlockLayout {
content content
layoutSettings { layoutSettings {
...LayoutColored
...LayoutContained ...LayoutContained
...LayoutPadded
} }
} }

View File

@@ -5,7 +5,7 @@ defineProps<SectionTextBlockFragment>();
</script> </script>
<template> <template>
<LayoutContained data-section-type="text-block" v-bind="layoutSettings!"> <LayoutWrapper data-section-type="text-block" :layout-settings="layoutSettings">
<UiProse :content="content" /> <UiProse :content="content" />
</LayoutContained> </LayoutWrapper>
</template> </template>

View File

@@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
const { data: siteOptions } = await useSiteOptions();
</script> </script>
<template> <template>
<UFooter id="site-footer"> <footer class="links:link-prose bg-accented">
<template #left> <div class="container py-6">
<SiteFooterCopyright /> <AcfSocial :social="parseAcfSocial(siteOptions)" />
</template> </div>
<template #right> <SiteFooterBottom />
<SiteFooterCredits /> </footer>
</template>
</UFooter>
</template> </template>

View File

@@ -0,0 +1,20 @@
<script setup lang="ts">
const { connexionButton } = useAuthConnexion();
</script>
<template>
<div class="bg-inverted py-1.5 text-inverted">
<div class="container flex flex-col items-center gap-3 sm:flex-row">
<SiteFooterCopyright class="sm:mr-auto" />
<AuthState>
<AcfLinkButton
:link="connexionButton.link"
:icon="connexionButton.icon"
color="neutral"
variant="link"
/>
</AuthState>
<SiteFooterCredits />
</div>
</div>
</template>

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
const { data } = await useAsyncGraphQLQuery("GeneralSettings", undefined, { cache: { ttl: 0 } }); const { data: generalSettings } = await useGeneralSettings();
</script> </script>
<template> <template>
<div> <div>
© {{ new Date().getFullYear() }} © {{ new Date().getFullYear() }}
<span v-if="data.generalSettings?.title">{{ data.generalSettings.title }}</span> <span v-if="generalSettings?.title">{{ generalSettings.title }}</span>
</div> </div>
</template> </template>

View File

@@ -1,6 +1,12 @@
<template> <template>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
Fait avec <UIcon name="i-lucide-heart" /> par Fait avec <UIcon name="i-lucide-heart" /> par
<ULink href="https://websimple.com" target="_blank" external title="Site web développé par Websimple">Websimple</ULink> <ULink
href="https://websimple.com"
target="_blank"
external
title="Site web développé par Websimple"
>Websimple</ULink
>
</div> </div>
</template> </template>

View File

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

View File

@@ -0,0 +1,10 @@
<script setup lang="ts">
defineProps<{ hasNextPage: boolean; isLoadingMore: boolean }>();
defineEmits<{ loadMore: [] }>();
</script>
<template>
<div v-if="hasNextPage" class="flex justify-center">
<UButton @click="$emit('loadMore')" :loading="isLoadingMore"> En voir plus </UButton>
</div>
</template>

View File

@@ -2,5 +2,6 @@ export function useAuth() {
const { loggedIn: isLoggedIn, session } = useUserSession(); const { loggedIn: isLoggedIn, session } = useUserSession();
const hasRole = (role: string) => session.value?.user?.roles?.includes(role) || false; const hasRole = (role: string) => session.value?.user?.roles?.includes(role) || false;
const isAdmin = computed(() => hasRole("administrator")); const isAdmin = computed(() => hasRole("administrator"));
return { isLoggedIn, hasRole, isAdmin }; return { isLoggedIn, hasRole, isAdmin };
} }

View File

@@ -3,9 +3,10 @@ import type { FormSubmitEvent } from "@nuxt/ui";
const isRedirecting = ref(false); const isRedirecting = ref(false);
export function useAuthConnexion() { export function useAuthConnexion() {
const { isLoggedIn } = useAuth();
const toast = useToast(); const toast = useToast();
const { fetch: refreshUserSession } = useUserSession(); const { fetch: refreshUserSession } = useUserSession();
const routeRedirect = useRoute().query.redirect as string || undefined; const routeRedirect = (useRoute().query.redirect as string) || undefined;
// Helper: Redirect after login / logout // Helper: Redirect after login / logout
async function redirectTo(to: string | undefined) { async function redirectTo(to: string | undefined) {
@@ -29,13 +30,13 @@ export function useAuthConnexion() {
duration: 3000, duration: 3000,
}); });
await redirectTo(redirect); await redirectTo(redirect);
} } catch (error) {
catch (error) {
console.log(error); console.log(error);
toast.add({ toast.add({
title: "Erreur de connexion", title: "Erreur de connexion",
color: "error", color: "error",
description: error instanceof Error ? error.message : "Une erreur est survenue lors de la connexion.", description:
error instanceof Error ? error.message : "Une erreur est survenue lors de la connexion.",
duration: 5000, duration: 5000,
}); });
} }
@@ -55,17 +56,28 @@ export function useAuthConnexion() {
duration: 3000, duration: 3000,
}); });
await redirectTo(redirect); await redirectTo(redirect);
} } catch (error) {
catch (error) {
console.log(error); console.log(error);
toast.add({ toast.add({
title: "Erreur de déconnexion", title: "Erreur de déconnexion",
color: "error", color: "error",
description: error instanceof Error ? error.message : "Une erreur est survenue lors de la déconnexion.", description:
error instanceof Error
? error.message
: "Une erreur est survenue lors de la déconnexion.",
duration: 5000, duration: 5000,
}); });
} }
} }
return { isRedirecting, login, logout }; // Dynamic connexion link / icon
const connexionButton = computed(() => ({
link: parseAcfLink({
title: isLoggedIn.value ? "Déconnexion" : "Connexion",
url: "/connexion",
}),
icon: isLoggedIn.value ? "i-lucide-log-out" : "i-lucide-log-in",
}));
return { isRedirecting, login, logout, connexionButton };
} }

View File

@@ -0,0 +1,8 @@
export const useGeneralSettings = () =>
useAsyncGraphQLQuery(
"GeneralSettings",
{},
{
transform: ({ generalSettings }) => generalSettings,
},
);

View File

@@ -0,0 +1,64 @@
import { tv, type VariantProps } from "tailwind-variants";
import * as z from "zod";
// Tailwind Variants for LayoutWrapper
export const tvLayoutWrapper = tv({
slots: {
base: "",
inner: "",
},
variants: {
// LayoutColored
color: {
default: { base: "bg-default" },
muted: { base: "bg-muted" },
elevated: { base: "bg-elevated" },
accented: { base: "bg-accented" },
inverted: { base: "bg-inverted text-inverted" },
primary: { base: "bg-primary text-inverted" },
},
// LayoutContained
container: {
default: { inner: "container" },
xl: { inner: "container-xl" },
lg: { inner: "container-lg" },
fluid: { inner: "container-fluid" },
fullbleed: { inner: "container-fullbleed" },
},
// LayoutPadded
verticalPadding: {
sm: { base: "py-3" },
md: { base: "py-6" },
lg: { base: "py-12" },
none: {},
},
},
defaultVariants: {
color: "default",
container: "default",
verticalPadding: "md",
},
});
export type LayoutWrapperProps = VariantProps<typeof tvLayoutWrapper>;
// Zod schemas for validating layout settings
const colorEnum = z.enum(["default", "muted", "elevated", "accented", "inverted", "primary"]);
const containerEnum = z.enum(["default", "xl", "lg", "fluid", "fullbleed"]);
const verticalPaddingEnum = z.enum(["sm", "md", "lg", "none"]);
const layoutSettingsSchema = z.object({
color: z.string().pipe(colorEnum).optional(),
container: z.string().pipe(containerEnum).optional(),
verticalPadding: z.string().pipe(verticalPaddingEnum).optional(),
});
export type LayoutSettings = z.input<typeof layoutSettingsSchema>;
export function useLayoutWrapper(input?: LayoutSettings) {
try {
return tvLayoutWrapper(layoutSettingsSchema.parse(input));
} catch {
return tvLayoutWrapper();
}
}

View File

@@ -11,8 +11,7 @@ export function useProseLinks(refContent: Ref<HTMLElement | null>) {
try { try {
const hrefUrl = new URL(href); const hrefUrl = new URL(href);
return hrefUrl.hostname === siteUrl.hostname; return hrefUrl.hostname === siteUrl.hostname;
} } catch {
catch {
return false; return false;
} }
}; };
@@ -25,8 +24,7 @@ export function useProseLinks(refContent: Ref<HTMLElement | null>) {
if (hrefUrl.hostname === siteUrl.hostname) { if (hrefUrl.hostname === siteUrl.hostname) {
return hrefUrl.pathname + hrefUrl.search + hrefUrl.hash; return hrefUrl.pathname + hrefUrl.search + hrefUrl.hash;
} }
} } catch {
catch {
// Invalid URL // Invalid URL
} }
return href; return href;
@@ -39,7 +37,14 @@ export function useProseLinks(refContent: Ref<HTMLElement | null>) {
if (!link) return; if (!link) return;
const href = link.getAttribute("href"); const href = link.getAttribute("href");
if (!href) return; if (!href) return;
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || link.target === "_blank" || link.hasAttribute("download")) { if (
e.metaKey ||
e.ctrlKey ||
e.shiftKey ||
e.altKey ||
link.target === "_blank" ||
link.hasAttribute("download")
) {
return; return;
} }
if (isInternal(href)) { if (isInternal(href)) {

View File

@@ -0,0 +1,11 @@
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
export function useResponsive() {
const { isMobileOrTablet } = useDevice();
const breakpoints = useBreakpoints(breakpointsTailwind, {
ssrWidth: isMobileOrTablet ? 375 : 1024,
});
const isDesktop = breakpoints.greaterOrEqual("lg");
return { breakpoints, isDesktop };
}

View File

@@ -0,0 +1,8 @@
export const useSiteOptions = () =>
useAsyncGraphQLQuery(
"SiteOptions",
{},
{
transform: ({ siteOptions }) => siteOptions?.groupSiteOptions,
},
);

View File

@@ -1,11 +0,0 @@
fragment SiteOptions on GroupSite_Fields {
email
}
query OptionsSite {
optionsSite {
groupSite {
... SiteOptions
}
}
}

View File

@@ -0,0 +1,4 @@
fragment PageInfo on WPPageInfo {
hasNextPage
endCursor
}

View File

@@ -0,0 +1,20 @@
fragment SiteOptions on GroupSiteOptions {
email
phoneNumber {
...AcfPhone
}
...AcfSocial
links {
contact {
...AcfLink
}
}
}
query SiteOptions {
siteOptions {
groupSiteOptions {
...SiteOptions
}
}
}

View File

@@ -1,13 +1,9 @@
<script setup lang="ts">
import { fr } from "@nuxt/ui/locale";
</script>
<template> <template>
<UApp id="layout-default" :locale="fr"> <div id="layout-default">
<SiteHeader /> <SiteHeader />
<UMain> <UMain>
<slot /> <slot />
</UMain> </UMain>
<SiteFooter /> <SiteFooter />
</UApp> </div>
</template> </template>

View File

@@ -0,0 +1,18 @@
export default defineNuxtRouteMiddleware((to) => {
const { hasRole, isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo({ path: "/connexion", query: { redirect: to.fullPath } });
}
if (!hasRole(to.meta.hasRole || "")) {
return abortNavigation({
statusCode: 403,
message: "Vous n'avez pas les permissions requises pour accéder à cette page.",
});
}
});
declare module "#app" {
interface PageMeta {
hasRole?: string;
}
}

View File

@@ -0,0 +1,12 @@
export default defineNuxtRouteMiddleware((to) => {
const { isAdmin, isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo({ path: "/connexion", query: { redirect: to.fullPath } });
}
if (!isAdmin.value) {
return abortNavigation({
statusCode: 403,
message: "Vous n'avez pas les permissions requises pour accéder à cette page.",
});
}
});

View File

@@ -0,0 +1,6 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo({ path: "/connexion", query: { redirect: to.fullPath } });
}
});

View File

@@ -0,0 +1,6 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn } = useAuth();
if (isLoggedIn.value) {
return navigateTo({ path: "/connexion", query: { redirect: to.fullPath } });
}
});

View File

@@ -1,21 +1,31 @@
<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) {
throw createError({ statusCode: 404, message: `La page demandée est introuvable: ${uri}`, fatal: true }); console.error("NodeByUri query error:", error.value);
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,
});
} }
useNodeSeo(data.value.nodeByUri); useNodeSeo(data.value.nodeByUri);
</script> </script>
<template> <template>
<div v-if="data.nodeByUri" id="page-node-from-uri"> <div v-if="data?.nodeByUri" id="page-node-from-uri">
<Component :is="componentName" v-bind="data.nodeByUri" /> <Component :is="componentName" v-bind="data.nodeByUri" />
<pre>{{ data.nodeByUri }}</pre>
</div> </div>
</template> </template>

View File

@@ -0,0 +1,17 @@
import type { AcfLinkFragment } from "#graphql/operations";
import * as z from "zod";
const acfLinkSchema = z.object({
title: z.string(),
url: z.string(),
target: z.string().optional().default(""),
});
export type AcfLinkOutput = z.infer<typeof acfLinkSchema>;
export function parseAcfLink(data?: Partial<AcfLinkFragment>) {
try {
return acfLinkSchema.parse(data);
} catch {
return undefined;
}
}

View File

@@ -0,0 +1,28 @@
import type { AcfMediaFragment } from "#graphql/operations";
import * as z from "zod";
export const acfImageSchema = z.object({
src: z.url(),
alt: z.string(),
mediaDetails: z.object({
width: z.number(),
height: z.number(),
}),
objectPosition: z.string().optional().default("center"),
});
export const acfMediaSchema = z.object({
image: z.object({
node: acfImageSchema,
}),
aspectRatio: z.enum(["square", "video", "portrait", "auto"]).optional().default("auto"),
objectFit: z.enum(["cover", "contain"]).optional().default("cover"),
});
export function parseAcfMedia(data?: Partial<AcfMediaFragment>) {
try {
return acfMediaSchema.parse(data);
} catch {
return undefined;
}
}

View File

@@ -0,0 +1,33 @@
import type { AcfSocialFragment } from "#graphql/operations";
import * as z from "zod";
const socialProfile = z
.object({ url: z.url() })
.transform(({ url }) => ({ url, icon: getSocialIcon(url) }));
const acfSocialSchema = z.object({
profiles: z.array(socialProfile),
});
export type AcfSocialOutput = z.infer<typeof acfSocialSchema>;
export function parseAcfSocial(data?: AcfSocialFragment) {
try {
return acfSocialSchema.parse(data);
} catch {
return undefined;
}
}
const socialIconMap = {
"facebook.com": "i-cib-facebook-f",
"twitter.com": "i-cib-twitter",
"x.com": "i-cib-twitter",
"instagram.com": "i-cib-instagram",
"youtube.com": "i-cib-youtube",
"linkedin.com": "i-cib-linkedin",
"tiktok.com": "i-cib-tiktok",
};
function getSocialIcon(url: string): string {
const domain = new URL(url).hostname.toLowerCase().replace(/^www\./, "");
return socialIconMap[domain as keyof typeof socialIconMap] ?? "i-lucide-globe";
}

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +0,0 @@
// @ts-check
import withNuxt from "./.nuxt/eslint.config.mjs";
export default withNuxt({ rules: {
"vue/max-attributes-per-line": "off",
"vue/no-v-html": "off",
} },
);

View File

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

View File

@@ -1,4 +1,4 @@
{ {
"schema": "./server/graphql/schema.graphql", "schema": "./.nuxt/graphql/schema.gql",
"documents": "**/*.gql" "documents": "**/*.gql"
} }

View File

@@ -17,17 +17,11 @@ function moonshine_after_setup_theme() {
// Register sidebars // Register sidebars
} }
// Bypass headless home URL for specific cases // Display theme version in admin footer
add_filter( 'home_url', 'moonshine_bypass_home_url', 10, 4 ); add_filter( 'update_footer', 'moonshine_update_footer', 100 );
function moonshine_bypass_home_url( $url, $path, $orig_scheme, $blog_id ) { function moonshine_update_footer() {
$excluded_patterns = array( $package_json = json_decode( file_get_contents( get_theme_file_path( 'package.json' ) ), true );
'#/wp-json(/|$)#i', // WP REST API $name = $package_json['name'] ?? 'moonshine';
'#\.(xsl|xml)$#i', // Sitemap and XSLT files $version = $package_json['version'] ?? '(unknown)';
); return sprintf( '%s v%s', esc_html( $name ), esc_html( $version ) );
foreach ( $excluded_patterns as $pattern ) {
if ( preg_match( $pattern, $url ) ) {
return get_site_url( $blog_id, $path, $orig_scheme );
}
}
return $url;
} }

View File

@@ -0,0 +1 @@
<?php

View File

@@ -50,6 +50,16 @@ function moonshine_tiny_mce_before_init( $settings ) {
), ),
), ),
), ),
array(
'title' => __( "List styles", 'moonshine' ),
'items' => array(// List styles
array(
'title' => "Liste horizontale",
'selector' => 'ul,ol',
'classes' => 'list-horizontal',
),
),
),
array( array(
'title' => __( "Heading styles", 'moonshine' ), 'title' => __( "Heading styles", 'moonshine' ),
'items' => array(// Heading styles 'items' => array(// Heading styles

View File

@@ -0,0 +1,17 @@
<?php
// Default WPGraphQL settings
add_filter( 'graphql_get_setting_section_field_value', 'moonshine_wpgraphql_settings', 10, 5 );
function moonshine_wpgraphql_settings( $value, $default_value, $option_name, $section_fields, $section_name ) {
if ( $section_name === 'graphql_general_settings' ) {
switch ( $option_name ) {
case 'graphql_endpoint':
$value = 'graphql';
break;
case "public_introspection_enabled":
$value = "on";
break;
}
}
return $value;
}

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

@@ -0,0 +1,13 @@
<?php
// Override term connection query args
add_filter( 'graphql_term_object_connection_query_args', 'moonshine_graphql_term_object_connection_query_args', 10, 3 );
function moonshine_graphql_term_object_connection_query_args( $query_args, $source, $args ) {
// Sort by 'order' meta value instead of legacy 'term_order' field
if ( 'term_order' === $args['where']['orderby'] ?? false ) {
$query_args['meta_key'] = 'order';
$query_args['orderby'] = 'meta_value_num';
}
return $query_args;
}

View File

@@ -3,7 +3,7 @@ return array(
'project-id-version' => 'Moonshine', 'project-id-version' => 'Moonshine',
'report-msgid-bugs-to' => '', 'report-msgid-bugs-to' => '',
'pot-creation-date' => '2026-01-13 15:52+0000', 'pot-creation-date' => '2026-01-13 15:52+0000',
'po-revision-date' => '2026-01-13 15:53+0000', 'po-revision-date' => '2026-01-29 02:55+0000',
'last-translator' => '', 'last-translator' => '',
'language-team' => 'Français du Canada', 'language-team' => 'Français du Canada',
'language' => 'fr_CA', 'language' => 'fr_CA',
@@ -15,10 +15,15 @@ return array(
'x-loco-version' => '2.8.1; wp-6.9; php-8.3.27', 'x-loco-version' => '2.8.1; wp-6.9; php-8.3.27',
'x-domain' => 'moonshine', 'x-domain' => 'moonshine',
'messages' => array( 'messages' => array(
'Heading styles' => 'Styles de titres',
'Headless WordPress theme based on Nuxt.' => 'Thème Wordpress headless basé sur Nuxt.', 'Headless WordPress theme based on Nuxt.' => 'Thème Wordpress headless basé sur Nuxt.',
'https://websimple.com/' => 'https://websimple.com/', 'https://websimple.com/' => 'https://websimple.com/',
'Inline styles' => 'Styles de caractères',
'Link styles' => 'Styles de liens',
'Main menu' => 'Menu principal', 'Main menu' => 'Menu principal',
'Moonshine' => 'Moonshine', 'Moonshine' => 'Moonshine',
'Paragraph styles' => 'Styles de paragraphes',
'Pascal Martineau ' => 'Pascal Martineau ', 'Pascal Martineau ' => 'Pascal Martineau ',
'Semi-bold' => 'Semi-gras',
), ),
); );

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"

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