Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 💥[Feature] Use upstream provided way of switching between light & dark theme variants. (by @Faraz32123, @arbirali)
- Use `indigo-2.5.0` brand version which separates the dark & light theme variants instead of using 1 theme & a class based styling on body to toggle between themes. Note: we have used design tokens for both light and dark theme variants.
- On Upstream, theme variants are set on page load using a `selected-paragon-theme-variant` value from localStorage.
37 changes: 11 additions & 26 deletions tutorindigo/patches/mfe-env-config-buildtime-definitions
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@


let themeCookie = 'indigo-toggle-dark';
let themeCookieExpiry = 90; // days
let themeVariant = 'selected-paragon-theme-variant';

const AddDarkTheme = () => {
const cookies = new Cookies();
const isThemeToggleEnabled = getConfig().INDIGO_ENABLE_DARK_TOGGLE;

const getCookieExpiry = () => {
const today = new Date();
return new Date(today.getFullYear(), today.getMonth(), today.getDate() + themeCookieExpiry);
};

const getCookieOptions = () => {
const serverURL = new URL(getConfig().LMS_BASE_URL);
const options = { domain: serverURL.hostname, path: '/', expires: getCookieExpiry() };
return options;
};

const addDarkThemeToIframes = () => {
const iframes = document.getElementsByTagName('iframe');
const iframesLength = iframes.length;
if (iframesLength > 0) {
Array.from({ length: iframesLength }).forEach((_, index) => {
const style = document.createElement('style');
style.textContent = `
body{
body {
background-color: #0D0D0E;
color: #ccc;
}
a {color: #ccc;}
a:hover{color: #d3d3d3;}
`;
if (iframes[index].contentDocument) { iframes[index].contentDocument.head.appendChild(style); }
a { color: #ccc; }
a:hover { color: #d3d3d3; }
`;
if (iframes[index].contentDocument) {
iframes[index].contentDocument.head.appendChild(style);
}
});
}
};

useEffect(() => {
const theme = cookies.get(themeCookie);
const theme = window.localStorage.getItem(themeVariant);

// - When page loads, Footer loads before MFE content. Since there is no iframe on page,
// it does not append any class. MutationObserver observes changes in DOM and hence appends dark
Expand All @@ -52,12 +39,10 @@ const AddDarkTheme = () => {
});

if (isThemeToggleEnabled && theme === 'dark') {
document.body.classList.add('indigo-dark-theme');
document.documentElement.setAttribute('data-paragon-theme-variant', 'dark');

observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => observer?.disconnect(), 15000); // clear after 15 sec to avoid resource usage

cookies.set(themeCookie, theme, getCookieOptions()); // on page load, update expiry
}

return () => observer?.disconnect();
Expand Down
90 changes: 28 additions & 62 deletions tutorindigo/patches/mfe-env-config-runtime-definitions
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const ToggleThemeButton = () => {
const intl = useIntl();
const [isDarkThemeEnabled, setIsDarkThemeEnabled] = useState(false);

const themeCookie = "indigo-toggle-dark";
const themeCookie = 'selected-paragon-theme-variant';
const themeCookieExpiry = 90; // days
const isThemeToggleEnabled = getConfig().INDIGO_ENABLE_DARK_TOGGLE;

Expand All @@ -97,6 +97,8 @@ const ToggleThemeButton = () => {
document.cookie = `${name}=${value}; domain=${domain}; path=${path}; expires=${expires.toUTCString()}; SameSite=Lax`;
};

const serverURL = new URL(getConfig().LMS_BASE_URL);

const getCookieExpiry = () => {
const today = new Date();
return new Date(
Expand All @@ -108,77 +110,41 @@ const ToggleThemeButton = () => {

const getCookieOptions = (serverURL) => ({
domain: serverURL.hostname,
path: "/",
path: '/',
expires: getCookieExpiry(),
});

const addDarkThemeToIframes = () => {
const iframes = document.getElementsByTagName("iframe");
const iframesLength = iframes.length;
if (iframesLength > 0) {
Array.from({ length: iframesLength }).forEach((_, ind) => {
const style = document.createElement("style");
style.textContent = `
body{
background-color: #0D0D0E;
color: #ccc;
}
a {color: #ccc;}
a:hover{color: #d3d3d3;}
`;
if (iframes[ind].contentDocument) {
iframes[ind].contentDocument.head.appendChild(style);
}
});
}
};

const removeDarkThemeFromiframes = () => {
const iframes = document.getElementsByTagName("iframe");
const iframesLength = iframes.length;

Array.from({ length: iframesLength }).forEach((_, ind) => {
if (iframes[ind].contentDocument) {
const iframeHead = iframes[ind].contentDocument.head;
const styleTag = Array.from(iframeHead.querySelectorAll("style")).find(
(style) =>
style.textContent.includes("background-color: #0D0D0E;") &&
style.textContent.includes("color: #ccc;")
);
if (styleTag) {
styleTag.remove();
}
}
});
};

const onToggleTheme = () => {
const serverURL = new URL(getConfig().LMS_BASE_URL);
let theme = "";
let theme = '';

if (getCookie(themeCookie) === "dark") {
document.body.classList.remove("indigo-dark-theme");
removeDarkThemeFromiframes();
if (getCookie(themeCookie) === 'dark') {
document.documentElement.setAttribute('data-paragon-theme-variant', 'light');
setIsDarkThemeEnabled(false);
theme = "light";
theme = 'light';
} else {
document.body.classList.add("indigo-dark-theme");
addDarkThemeToIframes();
document.documentElement.setAttribute('data-paragon-theme-variant', 'dark');
setIsDarkThemeEnabled(true);
theme = "dark";
}
setCookie(themeCookie, theme, getCookieOptions(serverURL));

const learningMFEUnitIframe = document.getElementById("unit-iframe");
if (learningMFEUnitIframe) {
learningMFEUnitIframe.contentWindow.postMessage(
{ "indigo-toggle-dark": theme },
serverURL.origin
);
theme = 'dark';
}

window.localStorage.setItem(themeCookie, theme);
setTimeout(() => {
setCookie(themeCookie, theme, getCookieOptions(serverURL));
window.location.reload();
}, 1);
};

const hanldeKeyUp = (event) => {
useEffect(() => {
if (!getCookie(themeCookie) || getCookie(themeCookie) === 'undefined') {
return;
}
if (getCookie(themeCookie) !== window.localStorage.getItem(themeCookie)) {
window.localStorage.setItem(themeCookie, getCookie(themeCookie));
window.location.reload();
}
}, []);

const handleKeyUp = (event) => {
if (event.key === "Enter") {
onToggleTheme();
}
Expand Down Expand Up @@ -207,7 +173,7 @@ const ToggleThemeButton = () => {
id="theme-toggle-checkbox"
defaultChecked={getCookie(themeCookie) === "dark"}
onChange={onToggleTheme}
onKeyUp={hanldeKeyUp}
onKeyUp={handleKeyUp}
type="checkbox"
title={intl.formatMessage(messages["header.user.theme"])}
/>
Expand Down
28 changes: 26 additions & 2 deletions tutorindigo/plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
import os
import typing as t
from glob import glob
Expand Down Expand Up @@ -120,7 +121,7 @@ def _override_openedx_docker_image(
(
f"mfe-dockerfile-post-npm-install-{mfe}",
"""
RUN npm install '@edx/brand@github:@edly-io/brand-openedx#indigo-2.4.3'
RUN npm install '@edx/brand@github:@edly-io/brand-openedx#indigo-2.5.0'
""", # noqa: E501
),
]
Expand All @@ -129,7 +130,7 @@ def _override_openedx_docker_image(
hooks.Filters.ENV_PATCHES.add_item(
(
"mfe-dockerfile-post-npm-install-authn",
"RUN npm install '@edx/brand@github:@edly-io/brand-openedx#indigo-2.4.3'",
"RUN npm install '@edx/brand@github:@edly-io/brand-openedx#indigo-2.5.0'",
)
)

Expand Down Expand Up @@ -296,3 +297,26 @@ def _override_openedx_docker_image(
),
]
)

paragon_theme_urls = {
"variants": {
"light": {
"urls": {
"default": "https://raw.githubusercontent.com/edly-io/brand-openedx/refs/heads/ulmo/indigo/dist/light.min.css",
"brandOverride": "https://raw.githubusercontent.com/edly-io/brand-openedx/refs/heads/ulmo/indigo/dist/light.min.css",
},
},
"dark": {
"urls": {
"default": "https://raw.githubusercontent.com/edly-io/brand-openedx/refs/heads/ulmo/indigo/dist/dark.min.css",
"brandOverride": "https://raw.githubusercontent.com/edly-io/brand-openedx/refs/heads/ulmo/indigo/dist/dark.min.css",
}
},
}
}

fstring = f"""
MFE_CONFIG["PARAGON_THEME_URLS"] = {json.dumps(paragon_theme_urls)}
"""

hooks.Filters.ENV_PATCHES.add_item(("mfe-lms-common-settings", fstring))
13 changes: 10 additions & 3 deletions tutorindigo/templates/indigo/lms/static/js/dark-theme.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
$(document).ready(function() {
'use strict';

const themeCookie = 'indigo-toggle-dark';
const themeCookie = 'selected-paragon-theme-variant';

function applyThemeOnPage(){
const theme = $.cookie(themeCookie);

if (theme === 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
setTimeout(() => {
$('body').addClass("indigo-dark-theme");
$("#toggle-switch-input").prop("checked", true);
}, 200)
}
{% if INDIGO_ENABLE_DARK_TOGGLE %}
$('body').toggleClass("indigo-dark-theme", theme === 'dark'); // append or remove dark-class based on cookie-value
// update expiry
Expand All @@ -30,11 +37,11 @@ $(document).ready(function() {
textWrapper.attr('aria-checked', 'false');
}
}

function toggleTheme(){
const themeValue = $.cookie(themeCookie) === 'dark' ? 'light' : 'dark';
$.cookie(themeCookie, themeValue, { domain: window.location.hostname, expires: 90, path: '/' });
window.localStorage.setItem(themeCookie, themeValue);
applyThemeOnPage();
}

Expand Down