From 8d56b5590e6b7a89644815ad38e03bf3d641d2c7 Mon Sep 17 00:00:00 2001 From: Jasmin Savard Date: Sat, 11 Jan 2025 12:57:48 -0500 Subject: [PATCH] Migrate OC.Themes darkmode toggler --- .../wwwroot/Scripts/setup.js | 2 +- .../OrchardCore.Themes/Assets.json | 22 ------- .../OrchardCore.Themes/Assets/js/constants.js | 28 -------- .../Assets/js/theme-toggler.js | 56 ---------------- .../{ => Assets}/package-lock.json | 0 .../{ => Assets}/package.json | 1 + .../OrchardCore.Themes/Assets/ts/constants.ts | 59 +++++++++++++++++ .../{js/theme-loader.js => ts/theme-head.ts} | 7 +- .../Assets/ts/theme-manager.ts | 65 +++++++++++++++++++ .../OrchardCore.Themes/Assets2.json | 14 ++++ .../ResourceManagementOptionsConfiguration.cs | 8 ++- .../wwwroot/Scripts/theme-head.js | 60 +---------------- .../wwwroot/Scripts/theme-head.min.js | 1 - .../wwwroot/Scripts/theme-manager.js | 51 +-------------- .../wwwroot/Scripts/theme-manager.min.js | 1 - yarn.lock | 4 +- 16 files changed, 154 insertions(+), 225 deletions(-) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/Assets.json delete mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/constants.js delete mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-toggler.js rename src/OrchardCore.Modules/OrchardCore.Themes/{ => Assets}/package-lock.json (100%) rename src/OrchardCore.Modules/OrchardCore.Themes/{ => Assets}/package.json (87%) create mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/constants.ts rename src/OrchardCore.Modules/OrchardCore.Themes/Assets/{js/theme-loader.js => ts/theme-head.ts} (73%) create mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-manager.ts delete mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.min.js delete mode 100644 src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-manager.min.js diff --git a/src/OrchardCore.Modules/OrchardCore.Setup/wwwroot/Scripts/setup.js b/src/OrchardCore.Modules/OrchardCore.Setup/wwwroot/Scripts/setup.js index e5d454ea071..4989679e103 100644 --- a/src/OrchardCore.Modules/OrchardCore.Setup/wwwroot/Scripts/setup.js +++ b/src/OrchardCore.Modules/OrchardCore.Setup/wwwroot/Scripts/setup.js @@ -1 +1 @@ -!function(e,t,r,n){var o="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},i="function"==typeof o[n]&&o[n],u=i.cache||{},s="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function c(t,r){if(!u[t]){if(!e[t]){var a="function"==typeof o[n]&&o[n];if(!r&&a)return a(t,!0);if(i)return i(t,!0);if(s&&"string"==typeof t)return s(t);var d=new Error("Cannot find module '"+t+"'");throw d.code="MODULE_NOT_FOUND",d}p.resolve=function(r){var n=e[t][1][r];return null!=n?n:r},p.cache={};var l=u[t]=new c.Module(t);e[t][0].call(l.exports,p,l,l.exports,o)}return u[t].exports;function p(e){var t=p.resolve(e);return!1===t?{}:c(t)}}c.isParcelRequire=!0,c.Module=function(e){this.id=e,this.bundle=c,this.exports={}},c.modules=e,c.cache=u,c.parent=i,c.register=function(t,r){e[t]=[function(e,t){t.exports=r},{}]},Object.defineProperty(c,"root",{get:function(){return o[n]}}),o[n]=c;for(var a=0;a{const e=document.querySelector("#DatabaseProvider option:checked");if(e){const t="true"===e.getAttribute("data-connection-string")?.toLowerCase(),r="true"===e.getAttribute("data-table-prefix")?.toLowerCase();document.querySelectorAll(".connectionString").forEach((e=>e.style.display=t?"block":"none"));document.querySelectorAll(".tablePrefix").forEach((e=>e.style.display=r?"block":"none")),document.querySelectorAll(".pwd").forEach((e=>{t?e.setAttribute("required","required"):e.removeAttribute("required")}));const n=document.getElementById("connectionStringHint");n&&(n.textContent=e.getAttribute("data-connection-string-sample")||"")}},c=(e,t)=>{if(!e||!t)return;const r="password"===e.getAttribute("type")?"text":"password";e.setAttribute("type",r);const n=t.getElementsByClassName("icon")[0];n&&(n.getAttribute("data-icon")?n.setAttribute("data-icon","password"===r?"eye":"eye-slash"):(n.classList.toggle("fa-eye","password"===r),n.classList.toggle("fa-eye-slash","password"!==r)))};(()=>{s(),document.getElementById("DatabaseProvider")?.addEventListener("change",(function(){s()})),document.querySelectorAll("#recipes div a").forEach((function(e){e.addEventListener("click",(function(){(e=>{const t=e.getAttribute("data-recipe-name"),r=e.getAttribute("data-recipe-display-name"),n=e.getAttribute("data-recipe-description"),o=document.getElementById("recipeButton"),i=document.getElementById("RecipeName");o&&i&&(o.textContent=r||"",i.value=t||"",o.setAttribute("title",n||""),o.focus())})(this)}))}));const e=document.getElementById("Password"),t=JSON.parse(e?.dataset.strength??"")??{requiredLength:6,requiredUniqueChars:1,requireNonAlphanumeric:!0,requireLowercase:!0,requireUppercase:!0,requireDigit:!0};e&&(0,u.default)(e,t),e&&e.addEventListener("focus",(function(){const r=document.createElement("div");r.className="popover bs-popover-top",r.role="tooltip",r.innerHTML=`
Password requirements:
  • Minimum length: ${t.requiredLength}
  • Unique Chars: ${t.requiredUniqueChars}
  • Uppercase: ${t.requireUppercase?"required":"not required"}
  • Lowercase: ${t.requireLowercase?"required":"not required"}
  • Digit: ${t.requireDigit?"required":"not required"}
  • Non alphanumeric: ${t.requireNonAlphanumeric?"required":"not required"}
`;const n=e.getBoundingClientRect();r.style.position="absolute",r.style.top=`${n.top+53}px`,r.style.left=`${n.left}px`,document.body.appendChild(r),e.addEventListener("blur",(function t(){r.remove(),e?.removeEventListener("blur",t)}))}));const r=document.querySelector("#toggleConnectionString");r&&r.addEventListener("click",(function(e){c(document.querySelector("#ConnectionString"),document.querySelector("#toggleConnectionString"))}));const n=document.querySelector("#togglePassword");n?.addEventListener("click",(function(e){c(document.querySelector("#Password"),document.querySelector("#togglePassword"))}));const o=document.querySelector("#togglePasswordConfirmation");o?.addEventListener("click",(function(e){c(document.querySelector("#PasswordConfirmation"),document.querySelector("#togglePasswordConfirmation"))})),(()=>{const e=document.getElementById("culturesList");e.addEventListener("change",(()=>{const t=e.options[e.selectedIndex];t&&(window.location.href=t.dataset.url||"")}))})()})()},{"@orchardcore/frontend/components/strength":"4C8NG","@parcel/transformer-js/src/esmodule-helpers.js":"2Cr9l"}],"4C8NG":[function(e,t,r,n){var o=e("@parcel/transformer-js/src/esmodule-helpers.js");function i(e,t){const r=Object.assign({requiredLength:8,requireUppercase:!1,requireLowercase:!1,requireDigit:!1,requireNonAlphanumeric:!1,target:"#passwordStrength",style:"margin-top: 7px; height: 7px; border-radius: 5px"},t);let n=0,o=0,i=0,u=0;const s=/[A-Z]/,c=/[a-z]/,a=/[0-9]/,d=/[^\da-zA-Z]/;let l=!1;function p(e){const t=e.length>=r.requiredLength?1:0;n=!r.requireUppercase||e.match(s)?1:0,o=!r.requireLowercase||e.match(c)?1:0,i=!r.requireDigit||e.match(a)?1:0,u=!r.requireNonAlphanumeric||e.match(d)?1:0;const p=(t+n+o+i+u)/5*100;l=p>=100,function(e,t){const n=document.createElement("div");n.className="progress",n.setAttribute("value",e.toString()),n.setAttribute("style",r.style),n.setAttribute("max","100"),n.setAttribute("aria-describedby","");const o=document.createElement("div");o.className="progress-bar "+t,o.style.width=e+"%",n.appendChild(o);const i=document.querySelector(r.target);i.innerHTML="",i.appendChild(n)}(p,function(e){return e>=100?"bg-success":e>=50?"bg-warning":0==e?"":"bg-danger"}(p))}e.addEventListener("keyup",(()=>p(e.value))),e.addEventListener("keydown",(()=>p(e.value))),e.addEventListener("change",(()=>p(e.value))),e.addEventListener("drop",(e=>{e.preventDefault(),p(e.dataTransfer?.getData("text")??"")})),e.form?.addEventListener("submit",(t=>{p(e.value),l||t.preventDefault()}))}o.defineInteropFlag(r),o.export(r,"default",(()=>i))},{"@parcel/transformer-js/src/esmodule-helpers.js":"2Cr9l"}],"2Cr9l":[function(e,t,r,n){r.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},r.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.exportAll=function(e,t){return Object.keys(e).forEach((function(r){"default"===r||"__esModule"===r||Object.prototype.hasOwnProperty.call(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:function(){return e[r]}})})),t},r.export=function(e,t,r){Object.defineProperty(e,t,{enumerable:!0,get:r})}},{}]},["7SRNq"],"7SRNq","parcelRequire94c2"); \ No newline at end of file +!function(e,t,r,n){var o="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},i="function"==typeof o[n]&&o[n],s=i.cache||{},c="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function u(t,r){if(!s[t]){if(!e[t]){var a="function"==typeof o[n]&&o[n];if(!r&&a)return a(t,!0);if(i)return i(t,!0);if(c&&"string"==typeof t)return c(t);var d=new Error("Cannot find module '"+t+"'");throw d.code="MODULE_NOT_FOUND",d}p.resolve=function(r){var n=e[t][1][r];return null!=n?n:r},p.cache={};var l=s[t]=new u.Module(t);e[t][0].call(l.exports,p,l,l.exports,o)}return s[t].exports;function p(e){var t=p.resolve(e);return!1===t?{}:u(t)}}u.isParcelRequire=!0,u.Module=function(e){this.id=e,this.bundle=u,this.exports={}},u.modules=e,u.cache=s,u.parent=i,u.register=function(t,r){e[t]=[function(e,t){t.exports=r},{}]},Object.defineProperty(u,"root",{get:function(){return o[n]}}),o[n]=u;for(var a=0;a{const e=document.querySelector("#DatabaseProvider option:checked");if(e){const t="true"===e.getAttribute("data-connection-string")?.toLowerCase(),r="true"===e.getAttribute("data-table-prefix")?.toLowerCase();document.querySelectorAll(".connectionString").forEach((e=>e.style.display=t?"block":"none"));document.querySelectorAll(".tablePrefix").forEach((e=>e.style.display=r?"block":"none")),document.querySelectorAll(".pwd").forEach((e=>{t?e.setAttribute("required","required"):e.removeAttribute("required")}));const n=document.getElementById("connectionStringHint");n&&(n.textContent=e.getAttribute("data-connection-string-sample")||"")}},u=(e,t)=>{if(!e||!t)return;const r="password"===e.getAttribute("type")?"text":"password";e.setAttribute("type",r);const n=t.getElementsByClassName("icon")[0];n&&(n.getAttribute("data-icon")?n.setAttribute("data-icon","password"===r?"eye":"eye-slash"):(n.classList.toggle("fa-eye","password"===r),n.classList.toggle("fa-eye-slash","password"!==r)))};(()=>{c(),document.getElementById("DatabaseProvider")?.addEventListener("change",(function(){c()})),document.querySelectorAll("#recipes div a").forEach((function(e){e.addEventListener("click",(function(){(e=>{const t=e.getAttribute("data-recipe-name"),r=e.getAttribute("data-recipe-display-name"),n=e.getAttribute("data-recipe-description"),o=document.getElementById("recipeButton"),i=document.getElementById("RecipeName");o&&i&&(o.textContent=r||"",i.value=t||"",o.setAttribute("title",n||""),o.focus())})(this)}))}));const e=document.getElementById("Password"),t=JSON.parse(e?.dataset.strength??"")??{requiredLength:6,requiredUniqueChars:1,requireNonAlphanumeric:!0,requireLowercase:!0,requireUppercase:!0,requireDigit:!0};e&&(0,s.default)(e,t),e&&e.addEventListener("focus",(function(){const r=document.createElement("div");r.className="popover bs-popover-top",r.role="tooltip",r.innerHTML=`
Password requirements:
  • Minimum length: ${t.requiredLength}
  • Unique Chars: ${t.requiredUniqueChars}
  • Uppercase: ${t.requireUppercase?"required":"not required"}
  • Lowercase: ${t.requireLowercase?"required":"not required"}
  • Digit: ${t.requireDigit?"required":"not required"}
  • Non alphanumeric: ${t.requireNonAlphanumeric?"required":"not required"}
`;const n=e.getBoundingClientRect();r.style.position="absolute",r.style.top=`${n.top+53}px`,r.style.left=`${n.left}px`,document.body.appendChild(r),e.addEventListener("blur",(function t(){r.remove(),e?.removeEventListener("blur",t)}))}));const r=document.querySelector("#toggleConnectionString");r&&r.addEventListener("click",(function(e){u(document.querySelector("#ConnectionString"),document.querySelector("#toggleConnectionString"))}));const n=document.querySelector("#togglePassword");n?.addEventListener("click",(function(e){u(document.querySelector("#Password"),document.querySelector("#togglePassword"))}));const o=document.querySelector("#togglePasswordConfirmation");o?.addEventListener("click",(function(e){u(document.querySelector("#PasswordConfirmation"),document.querySelector("#togglePasswordConfirmation"))})),(()=>{const e=document.getElementById("culturesList");e.addEventListener("change",(()=>{const t=e.options[e.selectedIndex];t&&(window.location.href=t.dataset.url||"")}))})()})()},{"@orchardcore/frontend/components/password-strength":"dk0Nf","@parcel/transformer-js/src/esmodule-helpers.js":"2Cr9l"}],dk0Nf:[function(e,t,r,n){e("@parcel/transformer-js/src/esmodule-helpers.js").defineInteropFlag(r),r.default=(e,t)=>{const r=Object.assign({requiredLength:8,requireUppercase:!1,requireLowercase:!1,requireDigit:!1,requireNonAlphanumeric:!1,target:"#passwordStrength",style:"margin-top: 7px; height: 7px; border-radius: 5px"},t);let n=0,o=0,i=0,s=0;const c=/[A-Z]/,u=/[a-z]/,a=/[0-9]/,d=/[^\da-zA-Z]/;let l=!1;const p=e=>{const t=e.length>=r.requiredLength?1:0;n=!r.requireUppercase||e.match(c)?1:0,o=!r.requireLowercase||e.match(u)?1:0,i=!r.requireDigit||e.match(a)?1:0,s=!r.requireNonAlphanumeric||e.match(d)?1:0;const p=(t+n+o+i+s)/5*100;l=p>=100,f(p,(e=>e>=100?"bg-success":e>=50?"bg-warning":0==e?"":"bg-danger")(p))},f=(e,t)=>{const n=document.createElement("div");n.className="progress",n.setAttribute("value",e.toString()),n.setAttribute("style",r.style),n.setAttribute("max","100"),n.setAttribute("aria-describedby","");const o=document.createElement("div");o.className="progress-bar "+t,o.style.width=e+"%",n.appendChild(o);const i=document.querySelector(r.target);i.innerHTML="",i.appendChild(n)};e.addEventListener("keyup",(()=>p(e.value))),e.addEventListener("keydown",(()=>p(e.value))),e.addEventListener("change",(()=>p(e.value))),e.addEventListener("drop",(e=>{e.preventDefault(),p(e.dataTransfer?.getData("text")??"")})),e.form?.addEventListener("submit",(t=>{p(e.value),l||t.preventDefault()}))}},{"@parcel/transformer-js/src/esmodule-helpers.js":"2Cr9l"}],"2Cr9l":[function(e,t,r,n){r.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},r.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.exportAll=function(e,t){return Object.keys(e).forEach((function(r){"default"===r||"__esModule"===r||Object.prototype.hasOwnProperty.call(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:function(){return e[r]}})})),t},r.export=function(e,t,r){Object.defineProperty(e,t,{enumerable:!0,get:r})}},{}]},["7SRNq"],"7SRNq","parcelRequire94c2"); \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets.json b/src/OrchardCore.Modules/OrchardCore.Themes/Assets.json deleted file mode 100644 index e284d4a1669..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Themes/Assets.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "inputs": [ - "Assets/js/constants.js", - "Assets/js/theme-loader.js" - ], - "watch": [ - "Assets/js/constants.js", - "Assets/js/theme-loader.js" - ], - "output": "wwwroot/Scripts/theme-head.js" - }, - { - "inputs": [ - "Assets/js/theme-toggler.js" - ], - "watch": [ - "Assets/js/theme-toggler.js" - ], - "output": "wwwroot/Scripts/theme-manager.js" - } -] diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/constants.js b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/constants.js deleted file mode 100644 index 0e7f349cc68..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/constants.js +++ /dev/null @@ -1,28 +0,0 @@ -const darkThemeName = 'dark'; -const lightThemeName = 'light'; -const themeStoreKeySuffix = 'theme'; - -const getTenantName = () => document.documentElement.getAttribute('data-tenant') || 'default'; -const getStoreKeySuffix = () => themeStoreKeySuffix || 'theme'; -const getStoreKey = () => `${getTenantName()}-${getStoreKeySuffix()}`; -const getStoredTheme = () => localStorage.getItem(getStoreKey()); -const setStoredTheme = (theme) => localStorage.setItem(getStoreKey(), theme); -const isDarkMedia = () => window.matchMedia('(prefers-color-scheme: dark)').matches; - -const getPreferredTheme = () => { - const storedTheme = getStoredTheme(); - if (storedTheme) { - return storedTheme; - } - - return isDarkMedia() ? darkThemeName : lightThemeName; -}; - -const setTheme = (theme) => { - if (theme === 'auto') { - document.documentElement.setAttribute('data-bs-theme', isDarkMedia() ? darkThemeName : lightThemeName); - } else { - document.documentElement.setAttribute('data-bs-theme', theme); - } -}; - diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-toggler.js b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-toggler.js deleted file mode 100644 index 6df6e169f90..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-toggler.js +++ /dev/null @@ -1,56 +0,0 @@ -(() => { - 'use strict' - - const showActiveTheme = (theme, focus = false) => { - const themeSwitcher = document.querySelector('#bd-theme'); - - if (!themeSwitcher) { - return; - } - - const themeSwitcherText = document.querySelector('#bd-theme-text'); - const activeThemeIcon = document.querySelector('.theme-icon-active'); - const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`); - const svgOfActiveBtn = btnToActive.querySelector('.theme-icon'); - - btnToActive.classList.add('active'); - btnToActive.setAttribute('aria-pressed', 'true'); - - activeThemeIcon.innerHTML = svgOfActiveBtn.innerHTML; - - const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`; - themeSwitcher.setAttribute('aria-label', themeSwitcherLabel); - - const btnsToInactive = document.querySelectorAll(`[data-bs-theme-value]:not([data-bs-theme-value="${theme}"])`); - - for (let i = 0; i < btnsToInactive.length; i++) { - btnsToInactive[i].classList.remove('active'); - btnsToInactive[i].setAttribute('aria-pressed', 'false'); - } - - if (focus) { - themeSwitcher.focus(); - } - } - - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { - const storedTheme = getStoredTheme() - if (storedTheme !== lightThemeName && storedTheme !== darkThemeName) { - setTheme(getPreferredTheme()); - } - }); - - window.addEventListener('DOMContentLoaded', () => { - showActiveTheme(getPreferredTheme()); - - document.querySelectorAll('[data-bs-theme-value]') - .forEach(toggle => { - toggle.addEventListener('click', () => { - const theme = toggle.getAttribute('data-bs-theme-value'); - setStoredTheme(theme); - setTheme(theme); - showActiveTheme(theme, true); - }) - }) - }); -})(); diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/package-lock.json b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/package-lock.json similarity index 100% rename from src/OrchardCore.Modules/OrchardCore.Themes/package-lock.json rename to src/OrchardCore.Modules/OrchardCore.Themes/Assets/package-lock.json diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/package.json b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/package.json similarity index 87% rename from src/OrchardCore.Modules/OrchardCore.Themes/package.json rename to src/OrchardCore.Modules/OrchardCore.Themes/Assets/package.json index 8eeab57ac39..ac294d43419 100644 --- a/src/OrchardCore.Modules/OrchardCore.Themes/package.json +++ b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/package.json @@ -1,6 +1,7 @@ { "name": "@orchardcore/themes", "version": "1.0.0", + "type": "module", "dependencies": { "@popperjs/core": "2.11.8", "bootstrap": "5.3.3" diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/constants.ts b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/constants.ts new file mode 100644 index 00000000000..f05f69883e9 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/constants.ts @@ -0,0 +1,59 @@ +const darkThemeName = "dark"; +const lightThemeName = "light"; +const themeStoreKeySuffix = "theme"; + +const getTenantName = () => + document.documentElement.getAttribute("data-tenant") || "default"; + +const getStoreKeySuffix = () => themeStoreKeySuffix || "theme"; + +const getStoreKey = () => `${getTenantName()}-${getStoreKeySuffix()}`; + +const getStoredTheme = () => localStorage.getItem(getStoreKey()); + +const setStoredTheme = (theme: string | null) => { + if (theme) { + localStorage.setItem(getStoreKey(), theme); + } +}; + +const isDarkMedia = () => + window.matchMedia("(prefers-color-scheme: dark)").matches; + +const getPreferredTheme = () => { + const storedTheme = getStoredTheme(); + if (storedTheme) { + return storedTheme; + } + + return isDarkMedia() ? darkThemeName : lightThemeName; +}; + +const setTheme = (theme: string | null) => { + if (!theme) { + return; + } + + if (theme === "auto") { + document.documentElement.setAttribute( + "data-bs-theme", + isDarkMedia() ? darkThemeName : lightThemeName + ); + } else { + document.documentElement.setAttribute("data-bs-theme", theme ?? ""); + } +}; + +export { + darkThemeName, + lightThemeName, + themeStoreKeySuffix, + getTenantName, + getStoreKeySuffix, + getStoreKey, + getStoredTheme, + setStoredTheme, + isDarkMedia, + getPreferredTheme, + setTheme, +}; diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-loader.js b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-head.ts similarity index 73% rename from src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-loader.js rename to src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-head.ts index fa28782a978..b4e3ac109c6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/js/theme-loader.js +++ b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-head.ts @@ -1,3 +1,5 @@ +import { getPreferredTheme, setTheme } from "./constants"; + // We need to apply the classes BEFORE the page is rendered. // That is why we use a MutationObserver instead of document.Ready(). const themeObserver = new MutationObserver(function (mutations) { @@ -5,12 +7,13 @@ const themeObserver = new MutationObserver(function (mutations) { for (let i = 0; i < mutations.length; i++) { for (let j = 0; j < mutations[i].addedNodes.length; j++) { - if (mutations[i].addedNodes[j].tagName == 'BODY') { + const addedNode = mutations[i].addedNodes[j] as HTMLElement; + if (addedNode.tagName === 'BODY') { setTheme(getPreferredTheme()); // we're done: themeObserver.disconnect(); - }; + } } } }); diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-manager.ts b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-manager.ts new file mode 100644 index 00000000000..d9c329cd96e --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Themes/Assets/ts/theme-manager.ts @@ -0,0 +1,65 @@ +import { darkThemeName, getPreferredTheme, getStoredTheme, lightThemeName, setStoredTheme, setTheme } from "./constants"; + +const showActiveTheme = (theme, focus = false) => { + const themeSwitcher = document.querySelector("#bd-theme"); + + if (!themeSwitcher) { + return; + } + + const themeSwitcherText = document.querySelector("#bd-theme-text"); + const activeThemeIcon = document.querySelector(".theme-icon-active"); + const btnToActive = document.querySelector( + `[data-bs-theme-value="${theme}"]` + ); + const svgOfActiveBtn = btnToActive?.querySelector(".theme-icon"); + + if (btnToActive) { + btnToActive.classList.add("active"); + btnToActive.setAttribute("aria-pressed", "true"); + } + + if (activeThemeIcon && svgOfActiveBtn) { + activeThemeIcon.innerHTML = svgOfActiveBtn.innerHTML; + } + + if (btnToActive && themeSwitcherText) { + const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`; + themeSwitcher.setAttribute("aria-label", themeSwitcherLabel); + } + + const btnsToInactive = document.querySelectorAll( + `[data-bs-theme-value]:not([data-bs-theme-value="${theme}"])` + ); + + for (let i = 0; i < btnsToInactive.length; i++) { + btnsToInactive[i].classList.remove("active"); + btnsToInactive[i].setAttribute("aria-pressed", "false"); + } + + if (focus) { + themeSwitcher.focus(); + } +}; + +window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", () => { + const storedTheme = getStoredTheme(); + if (storedTheme !== lightThemeName && storedTheme !== darkThemeName) { + setTheme(getPreferredTheme()); + } + }); + +window.addEventListener("DOMContentLoaded", () => { + showActiveTheme(getPreferredTheme()); + + document.querySelectorAll("[data-bs-theme-value]").forEach((toggle) => { + toggle.addEventListener("click", () => { + const theme = toggle.getAttribute("data-bs-theme-value"); + setStoredTheme(theme); + setTheme(theme); + showActiveTheme(theme, true); + }); + }); +}); diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/Assets2.json b/src/OrchardCore.Modules/OrchardCore.Themes/Assets2.json index 9f523b64e72..a369f888db6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Themes/Assets2.json +++ b/src/OrchardCore.Modules/OrchardCore.Themes/Assets2.json @@ -4,5 +4,19 @@ "name": "themes-admin", "source": "Assets/scss/themes.admin.scss", "tags": ["themes", "css"] + }, + { + "action": "parcel", + "name": "themes-theme-manager", + "source": "Assets/ts/theme-manager.ts", + "dest": "wwwroot/Scripts/", + "tags": ["themes", "js"] + }, + { + "action": "parcel", + "name": "themes-theme-head", + "source": "Assets/ts/theme-head.ts", + "dest": "wwwroot/Scripts/", + "tags": ["themes", "js"] } ] diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/ResourceManagementOptionsConfiguration.cs b/src/OrchardCore.Modules/OrchardCore.Themes/ResourceManagementOptionsConfiguration.cs index 9665c795f7b..620985df5da 100644 --- a/src/OrchardCore.Modules/OrchardCore.Themes/ResourceManagementOptionsConfiguration.cs +++ b/src/OrchardCore.Modules/OrchardCore.Themes/ResourceManagementOptionsConfiguration.cs @@ -3,7 +3,8 @@ namespace OrchardCore.Themes; -public sealed class ResourceManagementOptionsConfiguration : IConfigureOptions +public sealed class ResourceManagementOptionsConfiguration + : IConfigureOptions { private static readonly ResourceManifest _manifest; @@ -13,13 +14,14 @@ static ResourceManagementOptionsConfiguration() _manifest .DefineScript("theme-head") - .SetUrl("~/OrchardCore.Themes/Scripts/theme-head.min.js", "~/OrchardCore.Themes/Scripts/theme-head.js") + .SetUrl("~/OrchardCore.Themes/Scripts/theme-head.js") .SetVersion("1.0.0"); _manifest .DefineScript("theme-manager") - .SetUrl("~/OrchardCore.Themes/Scripts/theme-manager.min.js", "~/OrchardCore.Themes/Scripts/theme-manager.js") + .SetUrl("~/OrchardCore.Themes/Scripts/theme-manager.js") .SetDependencies("theme-head") + .SetAttribute("type", "module") .SetVersion("1.0.0"); } diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.js b/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.js index d0f596fdf59..0e674dbc0f5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.js +++ b/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.js @@ -1,59 +1 @@ -/* -** NOTE: This file is generated by Gulp and should not be edited directly! -** Any changes made directly to this file will be overwritten next time its asset group is processed by Gulp. -*/ - -var darkThemeName = 'dark'; -var lightThemeName = 'light'; -var themeStoreKeySuffix = 'theme'; -var getTenantName = function getTenantName() { - return document.documentElement.getAttribute('data-tenant') || 'default'; -}; -var getStoreKeySuffix = function getStoreKeySuffix() { - return themeStoreKeySuffix || 'theme'; -}; -var getStoreKey = function getStoreKey() { - return "".concat(getTenantName(), "-").concat(getStoreKeySuffix()); -}; -var getStoredTheme = function getStoredTheme() { - return localStorage.getItem(getStoreKey()); -}; -var setStoredTheme = function setStoredTheme(theme) { - return localStorage.setItem(getStoreKey(), theme); -}; -var isDarkMedia = function isDarkMedia() { - return window.matchMedia('(prefers-color-scheme: dark)').matches; -}; -var getPreferredTheme = function getPreferredTheme() { - var storedTheme = getStoredTheme(); - if (storedTheme) { - return storedTheme; - } - return isDarkMedia() ? darkThemeName : lightThemeName; -}; -var setTheme = function setTheme(theme) { - if (theme === 'auto') { - document.documentElement.setAttribute('data-bs-theme', isDarkMedia() ? darkThemeName : lightThemeName); - } else { - document.documentElement.setAttribute('data-bs-theme', theme); - } -}; -// We need to apply the classes BEFORE the page is rendered. -// That is why we use a MutationObserver instead of document.Ready(). -var themeObserver = new MutationObserver(function (mutations) { - for (var i = 0; i < mutations.length; i++) { - for (var j = 0; j < mutations[i].addedNodes.length; j++) { - if (mutations[i].addedNodes[j].tagName == 'BODY') { - setTheme(getPreferredTheme()); - - // we're done: - themeObserver.disconnect(); - } - ; - } - } -}); -themeObserver.observe(document.documentElement, { - childList: true, - subtree: true -}); \ No newline at end of file +!function(e,t,n,o){var r="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},u="function"==typeof r[o]&&r[o],f=u.cache||{},d="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function i(t,n){if(!f[t]){if(!e[t]){var a="function"==typeof r[o]&&r[o];if(!n&&a)return a(t,!0);if(u)return u(t,!0);if(d&&"string"==typeof t)return d(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}s.resolve=function(n){var o=e[t][1][n];return null!=o?o:n},s.cache={};var l=f[t]=new i.Module(t);e[t][0].call(l.exports,s,l,l.exports,r)}return f[t].exports;function s(e){var t=s.resolve(e);return!1===t?{}:i(t)}}i.isParcelRequire=!0,i.Module=function(e){this.id=e,this.bundle=i,this.exports={}},i.modules=e,i.cache=f,i.parent=u,i.register=function(t,n){e[t]=[function(e,t){t.exports=n},{}]},Object.defineProperty(i,"root",{get:function(){return r[o]}}),r[o]=i;for(var a=0;au)),r.export(n,"lightThemeName",(()=>f)),r.export(n,"themeStoreKeySuffix",(()=>d)),r.export(n,"getTenantName",(()=>i)),r.export(n,"getStoreKeySuffix",(()=>a)),r.export(n,"getStoreKey",(()=>c)),r.export(n,"getStoredTheme",(()=>l)),r.export(n,"setStoredTheme",(()=>s)),r.export(n,"isDarkMedia",(()=>m)),r.export(n,"getPreferredTheme",(()=>p)),r.export(n,"setTheme",(()=>h));const u="dark",f="light",d="theme",i=()=>document.documentElement.getAttribute("data-tenant")||"default",a=()=>d||"theme",c=()=>`${i()}-${a()}`,l=()=>localStorage.getItem(c()),s=e=>{e&&localStorage.setItem(c(),e)},m=()=>window.matchMedia("(prefers-color-scheme: dark)").matches,p=()=>{const e=l();return e||(m()?u:f)},h=e=>{e&&("auto"===e?document.documentElement.setAttribute("data-bs-theme",m()?u:f):document.documentElement.setAttribute("data-bs-theme",e??""))}},{"@parcel/transformer-js/src/esmodule-helpers.js":"h9J8A"}],h9J8A:[function(e,t,n,o){n.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},n.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},n.exportAll=function(e,t){return Object.keys(e).forEach((function(n){"default"===n||"__esModule"===n||Object.prototype.hasOwnProperty.call(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:function(){return e[n]}})})),t},n.export=function(e,t,n){Object.defineProperty(e,t,{enumerable:!0,get:n})}},{}]},["f3D3f"],"f3D3f","parcelRequire94c2"); \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.min.js b/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.min.js deleted file mode 100644 index e09c488f962..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-head.min.js +++ /dev/null @@ -1 +0,0 @@ -var darkThemeName="dark",lightThemeName="light",themeStoreKeySuffix="theme",getTenantName=function(){return document.documentElement.getAttribute("data-tenant")||"default"},getStoreKeySuffix=function(){return themeStoreKeySuffix||"theme"},getStoreKey=function(){return"".concat(getTenantName(),"-").concat(getStoreKeySuffix())},getStoredTheme=function(){return localStorage.getItem(getStoreKey())},setStoredTheme=function(e){return localStorage.setItem(getStoreKey(),e)},isDarkMedia=function(){return window.matchMedia("(prefers-color-scheme: dark)").matches},getPreferredTheme=function(){var e=getStoredTheme();return e||(isDarkMedia()?darkThemeName:lightThemeName)},setTheme=function(e){"auto"===e?document.documentElement.setAttribute("data-bs-theme",isDarkMedia()?darkThemeName:lightThemeName):document.documentElement.setAttribute("data-bs-theme",e)},themeObserver=new MutationObserver((function(e){for(var t=0;t 1 && arguments[1] !== undefined ? arguments[1] : false; - var themeSwitcher = document.querySelector('#bd-theme'); - if (!themeSwitcher) { - return; - } - var themeSwitcherText = document.querySelector('#bd-theme-text'); - var activeThemeIcon = document.querySelector('.theme-icon-active'); - var btnToActive = document.querySelector("[data-bs-theme-value=\"".concat(theme, "\"]")); - var svgOfActiveBtn = btnToActive.querySelector('.theme-icon'); - btnToActive.classList.add('active'); - btnToActive.setAttribute('aria-pressed', 'true'); - activeThemeIcon.innerHTML = svgOfActiveBtn.innerHTML; - var themeSwitcherLabel = "".concat(themeSwitcherText.textContent, " (").concat(btnToActive.dataset.bsThemeValue, ")"); - themeSwitcher.setAttribute('aria-label', themeSwitcherLabel); - var btnsToInactive = document.querySelectorAll("[data-bs-theme-value]:not([data-bs-theme-value=\"".concat(theme, "\"])")); - for (var i = 0; i < btnsToInactive.length; i++) { - btnsToInactive[i].classList.remove('active'); - btnsToInactive[i].setAttribute('aria-pressed', 'false'); - } - if (focus) { - themeSwitcher.focus(); - } - }; - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function () { - var storedTheme = getStoredTheme(); - if (storedTheme !== lightThemeName && storedTheme !== darkThemeName) { - setTheme(getPreferredTheme()); - } - }); - window.addEventListener('DOMContentLoaded', function () { - showActiveTheme(getPreferredTheme()); - document.querySelectorAll('[data-bs-theme-value]').forEach(function (toggle) { - toggle.addEventListener('click', function () { - var theme = toggle.getAttribute('data-bs-theme-value'); - setStoredTheme(theme); - setTheme(theme); - showActiveTheme(theme, true); - }); - }); - }); -})(); \ No newline at end of file +!function(e,t,r,o){var n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},a="function"==typeof n[o]&&n[o],u=a.cache||{},d="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function i(t,r){if(!u[t]){if(!e[t]){var c="function"==typeof n[o]&&n[o];if(!r&&c)return c(t,!0);if(a)return a(t,!0);if(d&&"string"==typeof t)return d(t);var s=new Error("Cannot find module '"+t+"'");throw s.code="MODULE_NOT_FOUND",s}f.resolve=function(r){var o=e[t][1][r];return null!=o?o:r},f.cache={};var l=u[t]=new i.Module(t);e[t][0].call(l.exports,f,l,l.exports,n)}return u[t].exports;function f(e){var t=f.resolve(e);return!1===t?{}:i(t)}}i.isParcelRequire=!0,i.Module=function(e){this.id=e,this.bundle=i,this.exports={}},i.modules=e,i.cache=u,i.parent=a,i.register=function(t,r){e[t]=[function(e,t){t.exports=r},{}]},Object.defineProperty(i,"root",{get:function(){return n[o]}}),n[o]=i;for(var c=0;c{const r=document.querySelector("#bd-theme");if(!r)return;const o=document.querySelector("#bd-theme-text"),n=document.querySelector(".theme-icon-active"),a=document.querySelector(`[data-bs-theme-value="${e}"]`),u=a?.querySelector(".theme-icon");if(a&&(a.classList.add("active"),a.setAttribute("aria-pressed","true")),n&&u&&(n.innerHTML=u.innerHTML),a&&o){const e=`${o.textContent} (${a.dataset.bsThemeValue})`;r.setAttribute("aria-label",e)}const d=document.querySelectorAll(`[data-bs-theme-value]:not([data-bs-theme-value="${e}"])`);for(let e=0;e{const e=(0,n.getStoredTheme)();e!==n.lightThemeName&&e!==n.darkThemeName&&(0,n.setTheme)((0,n.getPreferredTheme)())})),window.addEventListener("DOMContentLoaded",(()=>{a((0,n.getPreferredTheme)()),document.querySelectorAll("[data-bs-theme-value]").forEach((e=>{e.addEventListener("click",(()=>{const t=e.getAttribute("data-bs-theme-value");(0,n.setStoredTheme)(t),(0,n.setTheme)(t),a(t,!0)}))}))}))},{"./constants":"b4vdn"}],b4vdn:[function(e,t,r,o){var n=e("@parcel/transformer-js/src/esmodule-helpers.js");n.defineInteropFlag(r),n.export(r,"darkThemeName",(()=>a)),n.export(r,"lightThemeName",(()=>u)),n.export(r,"themeStoreKeySuffix",(()=>d)),n.export(r,"getTenantName",(()=>i)),n.export(r,"getStoreKeySuffix",(()=>c)),n.export(r,"getStoreKey",(()=>s)),n.export(r,"getStoredTheme",(()=>l)),n.export(r,"setStoredTheme",(()=>f)),n.export(r,"isDarkMedia",(()=>m)),n.export(r,"getPreferredTheme",(()=>h)),n.export(r,"setTheme",(()=>p));const a="dark",u="light",d="theme",i=()=>document.documentElement.getAttribute("data-tenant")||"default",c=()=>d||"theme",s=()=>`${i()}-${c()}`,l=()=>localStorage.getItem(s()),f=e=>{e&&localStorage.setItem(s(),e)},m=()=>window.matchMedia("(prefers-color-scheme: dark)").matches,h=()=>{const e=l();return e||(m()?a:u)},p=e=>{e&&("auto"===e?document.documentElement.setAttribute("data-bs-theme",m()?a:u):document.documentElement.setAttribute("data-bs-theme",e??""))}},{"@parcel/transformer-js/src/esmodule-helpers.js":"h9J8A"}],h9J8A:[function(e,t,r,o){r.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},r.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.exportAll=function(e,t){return Object.keys(e).forEach((function(r){"default"===r||"__esModule"===r||Object.prototype.hasOwnProperty.call(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:function(){return e[r]}})})),t},r.export=function(e,t,r){Object.defineProperty(e,t,{enumerable:!0,get:r})}},{}]},["7kSmt"],"7kSmt","parcelRequire94c2"); \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-manager.min.js b/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-manager.min.js deleted file mode 100644 index f4537733e23..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Themes/wwwroot/Scripts/theme-manager.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var e=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],a=document.querySelector("#bd-theme");if(a){var r=document.querySelector("#bd-theme-text"),n=document.querySelector(".theme-icon-active"),c=document.querySelector('[data-bs-theme-value="'.concat(e,'"]')),o=c.querySelector(".theme-icon");c.classList.add("active"),c.setAttribute("aria-pressed","true"),n.innerHTML=o.innerHTML;var d="".concat(r.textContent," (").concat(c.dataset.bsThemeValue,")");a.setAttribute("aria-label",d);for(var i=document.querySelectorAll('[data-bs-theme-value]:not([data-bs-theme-value="'.concat(e,'"])')),s=0;s