Introduce Dark Mode

This commit mainly changes the color definitions. Mostly, those changes are semantically equally, but there are a few changes that occurred to align the color scheme within the app.
This commit is contained in:
Sebastian Serth
2023-06-02 09:29:43 +02:00
parent aab3b95a1d
commit 944b455194
49 changed files with 582 additions and 197 deletions

View File

@@ -17,6 +17,7 @@
//
// lib/assets
//= require flash
//= require color_mode_picker
//
// vendor/assets
//= require ace/ace

View File

@@ -208,7 +208,7 @@ $(document).on('turbolinks:load', function() {
.html(function(_event, _d) {
const e = rect.nodes();
const i = e.indexOf(this) % learners.length;
return "<strong>Student: </strong><span style='color:orange'>" + learners_name(i) + "</span><br/>" +
return "<strong>Student: </strong><span style='color:var(--bs-warning)'>" + learners_name(i) + "</span><br/>" +
"0: " + learners_time(0, i) + "<br/>" +
"1: " + learners_time(1, i) + "<br/>" +
"2: " + learners_time(2, i) + "<br/>" +

View File

@@ -20,6 +20,7 @@ $(document).on('turbolinks:load', function() {
CodeOceanEditorSubmissions
)
$(document).on('theme:change:ace', CodeOceanEditor.handleAceThemeChangeEvent.bind(CodeOceanEditor));
$('#submit').one('click', CodeOceanEditorSubmissions.submitCode.bind(CodeOceanEditor));
$('#accept').one('click', CodeOceanEditorSubmissions.submitCode.bind(CodeOceanEditor));
}

View File

@@ -19,4 +19,13 @@ $(document).on('turbolinks:load', function(event) {
// Search for insertLines and Turbolinks reload / cache control
CodeOceanEditor.initializeEverything();
}
function handleThemeChangeEvent(event) {
if (CodeOceanEditor) {
CodeOceanEditor.THEME = event.detail.currentTheme === 'dark' ? 'ace/theme/tomorrow_night' : 'ace/theme/tomorrow';
document.dispatchEvent(new Event('theme:change:ace'));
}
}
$(document).on('theme:change', handleThemeChangeEvent.bind(this));
});

View File

@@ -2,7 +2,7 @@ var CodeOceanEditor = {
//ACE-Editor-Path
// ruby part adds the relative_url_root, if it is set.
ACE_FILES_PATH: '<%= "#{Rails.application.config.relative_url_root.chomp('/')}/assets/ace/" %>',
THEME: 'ace/theme/textmate',
THEME: window.getCurrentTheme() === 'dark' ? 'ace/theme/tomorrow_night' : 'ace/theme/tomorrow',
//Color-Encoding for Percentages in Progress Bars (For submissions)
ADEQUATE_PERCENTAGE: 50,
@@ -88,13 +88,13 @@ var CodeOceanEditor = {
getCardClass: function (result) {
if (result.file_role === 'teacher_defined_linter') {
return 'card bg-info text-white'
return 'bg-info text-white'
} else if (result.stderr && !result.score) {
return 'card bg-danger text-white';
return 'bg-danger text-white';
} else if (result.score < 1) {
return 'card bg-warning text-white';
return 'bg-warning text-white';
} else {
return 'card bg-success text-white';
return 'bg-success text-white';
}
},
@@ -127,7 +127,7 @@ var CodeOceanEditor = {
if (!filetree.hasClass('jstree-loading')) {
filetree.jstree("deselect_all");
filetree.jstree().select_node(file_id);
filetree.jstree(true).select_node(file_id);
} else {
setTimeout(CodeOceanEditor.selectFileInJsTree.bind(null, filetree, file_id), 250);
}
@@ -309,16 +309,12 @@ var CodeOceanEditor = {
});
}
editor.commands.bindKey("ctrl+alt+0", null);
this.editors.push(editor);
this.editor_for_file.set($(element).parent().data('filename'), editor);
var session = editor.getSession();
var mode = $(element).data('mode')
session.setMode(mode);
if (mode === 'ace/mode/python') {
editor.setTheme('ace/theme/tomorrow')
}
session.setTabSize($(element).data('indent-size'));
session.setUseSoftTabs(true);
session.setUseWrapMode(true);
@@ -345,6 +341,12 @@ var CodeOceanEditor = {
}.bind(this));
},
handleAceThemeChangeEvent: function (event) {
this.editors.forEach(function (editor) {
editor.setTheme(this.THEME);
}.bind(this));
},
handleUTF16Surrogates: function (AceDeltaObject, AceSession) {
if (AceDeltaObject.data === undefined || AceDeltaObject.data.action !== "removeText") {
return;
@@ -372,6 +374,7 @@ var CodeOceanEditor = {
initializeEventHandlers: function () {
$(document).on('click', '#results a', this.showOutput.bind(this));
$(document).on('keydown', this.handleKeyPress.bind(this));
$(document).on('theme:change:ace', this.handleAceThemeChangeEvent.bind(this));
this.initializeFileTreeButtons();
this.initializeWorkspaceButtons();
this.initializeRequestForComments()
@@ -398,9 +401,6 @@ var CodeOceanEditor = {
}).fail(_.noop)
.always(function () {
ace.edit(editor).session.setMode(newMode);
if (newMode === 'ace/mode/python') {
ace.edit(editor).setTheme('ace/theme/tomorrow')
}
});
},
@@ -411,7 +411,9 @@ var CodeOceanEditor = {
} else {
filesInstance = $('#files');
}
filesInstance.jstree(filesInstance.data('entries'));
const jsTreeConfig = filesInstance.data('entries') || {core: {}};
jsTreeConfig.core.themes = {...jsTreeConfig.core.themes, name: window.getCurrentTheme() === "dark" ? "default-dark" : "default"}
filesInstance.jstree(jsTreeConfig);
filesInstance.on('click', 'li.jstree-leaf > a', function (event) {
const file_id = parseInt($(event.target).parent().attr('id'));
const frame = $('[data-file-id="' + file_id + '"]').parent();
@@ -419,6 +421,11 @@ var CodeOceanEditor = {
this.showFrame(frame);
this.toggleButtonStates();
}.bind(this));
$(document).on('theme:change', function(event) {
const newColorScheme = event.detail.currentTheme;
// Update the JStree theme
filesInstance.jstree(true).set_theme(newColorScheme === "dark" ? "default-dark" : "default");
});
},
initializeFileTreeButtons: function () {
@@ -539,7 +546,8 @@ var CodeOceanEditor = {
},
populateCard: function (card, result, index) {
card.addClass(this.getCardClass(result));
card.addClass('card');
card.find('.card-header').addClass(this.getCardClass(result));
card.find('.card-title .filename').text(result.filename);
card.find('.card-title .number').text(index + 1);
card.find('.row .col-md-9').eq(0).find('.number').eq(0).text(result.passed);

View File

@@ -120,19 +120,19 @@ $(document).on('turbolinks:load', function() {
var largestSubmittedTimeStamp = submissions[submissions_length-1];
var largestArrayForRange;
if(largestSubmittedTimeStamp.cause == "assess"){
if(largestSubmittedTimeStamp.cause === "assess"){
largestArrayForRange = submissionsScoreAndTimeAssess;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "submit"){
} else if(largestSubmittedTimeStamp.cause === "submit"){
largestArrayForRange = submissionsScoreAndTimeSubmits;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "run"){
} else if(largestSubmittedTimeStamp.cause === "run"){
largestArrayForRange = submissionsScoreAndTimeRuns;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "autosave"){
} else if(largestSubmittedTimeStamp.cause === "autosave"){
largestArrayForRange = submissionsAutosaves;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "save"){
} else if(largestSubmittedTimeStamp.cause === "save"){
largestArrayForRange = submissionsSaves;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
}
@@ -163,6 +163,7 @@ $(document).on('turbolinks:load', function() {
.call(yAxis);
svg.append("text") // y axis label
.attr("class", "y axis")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("dy", "-3em")
@@ -180,12 +181,12 @@ $(document).on('turbolinks:load', function() {
.style('font-size', 20)
.style('text-decoration', 'underline');
svg.append("path")
//.datum()
.attr("class", "line")
.attr('id', 'myPath')// new
.attr("stroke", "black")
.attr("stroke", "var(--bs-emphasis-color)")
.attr("stroke-width", 5)
.attr("fill", "none")// end new
.attr("d", line(submissionsScoreAndTimeAssess));//---
@@ -194,7 +195,7 @@ $(document).on('turbolinks:load', function() {
.datum(submissionsScoreAndTimeAssess)
.attr("class", "line")
.attr('id', 'myPath')// new
.attr("stroke", "orange")
.attr("stroke", "var(--bs-warning)")
.attr("stroke-width", 5)
.attr("fill", "none")// end new
.attr("d", line);//---
@@ -203,6 +204,7 @@ $(document).on('turbolinks:load', function() {
svg.selectAll("dot") // Add dots to assesses
.data(submissionsScoreAndTimeAssess)
.enter().append("circle")
.attr("fill", "var(--bs-secondary)")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d[1]); })
.attr("cy", function(d) { return y(d[0]); });
@@ -216,14 +218,14 @@ $(document).on('turbolinks:load', function() {
.data(submissionsScoreAndTimeSubmits)
.enter().append("circle")
.attr("r", 6)
.attr("stroke", "black")
.attr("fill", "blue")
.attr("stroke", "var(--bs-emphasis-color)")
.attr("fill", "var(--bs-blue)")
.attr("cx", function(d) { return x(d[1]); })
.attr("cy", function(d) { return y(d[0]); });
for (var i = 0; i < submissionsScoreAndTimeRuns.length; i++) {
svg.append("line")
.attr("stroke", "red")
.attr("stroke", "var(--bs-red)")
.attr("stroke-width", 1)
.attr("fill", "none")// end new
.attr("y1", y(0))
@@ -232,9 +234,9 @@ $(document).on('turbolinks:load', function() {
.attr("x2", x(submissionsScoreAndTimeRuns[i]));
}
var color_hash = { 0 : ["Submissions", "blue"],
1 : ["Assesses", "orange"],
2 : ["Runs", "red"]
var color_hash = { 0 : ["Submissions", "var(--bs-blue)"],
1 : ["Assesses", "var(--bs-orange)"],
2 : ["Runs", "var(--bs-red)"]
};
// add legend

View File

@@ -1,17 +1,13 @@
$(document).on('turbolinks:load', function () {
// ruby part adds the relative_url_root, if it is set.
var ACE_FILES_PATH = '<%= "#{Rails.application.config.relative_url_root.chomp('/')}/assets/ace/" %>';
var THEME = 'ace/theme/textmate';
var TAB_KEY_CODE = 9;
var execution_environments;
var file_types;
const editors = [];
var configureEditors = function () {
_.each(['modePath', 'themePath', 'workerPath'], function (attribute) {
ace.config.set(attribute, ACE_FILES_PATH);
ace.config.set(attribute, CodeOceanEditor.ACE_FILES_PATH);
});
};
@@ -28,7 +24,8 @@ $(document).on('turbolinks:load', function () {
// document.removeLines(document.getLength() - 1, document.getLength() - 1);
editor.setReadOnly($(element).data('read-only') !== undefined);
editor.setShowPrintMargin(false);
editor.setTheme(THEME);
editor.setTheme(CodeOceanEditor.THEME);
editors.push(editor);
// For creating / editing an exercise
var textarea = $('textarea[id="exercise_files_attributes_' + index + '_content"]');
@@ -52,6 +49,14 @@ $(document).on('turbolinks:load', function () {
session.setUseWrapMode(true);
}
const handleAceThemeChangeEvent = function(event) {
editors.forEach(function (editor) {
editor.setTheme(CodeOceanEditor.THEME);
}.bind(this));
};
$(document).on('theme:change:ace', handleAceThemeChangeEvent.bind(this));
var initializeEditors = function () {
// initialize ace editors for all code textareas in the dom except the last one. The last one is the dummy area for new files, which is cloned when needed.
// this one must NOT! be initialized.

View File

@@ -1,13 +1,14 @@
(function() {
var ACE_FILES_PATH = '<%= "#{Rails.application.config.relative_url_root.chomp('/')}/assets/ace/" %>';
window.MarkdownEditor = function(selector) {
ace.config.set('modePath', ACE_FILES_PATH);
_.each(['modePath', 'themePath', 'workerPath'], function (attribute) {
ace.config.set(attribute, CodeOceanEditor.ACE_FILES_PATH);
}.bind(this));
var editor = ace.edit($(selector).next()[0]);
editor.on('change', function() {
$(selector).val(editor.getValue());
});
editor.setShowPrintMargin(false);
editor.setTheme(CodeOceanEditor.THEME);
var session = editor.getSession();
session.setMode('ace/mode/markdown');
session.setUseWrapMode(true);

View File

@@ -70,6 +70,7 @@ $(document).on('turbolinks:load', function () {
// set editor mode (used for syntax highlighting
currentEditor.getSession().setMode($(editor).data('mode'));
currentEditor.getSession().setOption("useWorker", false);
currentEditor.setTheme(CodeOceanEditor.THEME);
currentEditor.commentVisualsByLine = {};
setAnnotations(currentEditor, $(editor).data('file-id'));
@@ -77,6 +78,14 @@ $(document).on('turbolinks:load', function () {
currentEditor.on("guttermousemove", showPopover);
});
const handleAceThemeChangeEvent = function() {
$('.editor').each(function (_, editor) {
ace.edit(editor).setTheme(CodeOceanEditor.THEME);
}.bind(this));
};
$(document).on('theme:change:ace', handleAceThemeChangeEvent.bind(this));
function preprocess(commentText) {
// sanitize comments to deal with XSS attacks:
commentText = $('div.sanitizer').text(commentText).html();

View File

@@ -99,13 +99,16 @@ $(document).on('turbolinks:load', function () {
fileTree.removeClass('my-3 justify-content-center');
fileTree.jstree({
'core': {
'themes': {
'name': window.getCurrentTheme() === "dark" ? "default-dark" : "default"
},
'data': {
'url': function (node) {
const params = {sudo: sudo.is(':checked')};
return Routes.list_files_in_execution_environment_path(id, params);
},
'data': function (node) {
return {'path': getPath(fileTree.jstree(), node)|| '/'};
return {'path': getPath(fileTree.jstree(true), node)|| '/'};
}
}
}
@@ -130,6 +133,11 @@ $(document).on('turbolinks:load', function () {
window.location = downloadPath;
}
}.bind(this));
$(document).on('theme:change', function(event) {
const newColorScheme = event.detail.currentTheme;
// Update the JStree theme
fileTree.jstree(true).set_theme(newColorScheme === "dark" ? "default-dark" : "default");
});
}
}

View File

@@ -1,8 +1,4 @@
$(document).on('turbolinks:load', function(event) {
var ACE_FILES_PATH = '<%= "#{Rails.application.config.relative_url_root.chomp('/')}/assets/ace/" %>';
var THEME = 'ace/theme/textmate';
var currentSubmission = 0;
var active_file = undefined;
var fileTrees = [];
@@ -24,7 +20,7 @@ $(document).on('turbolinks:load', function(event) {
var selectFileInJsTree = function() {
if (!filetree.hasClass('jstree-loading')) {
filetree.jstree("deselect_all");
filetree.jstree().select_node(active_file.file_id);
filetree.jstree("select_node", active_file.file_id);
} else {
setTimeout(selectFileInJsTree, 250);
}
@@ -38,8 +34,10 @@ $(document).on('turbolinks:load', function(event) {
var initializeFileTree = function() {
$('.files').each(function(index, element) {
fileTree = $(element).jstree($(element).data('entries'));
fileTree.on('click', 'li.jstree-leaf', function() {
const jsTreeConfig = $(element).data('entries')
jsTreeConfig.core.themes = {...jsTreeConfig.core.themes, name: window.getCurrentTheme() === "dark" ? "default-dark" : "default"}
const fileTree = $(element).jstree(jsTreeConfig);
$(element).on('click', 'li.jstree-leaf', function() {
var id = parseInt($(this).attr('id'));
_.each(files[currentSubmission], function(file) {
if (file.file_id === id) {
@@ -48,6 +46,11 @@ $(document).on('turbolinks:load', function(event) {
});
showActiveFile();
});
$(document).on('theme:change', function(event) {
const newColorScheme = event.detail.currentTheme;
// Update the JStree theme
fileTree.jstree(true).set_theme(newColorScheme === "dark" ? "default-dark" : "default");
});
fileTrees.push(fileTree);
});
};
@@ -60,7 +63,7 @@ $(document).on('turbolinks:load', function(event) {
if ($.isController('exercises') && $('#timeline').isPresent() && event.originalEvent.data.url.includes("/statistics")) {
_.each(['modePath', 'themePath', 'workerPath'], function(attribute) {
ace.config.set(attribute, ACE_FILES_PATH);
ace.config.set(attribute, CodeOceanEditor.ACE_FILES_PATH);
});
var slider = $('#submissions-slider>input');
@@ -72,7 +75,7 @@ $(document).on('turbolinks:load', function(event) {
editor = ace.edit('current-file');
editor.setShowPrintMargin(false);
editor.setTheme(THEME);
editor.setTheme(CodeOceanEditor.THEME);
editor.$blockScrolling = Infinity;
editor.setReadOnly(true);
@@ -90,6 +93,12 @@ $(document).on('turbolinks:load', function(event) {
});
});
const handleAceThemeChangeEvent = function() {
editor.setTheme(CodeOceanEditor.THEME);
};
$(document).on('theme:change:ace', handleAceThemeChangeEvent.bind(this));
const onSliderChange = function(event) {
currentSubmission = slider.val();
var currentFiles = files[currentSubmission];

View File

@@ -113,6 +113,7 @@ $(document).on('turbolinks:load', function() {
.call(yAxis);
svg.append("text") // y axis label
.attr("class", "y axis")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("dy", "-3em")
@@ -134,7 +135,7 @@ $(document).on('turbolinks:load', function() {
.datum(minutes_count)
.attr("class", "line")
.attr('id', 'myPath')
.attr("stroke", "orange")
.attr("stroke", "var(--bs-warning)")
.attr("stroke-width", 5)
.attr("fill", "none")
.attr("d", line);
@@ -216,7 +217,7 @@ $(document).on('turbolinks:load', function() {
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(_event, d) {
return "<strong>Students: </strong><span style='color:orange'>" + d + "</span>";
return "<strong>Students: </strong><span style='color:var(--bs-warning)'>" + d + "</span>";
});
var svg = d3.select("#chart_2").append("svg")
@@ -248,6 +249,7 @@ $(document).on('turbolinks:load', function() {
.attr("dy", ".71em");
svg.append("text")
.attr("class", "y axis")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("dy", "-3em")