Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 27380290e1 | |||
| 7e44554767 | |||
| 9c3dceef84 | |||
| ba8d8e00a8 | |||
| 8f037b5950 | |||
| 291fa6eaa4 | |||
| 4079e4ecfb | |||
| eea020b136 | |||
| 5161bff624 | |||
| 3199835e83 | |||
| 6dd13ead91 | |||
| 980c5271ac | |||
| 115a5d2d38 | |||
| 6b17201f60 | |||
| ad3c53c5dd | |||
| fefa98021b | |||
| 1e58b1f1e7 | |||
| 0bafc3a9dd | |||
| 8bd544b5c3 | |||
| 4918c638ab | |||
| bff7bce1f1 | |||
| 0fbd2bf7ac | |||
| 238aa29bd4 | |||
| f268bdc3c3 | |||
| 11641a00d1 | |||
| 6a5d60e34c | |||
| 80e6555c88 | |||
| ff866e2078 | |||
| 5e39b53a44 | |||
| 2d93d44a93 | |||
| ec64a42c2e | |||
| 5f9c29c39a | |||
| 27f4f73148 | |||
| 21a7036ef5 | |||
| b1b1aa47c9 | |||
| 54fea5f64a | |||
| a27e6af5db | |||
| 2c86905c91 | |||
| 065b729a2f | |||
| c82bf47e98 | |||
| 51f594baa5 | |||
| 3e56ba7eb3 | |||
| aaea0b062a | |||
| b886585be1 | |||
| c6dfbeb247 | |||
| a1a8114f49 | |||
| 63f8e443cf | |||
| 5b8c50c758 | |||
| c5ce607fae | |||
| 9cd99c36db | |||
| 108269e3fe | |||
| 4492d760bb | |||
| 489ac82faa | |||
| d7cf08db00 | |||
| 4ae9b67b9c | |||
| 3b706c0092 | |||
| baa3061685 | |||
| fd61895bbd | |||
| cdcb09e24b | |||
| 341b0d6e9d | |||
| 58d1dc0045 | |||
| 5e0df227f3 | |||
| 2d0b176ab8 | |||
| bfb5ae3a70 | |||
| 9d99770b38 | |||
| e383255e73 | |||
| 684e2fa1e9 | |||
| 8e26f19f66 | |||
| 40becf1135 | |||
| 764bc6aeea | |||
| 12048ffdd3 | |||
| c7f6cca663 | |||
| 2b9a87511b | |||
| 688c4e36b3 | |||
| 5bda835566 | |||
| 6f6e0d7b76 | |||
| c1094239a3 | |||
| f9958701e6 | |||
| dbbb2f7009 | |||
| d0244eb6a3 | |||
| a2860478a9 | |||
| 33589d425a | |||
| 9b6a86fe0c | |||
| f520db7a9d | |||
| 3d7a2b2ef6 | |||
| ca2e660c05 | |||
| de126b0953 | |||
| 9495c4f004 |
56
.gitea/workflows/deploy.yaml
Normal file
56
.gitea/workflows/deploy.yaml
Normal 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 }}
|
||||||
34
.github/copilot-instructions.md
vendored
Normal file
34
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Copilot instructions (wp-headless)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
- This project is a full WordPress install (core lives in `wp-admin/` + `wp-includes/`). Treat core files as upstream: **don’t implement features by editing WordPress core or plugins**.
|
||||||
|
- Project-specific code lives in `wp-content/themes/moonshine/`:
|
||||||
|
- “Headless” stack is assembled via custom theme and plugins:
|
||||||
|
- `wp-content/themes/moonshine/` provides the WordPress PHP theme logic and Nuxt frontend.
|
||||||
|
- `wp-content/plugins/wp-graphql/` provides the GraphQL endpoint (typically `/graphql`).
|
||||||
|
- `wp-content/plugins/wpgraphql-acf/` exposes ACF fields in the GraphQL schema.
|
||||||
|
- `wp-content/plugins/wp-graphql-headless-login/` provides GraphQL-based authentication flows.
|
||||||
|
|
||||||
|
## Where to make changes
|
||||||
|
- **Changes should only be made in the Moonshine theme `wp-content/themes/moonshine/`**
|
||||||
|
- WordPress PHP theme logic lives in `wp-content/themes/moonshine/includes/`.
|
||||||
|
- Nuxt frontend (Nuxt 4): `wp-content/themes/moonshine/`
|
||||||
|
- App entry & routes: `wp-content/themes/moonshine/app/` (catch-all route is `app/pages/[...uri].vue`).
|
||||||
|
- Config: `wp-content/themes/moonshine/nuxt.config.ts`.
|
||||||
|
- Package manager: **pnpm** (`pnpm-lock.yaml` is present).
|
||||||
|
|
||||||
|
## Developer workflows
|
||||||
|
- **WP Headless** - WordPress Composer project (root folder):
|
||||||
|
- Install PHP deps (also manages WP plugins/themes via Composer repos): `composer install`.
|
||||||
|
- Update PHP deps / WordPress plugins: `composer update`.
|
||||||
|
- Composer uses an internal Satis repo (`https://satis.ledevsimple.ca`) plus `wpackagist.org`.
|
||||||
|
- PHP linting (phpcs):`composer lint`
|
||||||
|
- PHP beautifier (phpcbf): `composer lintfix`
|
||||||
|
- **Moonshine** - Headless WordPress theme based on Nuxt 4 (`wp-content/themes/moonshine/`):
|
||||||
|
- Dev: `pnpm dev`
|
||||||
|
- Build: `pnpm build`
|
||||||
|
- Lint (autofix): `pnpm lint`
|
||||||
|
|
||||||
|
## Conventions to follow
|
||||||
|
- Prefer adding project behavior via WordPress hooks/filters in the theme (`moonshine_*` functions) or via plugins—avoid editing WP core at all cost.
|
||||||
|
- In the Nuxt app, prefer the repo’s ESLint/Tailwind conventions (VS Code settings treat `*.css` as TailwindCSS and support Nuxt UI `ui` attributes).
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,8 +2,10 @@
|
|||||||
/*
|
/*
|
||||||
!/.cpanel.yml
|
!/.cpanel.yml
|
||||||
!/.gitea
|
!/.gitea
|
||||||
|
!/.github
|
||||||
!/.gitignore
|
!/.gitignore
|
||||||
!/.vscode
|
!/.vscode
|
||||||
|
!/README.md
|
||||||
!/composer.*
|
!/composer.*
|
||||||
!/phpcs.xml
|
!/phpcs.xml
|
||||||
!/wp-content/
|
!/wp-content/
|
||||||
|
|||||||
20
.vscode/settings.json
vendored
Normal file
20
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# WP Headless
|
||||||
|
|
||||||
|
Headless WordPress project boilerplate using Nuxt.
|
||||||
|
|
||||||
|
[✨ Release notes](/wp-content/themes/moonshine/CHANGELOG.md)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lewebsimple/wp-headless",
|
"name": "lewebsimple/wp-headless",
|
||||||
"description": "WordPress project",
|
"description": "WP Headless",
|
||||||
"version": "0.4.25",
|
"version": "0.4.25",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -32,12 +32,16 @@
|
|||||||
"lintfix": "vendor/bin/phpcbf"
|
"lintfix": "vendor/bin/phpcbf"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"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/wp-graphql": "*",
|
"wpackagist-plugin/wp-graphql": "*",
|
||||||
"wpackagist-plugin/wpgraphql-acf": "*"
|
"wpackagist-plugin/wpgraphql-acf": "*"
|
||||||
},
|
},
|
||||||
|
|||||||
258
composer.lock
generated
258
composer.lock
generated
@@ -4,8 +4,169 @@
|
|||||||
"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": "aec2b0e396a71ea02fe95432358ca91e",
|
"content-hash": "e3ce417e8c09ed84502559af141f6530",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "axepress/wp-graphql-plugin-boilerplate",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate.git",
|
||||||
|
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/AxeWP/wp-graphql-plugin-boilerplate/zipball/09495b61346453baabdf4c71a38ada3cfc91c3a7",
|
||||||
|
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"axepress/wp-graphql-cs": "^2.0.0",
|
||||||
|
"axepress/wp-graphql-stubs": "^2.3.0",
|
||||||
|
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpstan": "^2.0",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^2.0.1",
|
||||||
|
"szepeviktor/phpstan-wordpress": "^2.0",
|
||||||
|
"wp-cli/wp-cli-bundle": "^2.8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"AxeWP\\GraphQL\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AxePress Development",
|
||||||
|
"homepage": "https://axepress.dev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David Levine",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Boilerplate for creating WPGraphQL extensions",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/issues",
|
||||||
|
"source": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/tree/0.1.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/AxeWp",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-06-07T02:03:50+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "axepress/wp-graphql-rank-math",
|
||||||
|
"version": "0.3.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/AxeWP/wp-graphql-rank-math.git",
|
||||||
|
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/AxeWP/wp-graphql-rank-math/zipball/167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
|
||||||
|
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"axepress/wp-graphql-plugin-boilerplate": "^0.1.1",
|
||||||
|
"php": ">=7.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"axepress/wp-graphql-cs": "^2.0.0",
|
||||||
|
"axepress/wp-graphql-stubs": "^2.0.0",
|
||||||
|
"codeception/lib-innerbrowser": "^1.0",
|
||||||
|
"codeception/module-asserts": "^1.0",
|
||||||
|
"codeception/module-cli": "^1.0",
|
||||||
|
"codeception/module-db": "^1.0",
|
||||||
|
"codeception/module-filesystem": "^1.0",
|
||||||
|
"codeception/module-phpbrowser": "^1.0",
|
||||||
|
"codeception/module-rest": "^2.0",
|
||||||
|
"codeception/module-webdriver": "^1.0",
|
||||||
|
"codeception/phpunit-wrapper": "^9.0",
|
||||||
|
"codeception/util-universalframework": "^1.0",
|
||||||
|
"lucatume/wp-browser": "<3.5",
|
||||||
|
"php-coveralls/php-coveralls": "^2.5",
|
||||||
|
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpstan": "^2.1.5",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"szepeviktor/phpstan-wordpress": "^2.0.1",
|
||||||
|
"wp-cli/wp-cli-bundle": "^2.8.1",
|
||||||
|
"wp-graphql/wp-graphql-testcase": "~3.4.0"
|
||||||
|
},
|
||||||
|
"type": "wordpress-plugin",
|
||||||
|
"extra": {
|
||||||
|
"strauss": {
|
||||||
|
"packages": [
|
||||||
|
"axepress/wp-graphql-plugin-boilerplate"
|
||||||
|
],
|
||||||
|
"classmap_prefix": "WPGraphQL_RankMath_",
|
||||||
|
"constant_prefix": "WPGRAPHQL_SEO_",
|
||||||
|
"namespace_prefix": "WPGraphQL\\RankMath\\Vendor\\",
|
||||||
|
"target_directory": "vendor-prefixed",
|
||||||
|
"update_call_sites": false,
|
||||||
|
"exclude_from_prefix": {
|
||||||
|
"namespaces": [],
|
||||||
|
"file_patterns": []
|
||||||
|
},
|
||||||
|
"include_modified_date": false,
|
||||||
|
"delete_vendor_packages": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"access-functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"WPGraphQL\\RankMath\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"vendor-prefixed/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AxePress Development",
|
||||||
|
"email": "support@axepress.dev",
|
||||||
|
"homepage": "https://axepress.dev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David Levine",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Adds WPGraphQL support for RankMath SEO",
|
||||||
|
"support": {
|
||||||
|
"email": "support@axepress.dev",
|
||||||
|
"forum": "https://github.com/AxeWP/wp-graphql-rank-math/discussions",
|
||||||
|
"issues": "https://github.com/AxeWP/wp-graphql-rank-math/issues",
|
||||||
|
"source": "https://github.com/AxeWP/wp-graphql-rank-math/tree/0.3.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/sponsors/AxeWP",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-06-07T12:05:15+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "composer/installers",
|
"name": "composer/installers",
|
||||||
"version": "v2.3.0",
|
"version": "v2.3.0",
|
||||||
@@ -152,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.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/lewebsimple/acf-phone.git",
|
||||||
|
"reference": "cf4c6440e0c2cdf7e422423bb629014204e721bf"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/acf-phone/lewebsimple-acf-phone-cf4c6440e0c2cdf7e422423bb629014204e721bf-zip-439080.zip",
|
||||||
|
"reference": "cf4c6440e0c2cdf7e422423bb629014204e721bf",
|
||||||
|
"shasum": "f9d7cbcf27985656245285e5bc035578621f1a69"
|
||||||
|
},
|
||||||
|
"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.0",
|
||||||
|
"issues": "https://github.com/lewebsimple/acf-phone/issues"
|
||||||
|
},
|
||||||
|
"time": "2026-01-30T15:01:34+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "lewebsimple/advanced-custom-fields-pro",
|
"name": "lewebsimple/advanced-custom-fields-pro",
|
||||||
"version": "v6.7.0.2",
|
"version": "v6.7.0.2",
|
||||||
@@ -205,15 +403,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wpackagist-plugin/acf-extended",
|
"name": "wpackagist-plugin/acf-extended",
|
||||||
"version": "0.9.2.2",
|
"version": "0.9.2.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "svn",
|
"type": "svn",
|
||||||
"url": "https://plugins.svn.wordpress.org/acf-extended/",
|
"url": "https://plugins.svn.wordpress.org/acf-extended/",
|
||||||
"reference": "tags/0.9.2.2"
|
"reference": "tags/0.9.2.3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://downloads.wordpress.org/plugin/acf-extended.0.9.2.2.zip"
|
"url": "https://downloads.wordpress.org/plugin/acf-extended.0.9.2.3.zip"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"composer/installers": "^1.0 || ^2.0"
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
@@ -241,15 +439,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wpackagist-plugin/disable-comments",
|
"name": "wpackagist-plugin/disable-comments",
|
||||||
"version": "2.6.1",
|
"version": "2.6.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "svn",
|
"type": "svn",
|
||||||
"url": "https://plugins.svn.wordpress.org/disable-comments/",
|
"url": "https://plugins.svn.wordpress.org/disable-comments/",
|
||||||
"reference": "tags/2.6.1"
|
"reference": "tags/2.6.2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://downloads.wordpress.org/plugin/disable-comments.2.6.1.zip"
|
"url": "https://downloads.wordpress.org/plugin/disable-comments.2.6.2.zip"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"composer/installers": "^1.0 || ^2.0"
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
@@ -258,16 +456,52 @@
|
|||||||
"homepage": "https://wordpress.org/plugins/disable-comments/"
|
"homepage": "https://wordpress.org/plugins/disable-comments/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wpackagist-plugin/wp-graphql",
|
"name": "wpackagist-plugin/media-focus-point",
|
||||||
"version": "2.6.0",
|
"version": "2.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "svn",
|
"type": "svn",
|
||||||
"url": "https://plugins.svn.wordpress.org/wp-graphql/",
|
"url": "https://plugins.svn.wordpress.org/media-focus-point/",
|
||||||
"reference": "tags/2.6.0"
|
"reference": "tags/2.0.4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://downloads.wordpress.org/plugin/wp-graphql.2.6.0.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": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
},
|
||||||
|
"type": "wordpress-plugin",
|
||||||
|
"homepage": "https://wordpress.org/plugins/seo-by-rank-math/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wpackagist-plugin/wp-graphql",
|
||||||
|
"version": "2.7.0",
|
||||||
|
"source": {
|
||||||
|
"type": "svn",
|
||||||
|
"url": "https://plugins.svn.wordpress.org/wp-graphql/",
|
||||||
|
"reference": "tags/2.7.0"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://downloads.wordpress.org/plugin/wp-graphql.2.7.0.zip"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"composer/installers": "^1.0 || ^2.0"
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<ruleset name="wp-boilerplate">
|
<ruleset name="wp-boilerplate">
|
||||||
<rule ref="WebsimpleWP"/>
|
<rule ref="WebsimpleWP"/>
|
||||||
<file>wp-content/themes/wp-boilerplate/</file>
|
<file>wp-content/themes/moonshine/</file>
|
||||||
</ruleset>
|
</ruleset>
|
||||||
|
|||||||
20
wp-content/mu-plugins/headless-home-url.php
Normal file
20
wp-content/mu-plugins/headless-home-url.php
Normal 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 );
|
||||||
|
}
|
||||||
3
wp-content/themes/moonshine/.gitignore
vendored
3
wp-content/themes/moonshine/.gitignore
vendored
@@ -22,3 +22,6 @@ logs
|
|||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
||||||
|
# Wrangler files
|
||||||
|
.wrangler
|
||||||
|
|||||||
1
wp-content/themes/moonshine/.npmrc
Normal file
1
wp-content/themes/moonshine/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
shamefully-hoist=true
|
||||||
@@ -1,5 +1,165 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.5...v0.1.6)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Site options page & field group (489ac82)
|
||||||
|
- Initial SEO integration (c5ce607)
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Bypass headless home URL for specific cases (108269e)
|
||||||
|
|
||||||
|
## v0.1.5
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.4...v0.1.5)
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Auth server utils upgrade to latest nuxt-graphql (fd61895)
|
||||||
|
- Immutable extractNodes (baa3061)
|
||||||
|
- Type issue with NodePage (3b706c0)
|
||||||
|
|
||||||
|
## v0.1.4
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.2...v0.1.4)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Initial NodeByUri logic and frontend (688c4e3)
|
||||||
|
- BuilderSections component (2b9a875)
|
||||||
|
- LaoutContained (c7f6cca)
|
||||||
|
- LayoutContained section wrapper (12048ff)
|
||||||
|
- Initial typography / prose styles (764bc6a)
|
||||||
|
- UiProse prose component with link highjacking (40becf1)
|
||||||
|
- TinyMCE WYSIWYG editor styles (8e26f19)
|
||||||
|
- Login / logout toast (2d0b176)
|
||||||
|
- Hide title on front page (5e0df22)
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Fatal 404 (bfb5ae3)
|
||||||
|
|
||||||
|
### 💅 Refactors
|
||||||
|
|
||||||
|
- Update to nuxt-graphql 0.5.x (e383255)
|
||||||
|
- /api/login route (9d99770)
|
||||||
|
|
||||||
|
## v0.1.3
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.2...v0.1.3)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Initial NodeByUri logic and frontend (688c4e3)
|
||||||
|
- BuilderSections component (2b9a875)
|
||||||
|
- LaoutContained (c7f6cca)
|
||||||
|
- LayoutContained section wrapper (12048ff)
|
||||||
|
- Initial typography / prose styles (764bc6a)
|
||||||
|
- UiProse prose component with link highjacking (40becf1)
|
||||||
|
- TinyMCE WYSIWYG editor styles (8e26f19)
|
||||||
|
- Login / logout toast (2d0b176)
|
||||||
|
- Hide title on front page (5e0df22)
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- Fatal 404 (bfb5ae3)
|
||||||
|
|
||||||
|
### 💅 Refactors
|
||||||
|
|
||||||
|
- Update to nuxt-graphql 0.5.x (e383255)
|
||||||
|
- /api/login route (9d99770)
|
||||||
|
|
||||||
|
## v0.1.2
|
||||||
|
|
||||||
|
[compare changes](https://gitea.websimple.com/templates/wp-headless/compare/v0.1.1...v0.1.2)
|
||||||
|
|
||||||
|
### 🚀 Enhancements
|
||||||
|
|
||||||
|
- Initial Nuxt UI configuration (ca2e660)
|
||||||
|
- Initial layout with SiteHeader / SiteFooter (3d7a2b2)
|
||||||
|
- Update .gitignore and add Copilot instructions (f520db7)
|
||||||
|
- Optional SSL for dev server (9b6a86f)
|
||||||
|
- Typecheck npm script (33589d4)
|
||||||
|
- Initial theme setup (theme features, locale, main menu) (a286047)
|
||||||
|
- Initial GraphQL setup with remote WP schema (d0244eb)
|
||||||
|
- Initial authentication logic and UX (c109423)
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
|
||||||
|
|
||||||
@@ -8,8 +168,3 @@
|
|||||||
- Initial Moonshine theme - Headless WordPress theme based on Nuxt (b3134fe)
|
- Initial Moonshine theme - Headless WordPress theme based on Nuxt (b3134fe)
|
||||||
- CHANGELOG generation using conventional commits (55e16ab)
|
- CHANGELOG generation using conventional commits (55e16ab)
|
||||||
- ESLint configuration (e95bbfb)
|
- ESLint configuration (e95bbfb)
|
||||||
|
|
||||||
### ❤️ Contributors
|
|
||||||
|
|
||||||
- Pascal Martineau <pascal@lewebsimple.ca>
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
# Moonshine
|
# Moonshine
|
||||||
|
|
||||||
Headless WordPress theme based on Nuxt.
|
Thème WordPress en headless basé sur Nuxt.
|
||||||
|
|
||||||
|
## Variables d'environnement
|
||||||
|
|
||||||
|
| Nom | Description | Exemple | Requise |
|
||||||
|
|-----|-------------|---------|---------|
|
||||||
|
| `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
|
||||||
|
```
|
||||||
|
|||||||
252
wp-content/themes/moonshine/acf-json/group_abstract_builder.json
Normal file
252
wp-content/themes/moonshine/acf-json/group_abstract_builder.json
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
{
|
||||||
|
"key": "group_abstract_builder",
|
||||||
|
"title": "Abstract - Builder",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "field_builder_sections",
|
||||||
|
"label": "Section(s)",
|
||||||
|
"name": "sections",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "flexible_content",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 0,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"acfe_flexible_advanced": 1,
|
||||||
|
"acfe_flexible_stylised_button": 0,
|
||||||
|
"acfe_flexible_hide_empty_message": 0,
|
||||||
|
"acfe_flexible_empty_message": "",
|
||||||
|
"acfe_flexible_layouts_templates": 0,
|
||||||
|
"acfe_flexible_layouts_placeholder": 0,
|
||||||
|
"acfe_flexible_layouts_thumbnails": 0,
|
||||||
|
"acfe_flexible_async": [],
|
||||||
|
"acfe_flexible_add_actions": [
|
||||||
|
"copy",
|
||||||
|
"title",
|
||||||
|
"toggle"
|
||||||
|
],
|
||||||
|
"acfe_flexible_remove_button": [],
|
||||||
|
"acfe_flexible_remove_top_actions": [],
|
||||||
|
"acfe_flexible_modal_edit": {
|
||||||
|
"acfe_flexible_modal_edit_enabled": "1",
|
||||||
|
"acfe_flexible_modal_edit_size": "xlarge"
|
||||||
|
},
|
||||||
|
"acfe_flexible_modal": {
|
||||||
|
"acfe_flexible_modal_enabled": "0",
|
||||||
|
"acfe_flexible_modal_title": false,
|
||||||
|
"acfe_flexible_modal_size": "xlarge",
|
||||||
|
"acfe_flexible_modal_col": "4",
|
||||||
|
"acfe_flexible_modal_categories": false
|
||||||
|
},
|
||||||
|
"acfe_flexible_modal_settings": {
|
||||||
|
"acfe_flexible_modal_settings_enabled": "1",
|
||||||
|
"acfe_flexible_modal_settings_size": "large",
|
||||||
|
"acfe_flexible_modal_settings_close": "1",
|
||||||
|
"acfe_flexible_modal_settings_close_label": ""
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"layout_6852f761e95b0": {
|
||||||
|
"key": "layout_6852f761e95b0",
|
||||||
|
"name": "text_block",
|
||||||
|
"label": "Bloc de texte",
|
||||||
|
"display": "block",
|
||||||
|
"sub_fields": [
|
||||||
|
{
|
||||||
|
"key": "field_68eeceb62b8a6",
|
||||||
|
"label": "Contenu",
|
||||||
|
"name": "content",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "wysiwyg",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 1,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"default_value": "",
|
||||||
|
"acfe_wysiwyg_height": 300,
|
||||||
|
"acfe_wysiwyg_max_height": "",
|
||||||
|
"acfe_wysiwyg_valid_elements": "",
|
||||||
|
"acfe_wysiwyg_custom_style": "",
|
||||||
|
"acfe_wysiwyg_disable_wp_style": 0,
|
||||||
|
"acfe_wysiwyg_autoresize": 0,
|
||||||
|
"acfe_wysiwyg_disable_resize": 0,
|
||||||
|
"acfe_wysiwyg_remove_path": 0,
|
||||||
|
"acfe_wysiwyg_menubar": 0,
|
||||||
|
"acfe_wysiwyg_transparent": 0,
|
||||||
|
"acfe_wysiwyg_merge_toolbar": 0,
|
||||||
|
"acfe_wysiwyg_custom_toolbar": 0,
|
||||||
|
"required_message": "",
|
||||||
|
"allow_in_bindings": 0,
|
||||||
|
"tabs": "all",
|
||||||
|
"toolbar": "full",
|
||||||
|
"media_upload": 1,
|
||||||
|
"delay": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_description": "",
|
||||||
|
"graphql_field_name": "content",
|
||||||
|
"graphql_non_null": 1,
|
||||||
|
"acfe_wysiwyg_auto_init": 0,
|
||||||
|
"acfe_wysiwyg_min_height": 300,
|
||||||
|
"acfe_wysiwyg_toolbar_buttons": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"min": "",
|
||||||
|
"max": "",
|
||||||
|
"acfe_flexible_modal_edit_size": "",
|
||||||
|
"acfe_flexible_settings": [
|
||||||
|
"group_layout_contained"
|
||||||
|
],
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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": "",
|
||||||
|
"max": "",
|
||||||
|
"button_label": "Ajouter un élément",
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_description": "",
|
||||||
|
"graphql_field_name": "sections",
|
||||||
|
"graphql_non_null": 0,
|
||||||
|
"acfe_flexible_layouts_previews": false,
|
||||||
|
"acfe_flexible_close_button_label": "",
|
||||||
|
"acfe_flexible_layouts_state": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"param": "abstract"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"menu_order": 0,
|
||||||
|
"position": "acf_after_title",
|
||||||
|
"style": "seamless",
|
||||||
|
"label_placement": "top",
|
||||||
|
"instruction_placement": "label",
|
||||||
|
"hide_on_screen": [
|
||||||
|
"the_content"
|
||||||
|
],
|
||||||
|
"active": true,
|
||||||
|
"description": "",
|
||||||
|
"show_in_rest": 0,
|
||||||
|
"display_title": "",
|
||||||
|
"acfe_autosync": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"acfe_form": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_field_name": "GroupAbstractBuilder",
|
||||||
|
"map_graphql_types_from_location_rules": 0,
|
||||||
|
"graphql_types": "",
|
||||||
|
"acfe_meta": "",
|
||||||
|
"acfe_note": "",
|
||||||
|
"modified": 1769779666
|
||||||
|
}
|
||||||
123
wp-content/themes/moonshine/acf-json/group_abstract_media.json
Normal file
123
wp-content/themes/moonshine/acf-json/group_abstract_media.json
Normal 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
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"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": 1,
|
||||||
|
"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": 1769788591
|
||||||
|
}
|
||||||
149
wp-content/themes/moonshine/acf-json/group_layout_contained.json
Normal file
149
wp-content/themes/moonshine/acf-json/group_layout_contained.json
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
{
|
||||||
|
"key": "group_layout_contained",
|
||||||
|
"title": "Layout - Contained",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "field_68dc29d78941c",
|
||||||
|
"label": "Conteneur",
|
||||||
|
"name": "container",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "select",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 1,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"choices": {
|
||||||
|
"default": "1536px",
|
||||||
|
"xl": "1280px",
|
||||||
|
"lg": "1024px",
|
||||||
|
"fluid": "Largeur fluide",
|
||||||
|
"none": "Pleine largeur"
|
||||||
|
},
|
||||||
|
"default_value": "default",
|
||||||
|
"return_format": "value",
|
||||||
|
"multiple": 0,
|
||||||
|
"max": "",
|
||||||
|
"prepend": "",
|
||||||
|
"append": "",
|
||||||
|
"required_message": "",
|
||||||
|
"allow_null": 0,
|
||||||
|
"allow_in_bindings": 0,
|
||||||
|
"ui": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_description": "",
|
||||||
|
"graphql_field_name": "container",
|
||||||
|
"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": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"param": "abstract"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"menu_order": 0,
|
||||||
|
"position": "normal",
|
||||||
|
"style": "default",
|
||||||
|
"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": "GroupLayoutContained",
|
||||||
|
"map_graphql_types_from_location_rules": 0,
|
||||||
|
"graphql_types": "",
|
||||||
|
"acfe_meta": "",
|
||||||
|
"acfe_note": "",
|
||||||
|
"modified": 1768358794
|
||||||
|
}
|
||||||
158
wp-content/themes/moonshine/acf-json/group_options_site.json
Normal file
158
wp-content/themes/moonshine/acf-json/group_options_site.json
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
"key": "group_options_site",
|
||||||
|
"title": "Options - Site",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "field_697220310aaaf",
|
||||||
|
"label": "Email",
|
||||||
|
"name": "email",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "email",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 1,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"default_value": "",
|
||||||
|
"allow_in_bindings": 0,
|
||||||
|
"placeholder": "",
|
||||||
|
"prepend": "",
|
||||||
|
"append": "",
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_description": "",
|
||||||
|
"graphql_field_name": "email",
|
||||||
|
"graphql_non_null": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "field_697cbf414fdd5",
|
||||||
|
"label": "Phone number",
|
||||||
|
"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": 1,
|
||||||
|
"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,
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"acfe_group_modal_close": 0,
|
||||||
|
"acfe_group_modal_button": "",
|
||||||
|
"acfe_group_modal_size": "large"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"param": "options_page",
|
||||||
|
"operator": "==",
|
||||||
|
"value": "site-options"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"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": "GroupSiteOptions",
|
||||||
|
"map_graphql_types_from_location_rules": 0,
|
||||||
|
"graphql_types": "",
|
||||||
|
"acfe_meta": "",
|
||||||
|
"acfe_note": "",
|
||||||
|
"modified": 1769788698
|
||||||
|
}
|
||||||
66
wp-content/themes/moonshine/acf-json/group_post_page.json
Normal file
66
wp-content/themes/moonshine/acf-json/group_post_page.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"key": "group_post_page",
|
||||||
|
"title": "Post - Page",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"key": "field_690cbda0abcbb",
|
||||||
|
"label": "Constructeur de page",
|
||||||
|
"name": "builder",
|
||||||
|
"aria-label": "",
|
||||||
|
"type": "clone",
|
||||||
|
"instructions": "",
|
||||||
|
"required": 0,
|
||||||
|
"conditional_logic": 0,
|
||||||
|
"wrapper": {
|
||||||
|
"width": "",
|
||||||
|
"class": "",
|
||||||
|
"id": ""
|
||||||
|
},
|
||||||
|
"graphql_field_name": "builder",
|
||||||
|
"clone": [
|
||||||
|
"group_abstract_builder"
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"param": "post_type",
|
||||||
|
"operator": "==",
|
||||||
|
"value": "page"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"menu_order": 0,
|
||||||
|
"position": "normal",
|
||||||
|
"style": "seamless",
|
||||||
|
"label_placement": "top",
|
||||||
|
"instruction_placement": "label",
|
||||||
|
"hide_on_screen": [
|
||||||
|
"the_content"
|
||||||
|
],
|
||||||
|
"active": true,
|
||||||
|
"description": "",
|
||||||
|
"show_in_rest": 0,
|
||||||
|
"display_title": "",
|
||||||
|
"acfe_autosync": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"acfe_form": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_field_name": "GroupPostPage",
|
||||||
|
"map_graphql_types_from_location_rules": 0,
|
||||||
|
"graphql_types": "",
|
||||||
|
"acfe_meta": "",
|
||||||
|
"acfe_note": "",
|
||||||
|
"modified": 1768336934
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"key": "ui_options_page_site",
|
||||||
|
"title": "Options du site",
|
||||||
|
"active": true,
|
||||||
|
"menu_order": 0,
|
||||||
|
"page_title": "Options du site",
|
||||||
|
"menu_slug": "site-options",
|
||||||
|
"parent_slug": "options-general.php",
|
||||||
|
"advanced_configuration": 1,
|
||||||
|
"icon_url": "",
|
||||||
|
"menu_title": "",
|
||||||
|
"position": "",
|
||||||
|
"redirect": false,
|
||||||
|
"description": "",
|
||||||
|
"menu_icon": [],
|
||||||
|
"update_button": "Mise à jour",
|
||||||
|
"updated_message": "Options mises à jours",
|
||||||
|
"capability": "edit_posts",
|
||||||
|
"data_storage": "options",
|
||||||
|
"post_id": "",
|
||||||
|
"autoload": 0,
|
||||||
|
"show_in_graphql": 1,
|
||||||
|
"graphql_type_name": "SiteOptions",
|
||||||
|
"modified": 1769693948
|
||||||
|
}
|
||||||
13
wp-content/themes/moonshine/app/app.config.ts
Normal file
13
wp-content/themes/moonshine/app/app.config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export default defineAppConfig({
|
||||||
|
ui: {
|
||||||
|
colors: {
|
||||||
|
primary: "indigo",
|
||||||
|
neutral: "neutral",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
slots: {
|
||||||
|
base: "cursor-pointer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
10
wp-content/themes/moonshine/app/assets/css/_main.css
Normal file
10
wp-content/themes/moonshine/app/assets/css/_main.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@import "tailwindcss" theme(static) source("../../..");
|
||||||
|
@import "@nuxt/ui";
|
||||||
|
|
||||||
|
@import "./a11y.css";
|
||||||
|
@import "./containers.css";
|
||||||
|
@import "./links.css";
|
||||||
|
@import "./prose.css";
|
||||||
|
@import "./typography.css";
|
||||||
|
|
||||||
|
@import "./vendors/tinymce.css";
|
||||||
7
wp-content/themes/moonshine/app/assets/css/a11y.css
Normal file
7
wp-content/themes/moonshine/app/assets/css/a11y.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@utility disabled-default {
|
||||||
|
@apply disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility focus-default {
|
||||||
|
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2;
|
||||||
|
}
|
||||||
47
wp-content/themes/moonshine/app/assets/css/containers.css
Normal file
47
wp-content/themes/moonshine/app/assets/css/containers.css
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
:root {
|
||||||
|
--ui-container: var(--breakpoint-2xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Container padding */
|
||||||
|
@utility px-container {
|
||||||
|
@apply px-4 sm:px-6 lg:px-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Container sizes */
|
||||||
|
@utility container { @apply mx-auto px-container max-w-(--breakpoint-2xl); }
|
||||||
|
@utility container-xl { @apply container max-w-(--breakpoint-xl); }
|
||||||
|
@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 */
|
||||||
|
:root {
|
||||||
|
--container-outside-margin: 0;
|
||||||
|
--container-width: 100vw;
|
||||||
|
@variant sm {
|
||||||
|
--container-outside-margin: calc(50vw - theme("screens.sm") / 2);
|
||||||
|
--container-width: theme("screens.sm");
|
||||||
|
}
|
||||||
|
@variant md {
|
||||||
|
--container-outside-margin: calc(50vw - theme("screens.md") / 2);
|
||||||
|
--container-width: theme("screens.md");
|
||||||
|
}
|
||||||
|
@variant lg {
|
||||||
|
--container-outside-margin: calc(50vw - theme("screens.lg") / 2);
|
||||||
|
--container-width: theme("screens.lg");
|
||||||
|
}
|
||||||
|
@variant xl {
|
||||||
|
--container-outside-margin: calc(50vw - theme("screens.xl") / 2);
|
||||||
|
--container-width: theme("screens.xl");
|
||||||
|
}
|
||||||
|
@variant 2xl {
|
||||||
|
--container-outside-margin: calc(50vw - theme("screens.2xl") / 2);
|
||||||
|
--container-width: theme("screens.2xl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility container-left { @apply ml-(--container-outside-margin) px-container;}
|
||||||
|
@utility container-right { @apply mr-(--container-outside-margin) px-container;}
|
||||||
|
@utility container-half { width: calc(var(--container-width) / 2);}
|
||||||
7
wp-content/themes/moonshine/app/assets/css/links.css
Normal file
7
wp-content/themes/moonshine/app/assets/css/links.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/* Variant to target all children links without specific link or button classes */
|
||||||
|
@custom-variant links (& a:not([class*='link-']):not([class*='button-']));
|
||||||
|
|
||||||
|
/* Link styles */
|
||||||
|
@utility link-base { @apply cursor-pointer disabled-default transition; }
|
||||||
|
@utility link-underline { @apply link-base underline hover:decoration-primary; }
|
||||||
|
@utility link-opacity { @apply link-base hover:opacity-80; }
|
||||||
16
wp-content/themes/moonshine/app/assets/css/prose.css
Normal file
16
wp-content/themes/moonshine/app/assets/css/prose.css
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@utility prose {
|
||||||
|
/* Headings (allow class overrides) */
|
||||||
|
h1:not([class*="heading-"]) { @apply heading-1; }
|
||||||
|
h2:not([class*="heading-"]) { @apply heading-2; }
|
||||||
|
h3:not([class*="heading-"]) { @apply heading-3; }
|
||||||
|
h4:not([class*="heading-"]) { @apply heading-4; }
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
@apply links:link-underline;
|
||||||
|
|
||||||
|
/* Paragraphs */
|
||||||
|
p:not([class*="paragraph-"]) { @apply paragraph-base; }
|
||||||
|
|
||||||
|
/* Spacing */
|
||||||
|
@apply space-y-2;
|
||||||
|
}
|
||||||
10
wp-content/themes/moonshine/app/assets/css/typography.css
Normal file
10
wp-content/themes/moonshine/app/assets/css/typography.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* Heading styles */
|
||||||
|
@utility heading-base { @apply font-bold tracking-tight };
|
||||||
|
@utility heading-1 { @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 */
|
||||||
|
@utility paragraph-base { @apply font-sans; }
|
||||||
|
@utility paragraph-lead { @apply paragraph-base text-2xl; }
|
||||||
3
wp-content/themes/moonshine/app/assets/css/vendors/tinymce.css
vendored
Normal file
3
wp-content/themes/moonshine/app/assets/css/vendors/tinymce.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
body#tinymce {
|
||||||
|
@apply prose;
|
||||||
|
}
|
||||||
4
wp-content/themes/moonshine/app/assets/svg/site-logo.svg
Normal file
4
wp-content/themes/moonshine/app/assets/svg/site-logo.svg
Normal 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 |
@@ -0,0 +1,9 @@
|
|||||||
|
fragment AcfImage on MediaItem {
|
||||||
|
src: sourceUrl
|
||||||
|
alt: altText
|
||||||
|
mediaDetails {
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
objectPosition
|
||||||
|
}
|
||||||
17
wp-content/themes/moonshine/app/components/acf/AcfImage.vue
Normal file
17
wp-content/themes/moonshine/app/components/acf/AcfImage.vue
Normal 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>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fragment AcfLink on AcfLink {
|
||||||
|
title
|
||||||
|
url
|
||||||
|
target
|
||||||
|
}
|
||||||
23
wp-content/themes/moonshine/app/components/acf/AcfLink.vue
Normal file
23
wp-content/themes/moonshine/app/components/acf/AcfLink.vue
Normal 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>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<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;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { link, ...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>{{ link.title }}</slot>
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fragment AcfMedia on GroupAbstractMedia_Fields {
|
||||||
|
image {
|
||||||
|
node {
|
||||||
|
...AcfImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aspectRatio
|
||||||
|
objectFit
|
||||||
|
}
|
||||||
36
wp-content/themes/moonshine/app/components/acf/AcfMedia.vue
Normal file
36
wp-content/themes/moonshine/app/components/acf/AcfMedia.vue
Normal 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>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fragment AcfPhone on AcfPhone {
|
||||||
|
national
|
||||||
|
e164
|
||||||
|
extension
|
||||||
|
}
|
||||||
14
wp-content/themes/moonshine/app/components/acf/AcfPhone.vue
Normal file
14
wp-content/themes/moonshine/app/components/acf/AcfPhone.vue
Normal 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>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fragment AcfSocial on GroupAbstractSocial_Fields {
|
||||||
|
profiles {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
11
wp-content/themes/moonshine/app/components/acf/AcfSocial.vue
Normal file
11
wp-content/themes/moonshine/app/components/acf/AcfSocial.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<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>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<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>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { login } = useAuthConnexion();
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: "username",
|
||||||
|
type: "text" as const,
|
||||||
|
label: "Courriel",
|
||||||
|
placeholder: "Entrez votre courriel",
|
||||||
|
required: true,
|
||||||
|
}, {
|
||||||
|
name: "password",
|
||||||
|
label: "Mot de passe",
|
||||||
|
type: "password" as const,
|
||||||
|
placeholder: "Entrez votre mot de passe",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UAuthForm
|
||||||
|
:schema="authLoginFormSchema"
|
||||||
|
:fields="fields"
|
||||||
|
title="Connexion"
|
||||||
|
description="Veuillez vous identifier."
|
||||||
|
loading-auto
|
||||||
|
@submit="login"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { logout } = useAuthConnexion();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full space-y-6">
|
||||||
|
<div class="flex flex-col text-center">
|
||||||
|
<div class="text-xl text-pretty font-semibold text-highlighted">
|
||||||
|
Déconnexion
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 text-base text-pretty text-muted">
|
||||||
|
Veuillez confirmer la déconnexion.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<UButton
|
||||||
|
icon="i-lucide-log-out"
|
||||||
|
block
|
||||||
|
loading-auto
|
||||||
|
to="#"
|
||||||
|
label="Déconnexion"
|
||||||
|
@click="logout()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="w-full space-y-6">
|
||||||
|
<div class="flex flex-col text-center">
|
||||||
|
<div class="text-xl text-pretty font-semibold text-highlighted">
|
||||||
|
Redirection en cours
|
||||||
|
</div>
|
||||||
|
<div class="mt-1 text-base text-pretty text-muted">
|
||||||
|
Veuillez patienter...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fragment BuilderSections on GroupAbstractBuilder_Fields {
|
||||||
|
sections {
|
||||||
|
__typename
|
||||||
|
... on GroupAbstractBuilderSectionsHeroSplitLayout { ... SectionHeroSplit }
|
||||||
|
... on GroupAbstractBuilderSectionsTextBlockLayout { ... SectionTextBlock }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { BuilderSectionsFragment } from "#graphql/operations";
|
||||||
|
|
||||||
|
const props = defineProps<BuilderSectionsFragment>();
|
||||||
|
const sections = computed(() => {
|
||||||
|
return (props.sections || [])
|
||||||
|
.filter((section) => !!section)
|
||||||
|
.map(({ __typename, ...attrs }) => ({
|
||||||
|
componentName: __typename.replace(/^GroupAbstractBuilderSections(.+?)Layout$/, "Section$1"),
|
||||||
|
attrs,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="builder-sections">
|
||||||
|
<Component
|
||||||
|
:is="componentName"
|
||||||
|
v-for="({ componentName, attrs }, index) in sections"
|
||||||
|
:key="index"
|
||||||
|
v-bind="attrs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fragment LayoutContained on GroupLayoutContained_Fields {
|
||||||
|
container
|
||||||
|
verticalPadding
|
||||||
|
bgColor
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<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>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fragment NodePage on Page {
|
||||||
|
title
|
||||||
|
isFrontPage
|
||||||
|
groupPostPage {
|
||||||
|
... BuilderSections
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { NodePageFragment } from "#graphql/operations";
|
||||||
|
|
||||||
|
defineProps<NodePageFragment>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="node-page">
|
||||||
|
<h1 v-if="!isFrontPage" class="font-bold text-4xl">
|
||||||
|
{{ title }}
|
||||||
|
</h1>
|
||||||
|
<BuilderSections :sections="groupPostPage?.sections || []" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { isLoggedIn } = useAuth();
|
||||||
|
const { isRedirecting } = useAuthConnexion();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section data-section-name="auth-connexion" class="py-12">
|
||||||
|
<div class="container-sm">
|
||||||
|
<AuthState>
|
||||||
|
<AuthRedirecting v-if="isRedirecting" />
|
||||||
|
<template v-else>
|
||||||
|
<AuthLogoutForm v-if="isLoggedIn" />
|
||||||
|
<AuthLoginForm v-else />
|
||||||
|
</template>
|
||||||
|
</AuthState>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fragment SectionHeroSplit on GroupAbstractBuilderSectionsHeroSplitLayout {
|
||||||
|
content
|
||||||
|
reverse
|
||||||
|
...AcfMedia
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fragment SectionTextBlock on GroupAbstractBuilderSectionsTextBlockLayout {
|
||||||
|
content
|
||||||
|
layoutSettings {
|
||||||
|
...LayoutContained
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { SectionTextBlockFragment } from "#graphql/operations";
|
||||||
|
|
||||||
|
defineProps<SectionTextBlockFragment>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<LayoutContained data-section-type="text-block" v-bind="layoutSettings!">
|
||||||
|
<UiProse :content="content" />
|
||||||
|
</LayoutContained>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { data: siteOptions } = await useSiteOptions();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<footer class="bg-accented links:link-prose">
|
||||||
|
<div class="container py-6">
|
||||||
|
<AcfSocial :social="parseAcfSocial(siteOptions)" />
|
||||||
|
</div>
|
||||||
|
<SiteFooterBottom />
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-inverted text-inverted py-1.5">
|
||||||
|
<div class="container flex flex-col sm:flex-row items-center gap-3">
|
||||||
|
<SiteFooterCopyright class="sm:mr-auto" />
|
||||||
|
<AuthConnexionButton color="neutral" variant="link" />
|
||||||
|
<SiteFooterCredits />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { data: generalSettings } = await useGeneralSettings();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
© {{ new Date().getFullYear() }}
|
||||||
|
<span v-if="generalSettings?.title">{{ generalSettings.title }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UHeader mode="slideover">
|
||||||
|
<template #left>
|
||||||
|
<NuxtLink to="/">
|
||||||
|
<SvgSiteLogo class="h-12 w-auto" />
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
<template #right>
|
||||||
|
<AuthConnexionButton />
|
||||||
|
</template>
|
||||||
|
</UHeader>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{ content: string }>();
|
||||||
|
const refContent = useTemplateRef("refContent");
|
||||||
|
useProseLinks(refContent);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="refContent" class="prose" v-html="content" />
|
||||||
|
</template>
|
||||||
6
wp-content/themes/moonshine/app/composables/useAuth.ts
Normal file
6
wp-content/themes/moonshine/app/composables/useAuth.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export function useAuth() {
|
||||||
|
const { loggedIn: isLoggedIn, session } = useUserSession();
|
||||||
|
const hasRole = (role: string) => session.value?.user?.roles?.includes(role) || false;
|
||||||
|
const isAdmin = computed(() => hasRole("administrator"));
|
||||||
|
return { isLoggedIn, hasRole, isAdmin };
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import type { FormSubmitEvent } from "@nuxt/ui";
|
||||||
|
|
||||||
|
const isRedirecting = ref(false);
|
||||||
|
|
||||||
|
export function useAuthConnexion() {
|
||||||
|
const toast = useToast();
|
||||||
|
const { fetch: refreshUserSession } = useUserSession();
|
||||||
|
const routeRedirect = useRoute().query.redirect as string || undefined;
|
||||||
|
|
||||||
|
// Helper: Redirect after login / logout
|
||||||
|
async function redirectTo(to: string | undefined) {
|
||||||
|
isRedirecting.value = true;
|
||||||
|
await delay(1000);
|
||||||
|
await refreshUserSession();
|
||||||
|
await navigateTo(to || routeRedirect || "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login
|
||||||
|
async function login({ data: body }: FormSubmitEvent<AuthLoginForm>, redirect?: string) {
|
||||||
|
try {
|
||||||
|
const { success, message } = await $fetch("/api/login", { method: "POST", body });
|
||||||
|
if (!success) {
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
toast.add({
|
||||||
|
title: "Connexion réussie",
|
||||||
|
color: "success",
|
||||||
|
description: message,
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
await redirectTo(redirect);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.add({
|
||||||
|
title: "Erreur de connexion",
|
||||||
|
color: "error",
|
||||||
|
description: error instanceof Error ? error.message : "Une erreur est survenue lors de la connexion.",
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logout
|
||||||
|
async function logout(redirect?: string) {
|
||||||
|
try {
|
||||||
|
const result = await $fetch("/api/logout", { method: "POST" });
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error("Échec de la déconnexion.");
|
||||||
|
}
|
||||||
|
toast.add({
|
||||||
|
title: "Déconnexion réussie",
|
||||||
|
color: "success",
|
||||||
|
description: "Vous avez été déconnecté avec succès.",
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
await redirectTo(redirect);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.add({
|
||||||
|
title: "Erreur de déconnexion",
|
||||||
|
color: "error",
|
||||||
|
description: error instanceof Error ? error.message : "Une erreur est survenue lors de la déconnexion.",
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { isRedirecting, login, logout };
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export const useGeneralSettings = () => useAsyncGraphQLQuery("GeneralSettings", {}, {
|
||||||
|
transform: ({ generalSettings }) => generalSettings,
|
||||||
|
});
|
||||||
20
wp-content/themes/moonshine/app/composables/useNodeSeo.ts
Normal file
20
wp-content/themes/moonshine/app/composables/useNodeSeo.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import type { NodeByUriQueryResult, NodeSeoFragment } from "#graphql/operations";
|
||||||
|
|
||||||
|
export function useNodeSeo(node: NodeByUriQueryResult["nodeByUri"]) {
|
||||||
|
// Check if node has SEO data
|
||||||
|
if (!node || !("seo" in node) || !node.seo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { seo } = node as NodeSeoFragment;
|
||||||
|
|
||||||
|
useSeoMeta({
|
||||||
|
title: seo?.title || undefined,
|
||||||
|
description: seo?.description || undefined,
|
||||||
|
robots: (seo?.robots || []).join(", "),
|
||||||
|
ogTitle: seo?.openGraph?.title || undefined,
|
||||||
|
ogDescription: seo?.openGraph?.description || undefined,
|
||||||
|
ogImage: seo?.openGraph?.image?.url || undefined,
|
||||||
|
ogUrl: seo?.canonicalUrl || undefined,
|
||||||
|
twitterCard: "summary_large_image",
|
||||||
|
});
|
||||||
|
}
|
||||||
65
wp-content/themes/moonshine/app/composables/useProseLinks.ts
Normal file
65
wp-content/themes/moonshine/app/composables/useProseLinks.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
export function useProseLinks(refContent: Ref<HTMLElement | null>) {
|
||||||
|
const router = useRouter();
|
||||||
|
const { url } = useSiteConfig();
|
||||||
|
const siteUrl = new URL(url);
|
||||||
|
|
||||||
|
// Determine if the href is internal
|
||||||
|
const isInternal = (href: string) => {
|
||||||
|
if (!href) return false;
|
||||||
|
if (href.startsWith("/")) return true;
|
||||||
|
if (href.startsWith("#")) return false;
|
||||||
|
try {
|
||||||
|
const hrefUrl = new URL(href);
|
||||||
|
return hrefUrl.hostname === siteUrl.hostname;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert href to relative path
|
||||||
|
const convertToRelative = (href: string) => {
|
||||||
|
if (href.startsWith("/")) return href;
|
||||||
|
try {
|
||||||
|
const hrefUrl = new URL(href);
|
||||||
|
if (hrefUrl.hostname === siteUrl.hostname) {
|
||||||
|
return hrefUrl.pathname + hrefUrl.search + hrefUrl.hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// Invalid URL
|
||||||
|
}
|
||||||
|
return href;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Highjack click events to use router for internal links
|
||||||
|
const handleClick = (e: MouseEvent) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const link = target.closest("a");
|
||||||
|
if (!link) return;
|
||||||
|
const href = link.getAttribute("href");
|
||||||
|
if (!href) return;
|
||||||
|
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || link.target === "_blank" || link.hasAttribute("download")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isInternal(href)) {
|
||||||
|
e.preventDefault();
|
||||||
|
const path = convertToRelative(href);
|
||||||
|
router.push(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attach and detach event listeners
|
||||||
|
onMounted(() => {
|
||||||
|
const element = unref(refContent);
|
||||||
|
if (element) {
|
||||||
|
element.addEventListener("click", handleClick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const element = unref(refContent);
|
||||||
|
if (element) {
|
||||||
|
element.removeEventListener("click", handleClick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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 };
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export const useSiteOptions = () => useAsyncGraphQLQuery("SiteOptions", {}, {
|
||||||
|
transform: ({ siteOptions }) => siteOptions?.groupSiteOptions,
|
||||||
|
});
|
||||||
28
wp-content/themes/moonshine/app/error.vue
Normal file
28
wp-content/themes/moonshine/app/error.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { fr } from "@nuxt/ui/locale";
|
||||||
|
import type { NuxtError } from "#app";
|
||||||
|
|
||||||
|
const props = defineProps<{ error: NuxtError }>();
|
||||||
|
const formattedError = computed(() => {
|
||||||
|
const error = {
|
||||||
|
statusCode: props.error.statusCode,
|
||||||
|
statusMessage: props.error.statusMessage,
|
||||||
|
message: props.error.message,
|
||||||
|
};
|
||||||
|
switch (error.statusCode) {
|
||||||
|
case 404:
|
||||||
|
error.statusMessage = "Page non trouvée";
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
error.message = "Erreur interne du serveur.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UApp :locale="fr">
|
||||||
|
<UError :error="formattedError" />
|
||||||
|
</UApp>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
fragment AuthUser on User {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
roles {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation AuthLogin($username: String!, $password: String!) {
|
||||||
|
login( input: { provider: PASSWORD, credentials: { username: $username, password: $password }}) {
|
||||||
|
authToken
|
||||||
|
refreshToken
|
||||||
|
user {
|
||||||
|
... AuthUser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
mutation AuthRefreshToken($refreshToken: String!) {
|
||||||
|
refreshToken( input: { refreshToken: $refreshToken }) {
|
||||||
|
authToken
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fragment GeneralSettings on GeneralSettings {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
|
|
||||||
|
query GeneralSettings {
|
||||||
|
generalSettings {
|
||||||
|
... GeneralSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
27
wp-content/themes/moonshine/app/graphql/NodebyUri.query.gql
Normal file
27
wp-content/themes/moonshine/app/graphql/NodebyUri.query.gql
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
fragment NodeSeo on NodeWithRankMathSeo {
|
||||||
|
seo {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
robots
|
||||||
|
canonicalUrl
|
||||||
|
openGraph {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
image {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query NodeByUri($uri: String!) {
|
||||||
|
nodeByUri(uri: $uri) {
|
||||||
|
__typename
|
||||||
|
... on Page {
|
||||||
|
... NodePage
|
||||||
|
}
|
||||||
|
... on NodeWithRankMathSeo {
|
||||||
|
... NodeSeo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
fragment SiteOptions on GroupSiteOptions {
|
||||||
|
email
|
||||||
|
phoneNumber { ... AcfPhone }
|
||||||
|
...AcfSocial
|
||||||
|
links {
|
||||||
|
contact { ... AcfLink}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query SiteOptions {
|
||||||
|
siteOptions {
|
||||||
|
groupSiteOptions {
|
||||||
|
... SiteOptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { fr } from "@nuxt/ui/locale";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="layout-default">
|
<UApp id="layout-default" :locale="fr">
|
||||||
<NuxtPage />
|
<SiteHeader />
|
||||||
</div>
|
<UMain>
|
||||||
|
<slot />
|
||||||
|
</UMain>
|
||||||
|
<SiteFooter />
|
||||||
|
</UApp>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,8 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
// Fetch node by URI and handle query errors
|
||||||
|
const { path: uri } = useRoute();
|
||||||
|
const { data, error } = await useAsyncGraphQLQuery("NodeByUri", { uri });
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamically resolve component based on node type
|
||||||
|
const componentName = `Node${data.value.nodeByUri.__typename}`;
|
||||||
|
if (!useNuxtApp().vueApp.component(componentName)) {
|
||||||
|
throw createError({ statusCode: 404, message: `La page demandée ne peut pas être affichée correctement: ${componentName}`, fatal: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
useNodeSeo(data.value.nodeByUri);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="page-node-from-uri">
|
<div v-if="data?.nodeByUri" id="page-node-from-uri">
|
||||||
<h1>Moonshine</h1>
|
<Component :is="componentName" v-bind="data.nodeByUri" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
12
wp-content/themes/moonshine/app/pages/connexion.vue
Normal file
12
wp-content/themes/moonshine/app/pages/connexion.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { isRedirecting } = useAuthConnexion();
|
||||||
|
onBeforeMount(() => {
|
||||||
|
isRedirecting.value = false;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="page-connexion">
|
||||||
|
<SectionAuthConnexion />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
32
wp-content/themes/moonshine/app/utils/acf-social.ts
Normal file
32
wp-content/themes/moonshine/app/utils/acf-social.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import * as z from "zod";
|
||||||
|
import type { AcfSocialFragment } from "#graphql/operations";
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
2
wp-content/themes/moonshine/editor-style.css
Normal file
2
wp-content/themes/moonshine/editor-style.css
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// Core
|
||||||
|
require_once __DIR__ . '/includes/core/theme-setup.php';
|
||||||
|
|
||||||
|
// Vendors
|
||||||
|
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/wpgraphql.php';
|
||||||
|
|
||||||
|
// WPGraphQL
|
||||||
|
require_once __DIR__ . '/includes/wpgraphql/media-focus-point.php';
|
||||||
|
require_once __DIR__ . '/includes/wpgraphql/term-connection.php';
|
||||||
|
|||||||
4
wp-content/themes/moonshine/graphql.config.json
Normal file
4
wp-content/themes/moonshine/graphql.config.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"schema": "./server/graphql/schema.graphql",
|
||||||
|
"documents": "**/*.gql"
|
||||||
|
}
|
||||||
27
wp-content/themes/moonshine/includes/core/theme-setup.php
Normal file
27
wp-content/themes/moonshine/includes/core/theme-setup.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Setup theme
|
||||||
|
add_action( 'after_setup_theme', 'moonshine_after_setup_theme' );
|
||||||
|
function moonshine_after_setup_theme() {
|
||||||
|
// Load textdomain
|
||||||
|
load_theme_textdomain( 'moonshine', get_theme_file_path( 'languages' ) );
|
||||||
|
|
||||||
|
// Theme features
|
||||||
|
add_theme_support( 'custom-logo' );
|
||||||
|
add_theme_support( 'editor-styles' );
|
||||||
|
remove_theme_support( 'core-block-patterns' );
|
||||||
|
|
||||||
|
// Register menus
|
||||||
|
register_nav_menu( 'main', __( "Main menu", 'moonshine' ) );
|
||||||
|
|
||||||
|
// Register sidebars
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display theme version in admin footer
|
||||||
|
add_filter( 'update_footer', 'moonshine_update_footer', 100 );
|
||||||
|
function moonshine_update_footer() {
|
||||||
|
$package_json = json_decode( file_get_contents( get_theme_file_path( 'package.json' ) ), true );
|
||||||
|
$name = $package_json['name'] ?? 'moonshine';
|
||||||
|
$version = $package_json['version'] ?? '(unknown)';
|
||||||
|
return sprintf( '%s v%s', esc_html( $name ), esc_html( $version ) );
|
||||||
|
}
|
||||||
15
wp-content/themes/moonshine/includes/vendors/acf.php
vendored
Normal file
15
wp-content/themes/moonshine/includes/vendors/acf.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Disable ACF / ACFE modules
|
||||||
|
add_filter( 'acf/settings/enable_post_types', '__return_false' );
|
||||||
|
add_action( 'acf/init', 'moonshine_acf_init' );
|
||||||
|
function moonshine_acf_init() {
|
||||||
|
acf_update_setting( 'acfe/modules/block_types', false );
|
||||||
|
acf_update_setting( 'acfe/modules/categories', false );
|
||||||
|
acf_update_setting( 'acfe/modules/forms', false );
|
||||||
|
acf_update_setting( 'acfe/modules/options', false );
|
||||||
|
acf_update_setting( 'acfe/modules/options_pages', false );
|
||||||
|
acf_update_setting( 'acfe/modules/post_types', false );
|
||||||
|
acf_update_setting( 'acfe/modules/taxonomies', false );
|
||||||
|
acf_update_setting( 'acfe/modules/templates', false );
|
||||||
|
}
|
||||||
1
wp-content/themes/moonshine/includes/vendors/rankmath.php
vendored
Normal file
1
wp-content/themes/moonshine/includes/vendors/rankmath.php
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?php
|
||||||
129
wp-content/themes/moonshine/includes/vendors/tinymce.php
vendored
Normal file
129
wp-content/themes/moonshine/includes/vendors/tinymce.php
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Enable formats (styleselect) in TinyMCE
|
||||||
|
add_filter( 'mce_buttons', 'moonshine_tinymce_styleselect' );
|
||||||
|
function moonshine_tinymce_styleselect( $buttons ) {
|
||||||
|
array_unshift( $buttons, 'styleselect' );
|
||||||
|
return $buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure TinyMCE
|
||||||
|
add_filter( 'tiny_mce_before_init', 'moonshine_tiny_mce_before_init' );
|
||||||
|
function moonshine_tiny_mce_before_init( $settings ) {
|
||||||
|
// Reset TinyMCE editor CSS
|
||||||
|
if ( isset( $settings['content_css'] ) ) {
|
||||||
|
$content_css = explode( ',', $settings['content_css'] );
|
||||||
|
unset( $content_css[1] ); // wp-content.min.css
|
||||||
|
$settings['content_css'] = implode( ',', $content_css );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format styles
|
||||||
|
$settings['style_formats'] = wp_json_encode(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'title' => __( "Link styles", 'moonshine' ),
|
||||||
|
'items' => array(// Link styles
|
||||||
|
array(
|
||||||
|
'title' => "Lien (opacité)",
|
||||||
|
'selector' => 'a',
|
||||||
|
'classes' => 'link-opacity',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => __( "Inline styles", 'moonshine' ),
|
||||||
|
'items' => array(// Inline styles
|
||||||
|
array(
|
||||||
|
'title' => __( "Semi-bold", 'moonshine' ),
|
||||||
|
'inline' => 'span',
|
||||||
|
'classes' => 'font-semibold',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => __( "Paragraph styles", 'moonshine' ),
|
||||||
|
'items' => array(// Paragraph styles
|
||||||
|
array(
|
||||||
|
'title' => "Paragraphe vedette",
|
||||||
|
'block' => 'p',
|
||||||
|
'classes' => 'paragraph-lead',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => __( "Heading styles", 'moonshine' ),
|
||||||
|
'items' => array(// Heading styles
|
||||||
|
array(
|
||||||
|
'title' => "Titre 1",
|
||||||
|
'selector' => 'h1,h2,h3,h4',
|
||||||
|
'classes' => 'heading-1',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => "Titre 2",
|
||||||
|
'selector' => 'h1,h2,h3,h4',
|
||||||
|
'classes' => 'heading-2',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => "Titre 3",
|
||||||
|
'selector' => 'h1,h2,h3,h4',
|
||||||
|
'classes' => 'heading-3',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => "Titre 4",
|
||||||
|
'selector' => 'h1,h2,h3,h4',
|
||||||
|
'classes' => 'heading-4',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Block styles
|
||||||
|
$settings['block_formats'] = implode(
|
||||||
|
';',
|
||||||
|
array(
|
||||||
|
'Paragraph=p',
|
||||||
|
'Heading 1=h1',
|
||||||
|
'Heading 2=h2',
|
||||||
|
'Heading 3=h3',
|
||||||
|
'Heading 4=h4',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override TinyMCE editor styles
|
||||||
|
add_filter( 'mce_css', 'moonshine_override_editor_styles' );
|
||||||
|
function moonshine_override_editor_styles() {
|
||||||
|
return get_stylesheet_directory_uri() . '/editor-style.css';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove default TinyMCE styles for all editors (WordPress & ACF)
|
||||||
|
add_action( 'admin_print_footer_scripts', 'moonshine_remove_tinymce_default_styles', 99 );
|
||||||
|
function moonshine_remove_tinymce_default_styles() {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
(function($) {
|
||||||
|
if (typeof tinymce !== 'undefined') {
|
||||||
|
tinymce.on('AddEditor', function({editor}) {
|
||||||
|
editor.on('init', function() {
|
||||||
|
$(editor.iframeElement).contents().find("link[href*='content.min.css']").remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
// Convert absolute URLs to relative in link query
|
||||||
|
add_filter( 'wp_link_query', 'moonshine_tinymce_relative_urls' );
|
||||||
|
function moonshine_tinymce_relative_urls( $results ) {
|
||||||
|
foreach ( $results as &$result ) {
|
||||||
|
if ( empty( $result['permalink'] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$result['permalink'] = str_replace( get_home_url(), '', $result['permalink'] );
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
17
wp-content/themes/moonshine/includes/vendors/wpgraphql.php
vendored
Normal file
17
wp-content/themes/moonshine/includes/vendors/wpgraphql.php
vendored
Normal 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;
|
||||||
|
}
|
||||||
@@ -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 );
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
2
wp-content/themes/moonshine/languages/fr_CA.l10n.php
Normal file
2
wp-content/themes/moonshine/languages/fr_CA.l10n.php
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
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']];
|
||||||
BIN
wp-content/themes/moonshine/languages/fr_CA.mo
Normal file
BIN
wp-content/themes/moonshine/languages/fr_CA.mo
Normal file
Binary file not shown.
56
wp-content/themes/moonshine/languages/fr_CA.po
Normal file
56
wp-content/themes/moonshine/languages/fr_CA.po
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Moonshine\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-01-13 15:52+0000\n"
|
||||||
|
"PO-Revision-Date: 2026-01-29 02:55+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: Français du Canada\n"
|
||||||
|
"Language: fr_CA\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: Loco https://localise.biz/\n"
|
||||||
|
"X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n"
|
||||||
|
"X-Domain: moonshine"
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:54
|
||||||
|
msgid "Heading styles"
|
||||||
|
msgstr "Styles de titres"
|
||||||
|
|
||||||
|
#. Description of the theme
|
||||||
|
msgid "Headless WordPress theme based on Nuxt."
|
||||||
|
msgstr "Thème Wordpress headless basé sur Nuxt."
|
||||||
|
|
||||||
|
#. Author URI of the theme
|
||||||
|
msgid "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
|
||||||
|
msgid "Main menu"
|
||||||
|
msgstr "Menu principal"
|
||||||
|
|
||||||
|
#. Name of the theme
|
||||||
|
msgid "Moonshine"
|
||||||
|
msgstr "Moonshine"
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:44
|
||||||
|
msgid "Paragraph styles"
|
||||||
|
msgstr "Styles de paragraphes"
|
||||||
|
|
||||||
|
#. Author of the theme
|
||||||
|
msgid "Pascal Martineau "
|
||||||
|
msgstr "Pascal Martineau "
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:37
|
||||||
|
msgid "Semi-bold"
|
||||||
|
msgstr "Semi-gras"
|
||||||
57
wp-content/themes/moonshine/languages/moonshine.pot
Normal file
57
wp-content/themes/moonshine/languages/moonshine.pot
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Moonshine\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-01-29 02:55+0000\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Language: \n"
|
||||||
|
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: Loco https://localise.biz/\n"
|
||||||
|
"X-Loco-Version: 2.8.1; wp-6.9; php-8.3.27\n"
|
||||||
|
"X-Domain: moonshine"
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:54
|
||||||
|
msgid "Heading styles"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Description of the theme
|
||||||
|
msgid "Headless WordPress theme based on Nuxt."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Author URI of the theme
|
||||||
|
msgid "https://websimple.com/"
|
||||||
|
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
|
||||||
|
msgid "Main menu"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Name of the theme
|
||||||
|
msgid "Moonshine"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:44
|
||||||
|
msgid "Paragraph styles"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Author of the theme
|
||||||
|
msgid "Pascal Martineau "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/vendors/tinymce.php:37
|
||||||
|
msgid "Semi-bold"
|
||||||
|
msgstr ""
|
||||||
@@ -1,14 +1,80 @@
|
|||||||
|
import { version } from "./package.json";
|
||||||
|
|
||||||
|
const siteUrl = process.env.NUXT_SITE_URL;
|
||||||
|
if (!siteUrl) {
|
||||||
|
throw new Error(`NUXT_SITE_URL is not defined. Make sure to set it in your build environment variables.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wpUrl = process.env.NUXT_WP_URL;
|
||||||
|
if (!wpUrl) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
const enableCloudflareImage = Boolean(process.env.ENABLE_CLOUDFLARE_IMAGE);
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
|
"@lewebsimple/nuxt-graphql",
|
||||||
"@nuxt/eslint",
|
"@nuxt/eslint",
|
||||||
|
"@nuxt/image",
|
||||||
|
"@nuxt/ui",
|
||||||
|
"@nuxtjs/device",
|
||||||
|
"@nuxtjs/seo",
|
||||||
|
"nuxt-auth-utils",
|
||||||
|
"nuxt-svgo",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
dirs: [
|
||||||
|
{ path: "~/components", pathPrefix: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
|
|
||||||
|
css: ["~/assets/css/_main.css"],
|
||||||
|
|
||||||
|
site: {
|
||||||
|
url: siteUrl,
|
||||||
|
name: "WP Headless",
|
||||||
|
defaultLocale: "fr",
|
||||||
|
},
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
colorMode: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
runtimeConfig: {
|
||||||
|
wpUrl,
|
||||||
|
},
|
||||||
|
|
||||||
compatibilityDate: "2026-01-01",
|
compatibilityDate: "2026-01-01",
|
||||||
|
|
||||||
|
nitro: {
|
||||||
|
preset: "cloudflare_module",
|
||||||
|
cloudflare: {
|
||||||
|
deployConfig: true,
|
||||||
|
nodeCompat: true,
|
||||||
|
wrangler: {
|
||||||
|
// Project name
|
||||||
|
name: "wp-headless",
|
||||||
|
// Cloudflare Workers settings
|
||||||
|
compatibility_date: "2026-01-27",
|
||||||
|
observability: { enabled: true },
|
||||||
|
preview_urls: false,
|
||||||
|
// Environment variables
|
||||||
|
vars: {
|
||||||
|
NODE_ENV: "staging",
|
||||||
|
NUXT_SITE_URL: siteUrl,
|
||||||
|
NUXT_WP_URL: wpUrl,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
eslint: {
|
eslint: {
|
||||||
config: {
|
config: {
|
||||||
stylistic: {
|
stylistic: {
|
||||||
@@ -21,4 +87,36 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
graphql: {
|
||||||
|
client: {
|
||||||
|
cache: {
|
||||||
|
keyVersion: version,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
context: ["server/graphql/context"],
|
||||||
|
schema: {
|
||||||
|
wp: { type: "remote", endpoint: `${wpUrl}/graphql`, hooks: ["server/graphql/wp-hooks"] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
image: {
|
||||||
|
provider: enableCloudflareImage ? "cloudflare" : "none",
|
||||||
|
cloudflare: { baseURL: `${siteUrl}/` },
|
||||||
|
domains: [wpDomain],
|
||||||
|
format: ["avif", "webp"],
|
||||||
|
},
|
||||||
|
|
||||||
|
robots: {
|
||||||
|
sitemap: `${wpUrl}/sitemap_index.xml`,
|
||||||
|
},
|
||||||
|
|
||||||
|
sitemap: false,
|
||||||
|
|
||||||
|
svgo: {
|
||||||
|
autoImportPath: "~/assets/svg/",
|
||||||
|
componentPrefix: "Svg",
|
||||||
|
defaultImport: "component",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,27 +1,57 @@
|
|||||||
{
|
{
|
||||||
"name": "@lewebsimple/moonshine",
|
"name": "@lewebsimple/moonshine",
|
||||||
"description": "Headless WordPress theme based on Nuxt.",
|
"description": "Headless WordPress theme based on Nuxt.",
|
||||||
"version": "0.1.1",
|
"version": "0.1.11",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
"dev": "nuxt dev --host 0.0.0.0",
|
"editor-style": "pnpx @tailwindcss/cli -i ./app/assets/css/_main.css -o ./editor-style.css --minify",
|
||||||
|
"dev": "nuxt dev",
|
||||||
"lint": "eslint --fix .",
|
"lint": "eslint --fix .",
|
||||||
"postinstall": "pnpm --sequential /postinstall:.*/",
|
"postinstall": "nuxt prepare",
|
||||||
"postinstall:nuxt": "nuxt prepare",
|
"preview": "WRANGLER_ENV=dev pnpm run build && wrangler dev --port 3000",
|
||||||
"preview": "nuxt preview",
|
"release": "pnpm lint && changelogen --noAuthors --release --push",
|
||||||
"release": "pnpm lint && changelogen --release --push"
|
"typecheck": "nuxt typecheck"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nuxt": "^4.2.2",
|
"@iconify-json/cib": "^1.2.3",
|
||||||
"vue": "^3.5.26",
|
"@iconify-json/lucide": "^1.2.87",
|
||||||
"vue-router": "^4.6.4"
|
"@lewebsimple/nuxt-graphql": "^0.6.8",
|
||||||
|
"@nuxt/image": "^2.0.0",
|
||||||
|
"@nuxt/ui": "4.3.0",
|
||||||
|
"@nuxtjs/device": "4.0.0",
|
||||||
|
"@nuxtjs/seo": "^3.4.0",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
|
"nuxt": "^4.3.0",
|
||||||
|
"nuxt-auth-utils": "^0.5.28",
|
||||||
|
"nuxt-svgo": "^4.2.6",
|
||||||
|
"tailwindcss": "^4.1.18",
|
||||||
|
"vue": "^3.5.27",
|
||||||
|
"vue-router": "^4.6.4",
|
||||||
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/eslint": "^1.12.1",
|
"@nuxt/eslint": "^1.13.0",
|
||||||
"changelogen": "^0.6.2",
|
"changelogen": "^0.6.2",
|
||||||
"eslint": "^9.39.2"
|
"eslint": "^9.39.2",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"vue-tsc": "^3.2.4",
|
||||||
|
"wrangler": "^4.61.1"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"@tiptap/core": "3.14.0",
|
||||||
|
"@tiptap/pm": "3.14.0"
|
||||||
|
},
|
||||||
|
"onlyBuiltDependencies": [
|
||||||
|
"@parcel/watcher",
|
||||||
|
"esbuild",
|
||||||
|
"sharp",
|
||||||
|
"unrs-resolver",
|
||||||
|
"vue-demi",
|
||||||
|
"workerd"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"changelog": {
|
"changelog": {
|
||||||
"types": {
|
"types": {
|
||||||
|
|||||||
7452
wp-content/themes/moonshine/pnpm-lock.yaml
generated
7452
wp-content/themes/moonshine/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
|||||||
User-Agent: *
|
|
||||||
Disallow:
|
|
||||||
21
wp-content/themes/moonshine/server/api/login.post.ts
Normal file
21
wp-content/themes/moonshine/server/api/login.post.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
try {
|
||||||
|
const variables = await readBody<AuthLoginForm>(event);
|
||||||
|
const { data } = await useGraphQLOperation(event, "AuthLogin", variables);
|
||||||
|
if (!data?.login) {
|
||||||
|
throw new Error("INVALID_LOGIN");
|
||||||
|
}
|
||||||
|
if (!await handleLogin(event, data)) {
|
||||||
|
throw new Error("LOGIN_FAILED");
|
||||||
|
}
|
||||||
|
return { success: true, message: "Connexion réussie" };
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
const messages = {
|
||||||
|
INVALID_LOGIN: "Identifiants invalides. Veuillez réessayer.",
|
||||||
|
LOGIN_FAILED: "Une erreur est survenue lors de la connexion. Veuillez réessayer plus tard.",
|
||||||
|
};
|
||||||
|
const message = (error instanceof Error && error.message in messages) ? error.message : "LOGIN_FAILED";
|
||||||
|
return { success: false, message: messages[message as keyof typeof messages] };
|
||||||
|
}
|
||||||
|
});
|
||||||
12
wp-content/themes/moonshine/server/api/logout.post.ts
Normal file
12
wp-content/themes/moonshine/server/api/logout.post.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
try {
|
||||||
|
await handleLogout(event);
|
||||||
|
return { success: true, message: "Déconnexion réussie" };
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : "Une erreur est survenue lors de la déconnexion.";
|
||||||
|
return { success: false, message };
|
||||||
|
}
|
||||||
|
});
|
||||||
6
wp-content/themes/moonshine/server/graphql/context.ts
Normal file
6
wp-content/themes/moonshine/server/graphql/context.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default defineGraphQLContext(async (event) => {
|
||||||
|
const authToken = await getAuthToken(event);
|
||||||
|
return {
|
||||||
|
authToken,
|
||||||
|
};
|
||||||
|
});
|
||||||
16722
wp-content/themes/moonshine/server/graphql/schema.graphql
Normal file
16722
wp-content/themes/moonshine/server/graphql/schema.graphql
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user