Skip to content

Commit 18face1

Browse files
author
Timothe Joubert
committed
Merge branch 'main' into feature/v-download
2 parents f0c9fdc + 4989b83 commit 18face1

9 files changed

Lines changed: 3819 additions & 2447 deletions

File tree

.env.sample

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ XILOFONE_OUTPUT=i18n/locales/
3232
# NUXT_PUBLIC_SENTRY_DSN=
3333

3434
## ---- Dev
35-
NUXT_DEVTOOLS=true
35+
NUXT_DEVTOOLS=true

CLAUDE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# CLAUDE.md
2+
3+
## Translations (i18n)
4+
5+
Translation keys are managed via **Xilofone**, an external translation management service.
6+
7+
The `i18n/locales/nuxt.*.json` files are automatically generated by the following command:
8+
9+
```bash
10+
pnpm xilo
11+
```
12+
13+
If a translation key needs to be added or updated, make the change directly in the `nuxt.*.json` file **and explicitly instruct the developer to report the same change in the Xilofone interface**, otherwise it will be overwritten the next time they run `pnpm xilo`.

app/composables/use-roadiz-head-socials.ts

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,56 @@ export interface SocialLink {
55
icon?: string
66
}
77

8-
export function getSocialLinks({ key, url }: { key: string, url: string }) {
9-
// Remove trailing "url" and convert to lowercase for better matching
10-
// For example, "twitterUrl" becomes "twitter", "linkedin_url" becomes "linkedin"
11-
const formattedKey = key.toLowerCase().replace(/_?url$/, '')
8+
// useRoadizHeadSocialLinks will sort the social links based on the order defined in SOCIAL_NETWORKS
9+
// and will use a default icon for unknown networks
10+
const SOCIAL_NETWORKS = [
11+
{ prefixes: ['instagram'], name: 'Instagram', icon: 'social-instagram' },
12+
{ prefixes: ['facebook'], name: 'Facebook', icon: 'social-facebook' },
13+
{ prefixes: ['tiktok'], name: 'Tiktok', icon: 'social-tiktok' },
14+
{ prefixes: ['linkedin'], name: 'LinkedIn', icon: 'social-linkedin' },
15+
{ prefixes: ['mastodon'], name: 'Mastodon', icon: 'social-mastodon' },
16+
{ prefixes: ['pinterest'], name: 'Pinterest', icon: 'social-pinterest' },
17+
{ prefixes: ['snapchat'], name: 'Snapchat', icon: 'social-snapchat' },
18+
{ prefixes: ['youtube'], name: 'Youtube', icon: 'social-youtube' },
19+
{ prefixes: ['spotify'], name: 'Spotify', icon: 'social-spotify' },
20+
{ prefixes: ['twitter', 'x'], name: 'X', icon: 'social-x' },
21+
] as const
1222

13-
if (formattedKey.startsWith('mastodon')) {
14-
return { url: url, name: 'Mastodon', icon: 'social-mastodon' }
15-
}
16-
if (formattedKey.startsWith('pinterest')) {
17-
return { url: url, name: 'Pinterest', icon: 'social-pinterest' }
18-
}
19-
if (formattedKey.startsWith('snapchat')) {
20-
return { url: url, name: 'Snapchat', icon: 'social-snapchat' }
21-
}
22-
if (formattedKey.startsWith('instagram')) {
23-
return { url: url, name: 'Instagram', icon: 'social-instagram' }
24-
}
25-
if (formattedKey.startsWith('youtube')) {
26-
return { url: url, name: 'Youtube', icon: 'social-youtube' }
27-
}
28-
if (formattedKey.startsWith('linkedin')) {
29-
return { url: url, name: 'LinkedIn', icon: 'social-linkedin' }
30-
}
31-
if (formattedKey.startsWith('facebook')) {
32-
return { url: url, name: 'Facebook', icon: 'social-facebook' }
33-
}
34-
if (formattedKey.startsWith('tiktok')) {
35-
return { url: url, name: 'Tiktok', icon: 'social-tiktok' }
36-
}
37-
if (formattedKey.startsWith('spotify')) {
38-
return { url: url, name: 'Spotify', icon: 'social-spotify' }
39-
}
40-
if (formattedKey.startsWith('twitter') || formattedKey === 'x') {
41-
return { url: url, name: 'X', icon: 'social-x' }
23+
// Api keys in commonContent.urls can be in snake_case or camelCase,
24+
// so we need to normalize them to match the prefixes in SOCIAL_NETWORKS
25+
function normalizeKey(key: string): string {
26+
return key.replace(/_url$/i, '').replace(/Url$/, '').toLowerCase()
27+
}
28+
29+
export function getSocialLinks(key: string, url: string): SocialLink {
30+
const normalized = normalizeKey(key)
31+
const network = SOCIAL_NETWORKS.find(({ prefixes }) => prefixes.some(p => normalized === p))
32+
33+
if (network) {
34+
return {
35+
url,
36+
name: network.name,
37+
icon: network.icon,
38+
}
4239
}
4340

4441
return {
45-
url: url,
46-
name: key,
42+
url,
43+
name: normalized,
4744
icon: 'link',
4845
}
4946
}
5047

5148
export function useRoadizHeadSocialLinks() {
5249
const { data } = useCommonContent()
5350

54-
return computed(() => {
55-
const urlEntriesList = Object.entries(data.value?.urls || {})
56-
.filter(([_key, value]) => typeof value === 'string') as [string, string][]
57-
58-
return urlEntriesList.map(([key, url]) => getSocialLinks({ key, url }))
59-
})
51+
return computed(() =>
52+
Object.entries(data.value?.urls || {})
53+
.filter(([, value]) => typeof value === 'string')
54+
.map(([key, url]) => getSocialLinks(key, url as string))
55+
.sort((a, b) => {
56+
const ai = SOCIAL_NETWORKS.findIndex(({ name }) => name === a.name)
57+
const bi = SOCIAL_NETWORKS.findIndex(({ name }) => name === b.name)
58+
return (ai === -1 ? SOCIAL_NETWORKS.length : ai) - (bi === -1 ? SOCIAL_NETWORKS.length : bi)
59+
}))
6060
}

i18n/locales/nuxt.en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@
3232
"form.error": "An error occurred",
3333
"form.error_too_many_requests": "Too many requests, please try again later",
3434
"form.gdpr": "By submitting this form, you agree to our privacy policy.",
35+
"form.newsletter_description": "Subscribe to our newsletter to receive our latest news.",
36+
"form.newsletter_gdpr": "By subscribing, you agree to receive our communications and our privacy policy.",
37+
"form.newsletter_submit": "Subscribe",
38+
"form.newsletter_success": "Thank you, your subscription has been confirmed.",
3539
"form.pending": "Sending",
40+
"form.required_fields_notice": "Fields marked with an asterisk (*) are required",
3641
"form.submit": "Submit",
3742
"form.success": "Thanks, your message has been sent",
3843
"form.user_cookie_consent.button_label": "Allow",

i18n/locales/nuxt.fr.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@
3232
"form.error": "Une erreur est survenue",
3333
"form.error_too_many_requests": "Trop de requêtes, veuillez réessayer plus tard",
3434
"form.gdpr": "En soumettant ce formulaire, vous acceptez notre politique de confidentialité.",
35+
"form.newsletter_description": "Inscrivez-vous à notre newsletter pour recevoir nos dernières actualités.",
36+
"form.newsletter_gdpr": "En vous inscrivant, vous acceptez de recevoir nos communications et notre politique de confidentialité.",
37+
"form.newsletter_submit": "S'inscrire",
38+
"form.newsletter_success": "Merci, votre inscription a bien été prise en compte.",
3539
"form.pending": "Envoi en cours",
40+
"form.required_fields_notice": "Les champs marqués d'un astérisque (*) sont obligatoires",
3641
"form.submit": "Envoyer",
3742
"form.success": "Merci, votre message a bien été envoyé",
3843
"form.user_cookie_consent.button_label": "Autoriser",

package.json

Lines changed: 74 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,76 @@
11
{
2-
"name": "@rezozero/nuxt-starter",
3-
"version": "0.1.0",
4-
"private": true,
5-
"scripts": {
6-
"dev": "nuxi dev",
7-
"stories": "nuxi dev stories",
8-
"build": "nuxi build",
9-
"generate": "nuxi generate",
10-
"preview": "nuxi preview",
11-
"prepare": "nuxi prepare",
12-
"postinstall": "nuxi prepare && husky install",
13-
"generate:maintenance": "nuxt generate --maintenance",
14-
"lint": "pnpm lint:js && pnpm lint:css",
15-
"lint-fix": "pnpm lint:js --fix && pnpm lint:css --fix",
16-
"lint:js": "eslint .",
17-
"lint:css": "stylelint \"**/*.{vue,css,scss}\"",
18-
"xilo": "node ./node_modules/@rezo-zero/xilofone-fetch/dist/index.js"
19-
},
20-
"devDependencies": {
21-
"@nuxt/devtools": "latest",
22-
"@nuxt/eslint": "^1.16.0",
23-
"@nuxt/icon": "^2.2.3",
24-
"@nuxt/image": "^2.0.0",
25-
"@nuxtjs/i18n": "^10.4.0",
26-
"@nuxtjs/robots": "^6.0.9",
27-
"@nuxtjs/sitemap": "^8.1.0",
28-
"@rezo-zero/intervention-request-provider": "^2.0.0",
29-
"@rezo-zero/nuxt-cache-control": "^0.1.7",
30-
"@rezo-zero/xilofone-fetch": "^1.0.0",
31-
"@roadiz/types": "^0.5.0",
32-
"@stylistic/eslint-plugin": "^5.10.0",
33-
"@types/body-scroll-lock": "^3.1.2",
34-
"@types/json-schema": "^7.0.15",
35-
"@types/lodash": "^4.17.24",
36-
"@types/node": "^24.13.2",
37-
"@vueuse/nuxt": "^14.3.0",
38-
"eslint": "^10.4.1",
39-
"husky": "^9.1.7",
40-
"include-media": "^2.0.0",
41-
"nuxt": "^4.4.8",
42-
"postcss-html": "^1.8.1",
43-
"postcss-pxtorem": "^6.1.0",
44-
"sass": "^1.100.0",
45-
"stylelint": "^17.13.0",
46-
"stylelint-config-css-modules": "^4.6.0",
47-
"stylelint-config-idiomatic-order": "^10.0.0",
48-
"stylelint-config-standard-scss": "^17.0.0",
49-
"stylelint-config-standard-vue": "^1.0.0",
50-
"typescript": "~6.0.3",
51-
"vite-svg-loader": "^5.1.1"
52-
},
53-
"dependencies": {
54-
"@floating-ui/vue": "^2.0.0",
55-
"@gtm-support/vue-gtm": "^3.2.0",
56-
"@popperjs/core": "^2.11.8",
57-
"@sentry/nuxt": "^10.57.0",
58-
"@vue-a11y/skip-to": "^3.0.3",
59-
"@vueuse/core": "^14.3.0",
60-
"body-scroll-lock": "^3.1.5",
61-
"floating-vue": "^5.2.2",
62-
"lodash": "^4.18.1",
63-
"marked": "^18.0.5",
64-
"nuxt-schema-org": "^6.2.0",
65-
"ohash": "^2.0.11",
66-
"plyr": "^3.8.4",
67-
"swiper": "^12.2.0",
68-
"tiny-emitter": "^2.1.0",
69-
"ufo": "^1.6.4",
70-
"v-calendar": "^3.1.2",
71-
"vue-multiselect": "^3.5.0"
72-
},
73-
"engines": {
74-
"node": "24.14.1"
75-
},
76-
"packageManager": "pnpm@11.5.1"
2+
"name": "@rezozero/nuxt-starter",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"dev": "nuxi dev",
7+
"stories": "nuxi dev stories",
8+
"build": "nuxi build",
9+
"generate": "nuxi generate",
10+
"preview": "nuxi preview",
11+
"prepare": "nuxi prepare",
12+
"postinstall": "nuxi prepare && husky",
13+
"generate:maintenance": "nuxt generate --maintenance",
14+
"lint": "pnpm lint:js && pnpm lint:css",
15+
"lint-fix": "pnpm lint:js --fix && pnpm lint:css --fix",
16+
"lint:js": "eslint .",
17+
"lint:css": "stylelint \"**/*.{vue,css,scss}\"",
18+
"xilo": "node ./node_modules/@rezo-zero/xilofone-fetch/dist/index.js"
19+
},
20+
"devDependencies": {
21+
"@nuxt/eslint": "^1.16.0",
22+
"@nuxt/icon": "^2.2.3",
23+
"@nuxt/image": "^2.0.0",
24+
"@nuxtjs/i18n": "10.2.4",
25+
"@nuxtjs/robots": "^6.1.1",
26+
"@nuxtjs/sitemap": "^8.2.1",
27+
"@rezo-zero/intervention-request-provider": "^2.0.0",
28+
"@rezo-zero/nuxt-cache-control": "^0.1.11",
29+
"@rezo-zero/xilofone-fetch": "^1.0.0",
30+
"@roadiz/types": "^0.5.0",
31+
"@stylistic/eslint-plugin": "^5.10.0",
32+
"@types/body-scroll-lock": "^3.1.2",
33+
"@types/json-schema": "^7.0.15",
34+
"@types/lodash": "^4.17.24",
35+
"@types/node": "^24.13.2",
36+
"eslint": "^10.5.0",
37+
"husky": "^9.1.7",
38+
"include-media": "^2.0.0",
39+
"nuxt": "^4.4.8",
40+
"postcss-html": "^1.8.1",
41+
"postcss-pxtorem": "^6.1.0",
42+
"sass": "^1.101.0",
43+
"stylelint": "^17.13.0",
44+
"stylelint-config-css-modules": "^4.6.0",
45+
"stylelint-config-idiomatic-order": "^10.0.0",
46+
"stylelint-config-standard-scss": "^17.0.0",
47+
"stylelint-config-standard-vue": "^1.0.0",
48+
"typescript": "~6.0.3",
49+
"vite-svg-loader": "^5.1.1"
50+
},
51+
"dependencies": {
52+
"@floating-ui/vue": "^2.0.0",
53+
"@gtm-support/vue-gtm": "^3.2.0",
54+
"@popperjs/core": "^2.11.8",
55+
"@sentry/nuxt": "^10.58.0",
56+
"@vue-a11y/skip-to": "^3.0.3",
57+
"@vueuse/core": "^14.3.0",
58+
"@vueuse/nuxt": "^14.3.0",
59+
"body-scroll-lock": "^3.1.5",
60+
"floating-vue": "^5.2.2",
61+
"lodash": "^4.18.1",
62+
"marked": "^18.0.5",
63+
"nuxt-schema-org": "^6.2.1",
64+
"ohash": "^2.0.11",
65+
"plyr": "^3.8.4",
66+
"swiper": "^12.2.0",
67+
"tiny-emitter": "^2.1.0",
68+
"ufo": "^1.6.4",
69+
"v-calendar": "^3.1.2",
70+
"vue-multiselect": "^3.5.0"
71+
},
72+
"engines": {
73+
"node": "24.14.1"
74+
},
75+
"packageManager": "pnpm@11.5.1"
7776
}

0 commit comments

Comments
 (0)