Skip to content
Open
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
25 changes: 14 additions & 11 deletions htdocs/js/GatewayQuiz/gateway.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
/* gateway styles */

div.gwMessage {
background-color: #ffeeaa;
box-shadow: 3px 3px 3px darkgray;
margin: 0 0 1rem 0;
padding: 0.25rem;
border-radius: 3px;
}

#gwTimer {
position: sticky;
width: 15em;
Expand Down Expand Up @@ -60,6 +52,11 @@ table.attemptResults {
border: 1px solid #ddd;
border-radius: 3px;

[data-bs-theme='dark'] & {
border-color: #555;
background-color: var(--bs-primary-bg-subtle, 'black');
}

h2 {
display: inline-block;
font-size: 16px;
Expand All @@ -85,21 +82,27 @@ table.attemptResults {
}

colgroup.page {
border-left: solid 1pt black;
border-right: solid 1pt black;
border-left: solid 1pt var(--bs-emphasis-color, black);
border-right: solid 1pt var(--bs-emphasis-color, black);
}

.page.active {
background-color: #ffeeaa;

[data-bs-theme='dark'] & {
color: white;
background-color: #80690a;
}
}
}

div.gwDivider {
margin: 0px 0px 10px 0px;
}

/* Override the pg style so that the problem-content is not offset in gateway quizzes. */
/* Override the pg style so that the problem-content is not offset in gateway quizzes and force a light color scheme. */
.problem-content {
color-scheme: light;
padding: unset;
background-color: unset;
border: unset;
Expand Down
96 changes: 96 additions & 0 deletions htdocs/js/MathJaxConfig/bs-color-scheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
if (MathJax.loader) MathJax.loader.checkVersion('[bs-color-scheme]', '4.1.0', 'extension');

const switchToBSStyle = (obj, key = '@media (prefers-color-scheme: dark)') => {
obj["[data-bs-theme='dark']"] = obj[key];
delete obj[key];
obj["[data-bs-theme='light']"] = structuredClone(obj);
};

for (const [immediate, extension, ready] of [
[
MathJax._.ui?.dialog,
'core',
() => {
const { DraggableDialog } = MathJax._.ui.dialog.DraggableDialog;
switchToBSStyle(DraggableDialog.styles);

// This is a workaround for a bug in MathJax 4.1.0. Delete this for the next version of MathJax.
// See https://github.com/mathjax/MathJax-src/pull/1414.
DraggableDialog.styles["[data-bs-theme='dark']"]['.mjx-dialog a[href]'] =
DraggableDialog.styles["[data-bs-theme='dark']"]['a[href]'];
delete DraggableDialog.styles["[data-bs-theme='dark']"]['a[href]'];
DraggableDialog.styles["[data-bs-theme='dark']"]['.mjx-dialog a[href]:visited'] =
DraggableDialog.styles["[data-bs-theme='dark']"]['a[href]:visited'];
delete DraggableDialog.styles["[data-bs-theme='dark']"]['a[href]:visited'];
}
],
[
MathJax._.a11y?.explorer,
'a11y/explorer',
() => {
const Region = MathJax._.a11y.explorer.Region;
for (const region of ['LiveRegion', 'HoverRegion', 'ToolTip']) {
if (':root' in Region[region].style.styles) {
Region[region].style.styles["[data-bs-theme='light']"] = Region[region].style.styles[':root'];

// The variable --mjx-bg1-color is defined to be 'rgba(var(--mjx-bg-blue), var(--mjx-bg-alpha))'.
// I suspect this is a typo as the variable -mjx-bg-alpha is not defined anywhere. In any case this
// change is needed to get the correct background color on the focused element in the explorer.
Region[region].style.styles["[data-bs-theme='light']"]['--mjx-bg1-color'] =
'rgba(var(--mjx-bg-blue), var(--mjx-bg1-alpha))';
}
Region[region].style.styles["[data-bs-theme='dark']"] =
Region[region].style.styles['@media (prefers-color-scheme: dark)'];
if (':root' in Region[region].style.styles["[data-bs-theme='dark']"]) {
Object.assign(
Region[region].style.styles["[data-bs-theme='dark']"],
Region[region].style.styles["[data-bs-theme='dark']"][':root']
);
delete Region[region].style.styles["[data-bs-theme='dark']"][':root'];
}
Region[region].style.styles['@media (prefers-color-scheme: dark)'] = {};
}
Region.LiveRegion.style.styles['@media (prefers-color-scheme: dark)']['mjx-ignore'] = { ignore: 1 };
MathJax.startup.extendHandler((handler) => {
switchToBSStyle(
handler.documentClass.speechStyles,
'@media (prefers-color-scheme: dark) /* explorer */'
);
return handler;
});
}
],
[
MathJax._.output?.chtml,
'output/chtml',
() => {
const { CHTML } = MathJax._.output.chtml_ts;
switchToBSStyle(CHTML);
const { ChtmlMaction } = MathJax._.output.chtml.Wrappers.maction;
switchToBSStyle(ChtmlMaction.styles, '@media (prefers-color-scheme: dark) /* chtml maction */');
}
],
[
MathJax._.output?.svg,
'output/svg',
() => {
const { SVG } = MathJax._.output.svg_ts;
switchToBSStyle(SVG.commonStyles);
const { SvgMaction } = MathJax._.output.svg.Wrappers.maction;
switchToBSStyle(SvgMaction.styles, '@media (prefers-color-scheme: dark) /* svg maction */');
}
]
]) {
if (immediate) {
ready();
} else {
const config = MathJax.config.loader;
config[extension] ??= {};
config[extension].extraLoads ??= [];
const check = config[extension].checkReady;
config[extension].checkReady = async () => {
if (check) await check();
return ready();
};
}
}
4 changes: 2 additions & 2 deletions htdocs/js/MathJaxConfig/mathjax-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ if (!window.MathJax) {
window.MathJax = {
tex: { packages: { '[+]': webworkConfig?.showMathJaxErrors ? [] : ['noerrors'] } },
loader: {
load: ['input/asciimath', '[tex]/noerrors', '[no-dark-mode]'],
paths: { 'no-dark-mode': webworkConfig?.mathJaxDarkModeUrl ?? './no-dark-mode.js' }
load: ['input/asciimath', '[tex]/noerrors', '[bs-color-scheme]'],
paths: { 'bs-color-scheme': webworkConfig?.mathJaxBSColorSchemeUrl ?? './bs-color-scheme.js' }
},
startup: {
ready() {
Expand Down
63 changes: 0 additions & 63 deletions htdocs/js/MathJaxConfig/no-dark-mode.js

This file was deleted.

4 changes: 2 additions & 2 deletions htdocs/js/PGCodeMirror/pgeditor.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.code-mirror-editor {
border: 1px solid #ddd;
border: 1px solid var(--ww-layout-border-color, #ddd);
min-height: 400px;
overflow: auto;
resize: vertical;
Expand All @@ -25,7 +25,7 @@

// This style is used if the CodeMirror editor is disabled in localOverrides.conf.
.text-area-editor {
border: 1px solid #ddd;
border: 1px solid var(--ww-layout-border-color, #ddd);
padding: 2px;
height: 550px;
min-height: 400px;
Expand Down
1 change: 1 addition & 0 deletions htdocs/js/PGProblemEditor/pgproblemeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@
const iframe = document.createElement('iframe');
iframe.title = 'Rendered content';
iframe.id = 'pgedit-render-iframe';
iframe.style.colorScheme = 'light';

// Adjust the height of the iframe when the window is resized and when the iframe loads.
const adjustIFrameHeight = () => {
Expand Down
1 change: 1 addition & 0 deletions htdocs/js/RenderProblem/renderproblem.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
iframe = document.createElement('iframe');
iframe.id = `${renderArea.id}_iframe`;
iframe.style.border = 'none';
iframe.style.colorScheme = 'light';
while (renderArea.firstChild) renderArea.firstChild.remove();
renderArea.append(iframe);

Expand Down
75 changes: 75 additions & 0 deletions htdocs/js/System/color-scheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use strict';

(() => {
const getPreferredTheme = () => {
const storedTheme = localStorage.getItem('WW.color-scheme');
if (storedTheme) return storedTheme;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
};

let flatpickrDarkTheme;

const setTheme = (theme) => {
const themeValue =
theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme;
document.documentElement.setAttribute('data-bs-theme', themeValue);

if (!flatpickrDarkTheme) flatpickrDarkTheme = document.getElementById('flatpickr-dark-theme');
if (flatpickrDarkTheme) {
if (themeValue === 'dark') document.head.append(flatpickrDarkTheme);
else flatpickrDarkTheme.remove();
}
};

setTheme(getPreferredTheme());

const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.getElementById('color-scheme-chooser');
if (!themeSwitcher) return;

const activeThemeIcon = themeSwitcher.querySelector('.theme-icon-active');
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`);

for (const element of document.querySelectorAll('[data-bs-theme-value]')) {
element.classList.remove('active');
element.setAttribute('aria-pressed', 'false');
}

btnToActive.classList.add('active');
btnToActive.setAttribute('aria-pressed', 'true');
activeThemeIcon.classList.remove('fa-sun', 'fa-moon', 'fa-circle-half-stroke');
activeThemeIcon.classList.add(
theme === 'light' ? 'fa-sun' : theme === 'dark' ? 'fa-moon' : 'fa-circle-half-stroke'
);
themeSwitcher.setAttribute(
'aria-label',
`${themeSwitcher.title} (${
themeSwitcher.dataset[`${btnToActive.dataset.bsThemeValue}Text`] ?? btnToActive.dataset.bsThemeValue
})`
);

if (focus) themeSwitcher.focus();
};

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = localStorage.getItem('WW.color-scheme');
if (storedTheme !== 'light' && storedTheme !== 'dark') {
const preferredTheme = getPreferredTheme();
setTheme(preferredTheme);
showActiveTheme(preferredTheme);
}
});

window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme());

for (const toggle of document.querySelectorAll('[data-bs-theme-value]')) {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value');
localStorage.setItem('WW.color-scheme', theme);
setTheme(theme);
showActiveTheme(theme, true);
});
}
});
})();
Loading