Mr. Worldwide #93
+16
-3
@@ -400,7 +400,7 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Smooth navbar transition while i18n loads
|
/* Smooth navbar transition while i18n loads
|
||||||
- Keep navbar visible but subtly blurred/faded to avoid abrupt disappearance.
|
- Keep navbar visible with a soft fade/slide to avoid abrupt disappearance.
|
||||||
- Make elements non-interactive until translations are applied. */
|
- Make elements non-interactive until translations are applied. */
|
||||||
body:not(.i18n-ready) nav.navbar,
|
body:not(.i18n-ready) nav.navbar,
|
||||||
body:not(.i18n-ready) .navbar,
|
body:not(.i18n-ready) .navbar,
|
||||||
@@ -409,12 +409,25 @@ body:not(.i18n-ready) .navbar .nav-link,
|
|||||||
body:not(.i18n-ready) .navbar .navbar-text,
|
body:not(.i18n-ready) .navbar .navbar-text,
|
||||||
body:not(.i18n-ready) .navbar .btn {
|
body:not(.i18n-ready) .navbar .btn {
|
||||||
transition: filter 220ms ease, opacity 220ms ease, transform 220ms ease;
|
transition: filter 220ms ease, opacity 220ms ease, transform 220ms ease;
|
||||||
filter: blur(6px) saturate(0.9) grayscale(0.06);
|
/* Light mode & default: fully fade out navbar until i18n is ready
|
||||||
opacity: 0.85;
|
so fallback labels never flash. */
|
||||||
|
opacity: 0;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark mode: keep the original soft blur effect while loading
|
||||||
|
so the navbar stays visible but its text is obscured. */
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) nav.navbar,
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) .navbar,
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) .navbar .navbar-brand,
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) .navbar .nav-link,
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) .navbar .navbar-text,
|
||||||
|
html[data-theme="dark"] body:not(.i18n-ready) .navbar .btn {
|
||||||
|
filter: blur(6px) saturate(0.9) grayscale(0.06);
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
/* When translations are ready, restore full clarity and interactivity */
|
/* When translations are ready, restore full clarity and interactivity */
|
||||||
body.i18n-ready nav.navbar,
|
body.i18n-ready nav.navbar,
|
||||||
body.i18n-ready .navbar,
|
body.i18n-ready .navbar,
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_COMPLETION_MODAL = Object.freeze({
|
const DEFAULT_COMPLETION_MODAL = Object.freeze({
|
||||||
title: (window.i18n && typeof window.i18n.t === 'function') ? window.i18n.t('checklist.congratulations') : 'Congratulations! very nice 🎉🎉🎉',
|
// Default title: use the localized 100% modal title if available.
|
||||||
|
title: t('admin.modal100.defaultTitle', 'Congratulations! very nice 🎉🎉🎉'),
|
||||||
bodyText: '',
|
bodyText: '',
|
||||||
videoSrc: 'video/reward.mp4',
|
videoSrc: 'video/reward.mp4',
|
||||||
bodyHtml: ''
|
bodyHtml: ''
|
||||||
@@ -194,7 +195,12 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
const videoEl = document.getElementById('rewardVideo');
|
const videoEl = document.getElementById('rewardVideo');
|
||||||
const videoSourceEl = document.getElementById('rewardVideoSource');
|
const videoSourceEl = document.getElementById('rewardVideoSource');
|
||||||
|
|
||||||
const title = String(content?.title || '').trim() || DEFAULT_COMPLETION_MODAL.title;
|
const rawTitle = String(content?.title || '').trim();
|
||||||
|
// If the stored value is the i18n key itself, translate it; otherwise
|
||||||
|
// use the stored title, falling back to the localized default.
|
||||||
|
const title = (!rawTitle || rawTitle === 'admin.modal100.defaultTitle')
|
||||||
|
? t('admin.modal100.defaultTitle', 'Congratulations! very nice 🎉🎉🎉')
|
||||||
|
: rawTitle;
|
||||||
const bodyText = String(content?.bodyText || '');
|
const bodyText = String(content?.bodyText || '');
|
||||||
const bodyHtml = sanitizeHtml(String(content?.bodyHtml || ''));
|
const bodyHtml = sanitizeHtml(String(content?.bodyHtml || ''));
|
||||||
const videoSrc = String(content?.videoSrc || '').trim();
|
const videoSrc = String(content?.videoSrc || '').trim();
|
||||||
|
|||||||
@@ -1637,7 +1637,8 @@ window.onload = async function () {
|
|||||||
if (!dbBackupListBody) return;
|
if (!dbBackupListBody) return;
|
||||||
const list = Array.isArray(backups) ? backups : [];
|
const list = Array.isArray(backups) ? backups : [];
|
||||||
if (!list.length) {
|
if (!list.length) {
|
||||||
dbBackupListBody.innerHTML = '<tr><td colspan="4" class="text-muted">Aucune sauvegarde.</td></tr>';
|
const emptyText = t('admin.backup.noBackups', 'No backups found.');
|
||||||
|
dbBackupListBody.innerHTML = `<tr><td colspan="4" class="text-muted">${emptyText}</td></tr>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,8 @@
|
|||||||
"admin.modal100.videoLabel": "Video",
|
"admin.modal100.videoLabel": "Video",
|
||||||
"admin.modal100.videoInfoShort": "accepts relative path (e.g.: video/reward.mp4) or full URL.",
|
"admin.modal100.videoInfoShort": "accepts relative path (e.g.: video/reward.mp4) or full URL.",
|
||||||
|
|
||||||
|
"admin.modal100.defaultTitle": "Congratulations! very nice 🎉🎉🎉",
|
||||||
|
|
||||||
"admin.users.usersCount": "user(s)",
|
"admin.users.usersCount": "user(s)",
|
||||||
"admin.users.addUser": "Add user",
|
"admin.users.addUser": "Add user",
|
||||||
"admin.users.name": "Name",
|
"admin.users.name": "Name",
|
||||||
@@ -488,6 +490,7 @@
|
|||||||
"admin.backup.downloadDesc": "retrieves the file locally (useful before a risky operation).",
|
"admin.backup.downloadDesc": "retrieves the file locally (useful before a risky operation).",
|
||||||
"admin.backup.restoreHowDesc": "imports the file. With drop, restored collections are deleted first.",
|
"admin.backup.restoreHowDesc": "imports the file. With drop, restored collections are deleted first.",
|
||||||
"admin.backup.quickCheck": "Quick check",
|
"admin.backup.quickCheck": "Quick check",
|
||||||
|
"admin.backup.noBackups": "No backups found.",
|
||||||
"admin.backup.quickCheckDesc": "After restore, reload the page and check \"Films\", \"Checklist\" and \"Stats\".",
|
"admin.backup.quickCheckDesc": "After restore, reload the page and check \"Films\", \"Checklist\" and \"Stats\".",
|
||||||
"admin.backup.confirmDelete": "Delete backup \"{name}\"?",
|
"admin.backup.confirmDelete": "Delete backup \"{name}\"?",
|
||||||
"admin.backup.creating": "Creating…",
|
"admin.backup.creating": "Creating…",
|
||||||
|
|||||||
@@ -488,6 +488,7 @@
|
|||||||
"admin.backup.restoreWarning": "La restauration peut écraser les données. Fais un backup juste avant si besoin.",
|
"admin.backup.restoreWarning": "La restauration peut écraser les données. Fais un backup juste avant si besoin.",
|
||||||
"admin.backup.backupFile": "Fichier de backup",
|
"admin.backup.backupFile": "Fichier de backup",
|
||||||
"admin.backup.dropBeforeRestore": "Drop les collections avant restore (recommandé)",
|
"admin.backup.dropBeforeRestore": "Drop les collections avant restore (recommandé)",
|
||||||
|
"admin.backup.noBackups": "Aucune sauvegarde.",
|
||||||
"admin.backup.tip": "Conseil",
|
"admin.backup.tip": "Conseil",
|
||||||
"admin.backup.tipDesc": "Utilise drop sauf si tu sais exactement ce que tu fais (sinon risque de doublons/erreurs).",
|
"admin.backup.tipDesc": "Utilise drop sauf si tu sais exactement ce que tu fais (sinon risque de doublons/erreurs).",
|
||||||
"admin.backup.howItWorks": "Fonctionnement",
|
"admin.backup.howItWorks": "Fonctionnement",
|
||||||
|
|||||||
Reference in New Issue
Block a user