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 // lib/assets
//= require flash //= require flash
//= require color_mode_picker
// //
// vendor/assets // vendor/assets
//= require ace/ace //= require ace/ace

View File

@ -208,7 +208,7 @@ $(document).on('turbolinks:load', function() {
.html(function(_event, _d) { .html(function(_event, _d) {
const e = rect.nodes(); const e = rect.nodes();
const i = e.indexOf(this) % learners.length; 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/>" + "0: " + learners_time(0, i) + "<br/>" +
"1: " + learners_time(1, i) + "<br/>" + "1: " + learners_time(1, i) + "<br/>" +
"2: " + learners_time(2, i) + "<br/>" + "2: " + learners_time(2, i) + "<br/>" +

View File

@ -20,6 +20,7 @@ $(document).on('turbolinks:load', function() {
CodeOceanEditorSubmissions CodeOceanEditorSubmissions
) )
$(document).on('theme:change:ace', CodeOceanEditor.handleAceThemeChangeEvent.bind(CodeOceanEditor));
$('#submit').one('click', CodeOceanEditorSubmissions.submitCode.bind(CodeOceanEditor)); $('#submit').one('click', CodeOceanEditorSubmissions.submitCode.bind(CodeOceanEditor));
$('#accept').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 // Search for insertLines and Turbolinks reload / cache control
CodeOceanEditor.initializeEverything(); 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 //ACE-Editor-Path
// ruby part adds the relative_url_root, if it is set. // ruby part adds the relative_url_root, if it is set.
ACE_FILES_PATH: '<%= "#{Rails.application.config.relative_url_root.chomp('/')}/assets/ace/" %>', 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) //Color-Encoding for Percentages in Progress Bars (For submissions)
ADEQUATE_PERCENTAGE: 50, ADEQUATE_PERCENTAGE: 50,
@ -88,13 +88,13 @@ var CodeOceanEditor = {
getCardClass: function (result) { getCardClass: function (result) {
if (result.file_role === 'teacher_defined_linter') { if (result.file_role === 'teacher_defined_linter') {
return 'card bg-info text-white' return 'bg-info text-white'
} else if (result.stderr && !result.score) { } else if (result.stderr && !result.score) {
return 'card bg-danger text-white'; return 'bg-danger text-white';
} else if (result.score < 1) { } else if (result.score < 1) {
return 'card bg-warning text-white'; return 'bg-warning text-white';
} else { } else {
return 'card bg-success text-white'; return 'bg-success text-white';
} }
}, },
@ -127,7 +127,7 @@ var CodeOceanEditor = {
if (!filetree.hasClass('jstree-loading')) { if (!filetree.hasClass('jstree-loading')) {
filetree.jstree("deselect_all"); filetree.jstree("deselect_all");
filetree.jstree().select_node(file_id); filetree.jstree(true).select_node(file_id);
} else { } else {
setTimeout(CodeOceanEditor.selectFileInJsTree.bind(null, filetree, file_id), 250); setTimeout(CodeOceanEditor.selectFileInJsTree.bind(null, filetree, file_id), 250);
} }
@ -309,16 +309,12 @@ var CodeOceanEditor = {
}); });
} }
editor.commands.bindKey("ctrl+alt+0", null); editor.commands.bindKey("ctrl+alt+0", null);
this.editors.push(editor); this.editors.push(editor);
this.editor_for_file.set($(element).parent().data('filename'), editor); this.editor_for_file.set($(element).parent().data('filename'), editor);
var session = editor.getSession(); var session = editor.getSession();
var mode = $(element).data('mode') var mode = $(element).data('mode')
session.setMode(mode); session.setMode(mode);
if (mode === 'ace/mode/python') {
editor.setTheme('ace/theme/tomorrow')
}
session.setTabSize($(element).data('indent-size')); session.setTabSize($(element).data('indent-size'));
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
session.setUseWrapMode(true); session.setUseWrapMode(true);
@ -345,6 +341,12 @@ var CodeOceanEditor = {
}.bind(this)); }.bind(this));
}, },
handleAceThemeChangeEvent: function (event) {
this.editors.forEach(function (editor) {
editor.setTheme(this.THEME);
}.bind(this));
},
handleUTF16Surrogates: function (AceDeltaObject, AceSession) { handleUTF16Surrogates: function (AceDeltaObject, AceSession) {
if (AceDeltaObject.data === undefined || AceDeltaObject.data.action !== "removeText") { if (AceDeltaObject.data === undefined || AceDeltaObject.data.action !== "removeText") {
return; return;
@ -372,6 +374,7 @@ var CodeOceanEditor = {
initializeEventHandlers: function () { initializeEventHandlers: function () {
$(document).on('click', '#results a', this.showOutput.bind(this)); $(document).on('click', '#results a', this.showOutput.bind(this));
$(document).on('keydown', this.handleKeyPress.bind(this)); $(document).on('keydown', this.handleKeyPress.bind(this));
$(document).on('theme:change:ace', this.handleAceThemeChangeEvent.bind(this));
this.initializeFileTreeButtons(); this.initializeFileTreeButtons();
this.initializeWorkspaceButtons(); this.initializeWorkspaceButtons();
this.initializeRequestForComments() this.initializeRequestForComments()
@ -398,9 +401,6 @@ var CodeOceanEditor = {
}).fail(_.noop) }).fail(_.noop)
.always(function () { .always(function () {
ace.edit(editor).session.setMode(newMode); 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 { } else {
filesInstance = $('#files'); 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) { filesInstance.on('click', 'li.jstree-leaf > a', function (event) {
const file_id = parseInt($(event.target).parent().attr('id')); const file_id = parseInt($(event.target).parent().attr('id'));
const frame = $('[data-file-id="' + file_id + '"]').parent(); const frame = $('[data-file-id="' + file_id + '"]').parent();
@ -419,6 +421,11 @@ var CodeOceanEditor = {
this.showFrame(frame); this.showFrame(frame);
this.toggleButtonStates(); this.toggleButtonStates();
}.bind(this)); }.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 () { initializeFileTreeButtons: function () {
@ -539,7 +546,8 @@ var CodeOceanEditor = {
}, },
populateCard: function (card, result, index) { 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 .filename').text(result.filename);
card.find('.card-title .number').text(index + 1); card.find('.card-title .number').text(index + 1);
card.find('.row .col-md-9').eq(0).find('.number').eq(0).text(result.passed); 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 largestSubmittedTimeStamp = submissions[submissions_length-1];
var largestArrayForRange; var largestArrayForRange;
if(largestSubmittedTimeStamp.cause == "assess"){ if(largestSubmittedTimeStamp.cause === "assess"){
largestArrayForRange = submissionsScoreAndTimeAssess; largestArrayForRange = submissionsScoreAndTimeAssess;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true); x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "submit"){ } else if(largestSubmittedTimeStamp.cause === "submit"){
largestArrayForRange = submissionsScoreAndTimeSubmits; largestArrayForRange = submissionsScoreAndTimeSubmits;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true); x.domain([0,largestArrayForRange[largestArrayForRange.length - 1][1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "run"){ } else if(largestSubmittedTimeStamp.cause === "run"){
largestArrayForRange = submissionsScoreAndTimeRuns; largestArrayForRange = submissionsScoreAndTimeRuns;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true); x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "autosave"){ } else if(largestSubmittedTimeStamp.cause === "autosave"){
largestArrayForRange = submissionsAutosaves; largestArrayForRange = submissionsAutosaves;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true); x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
} else if(largestSubmittedTimeStamp.cause == "save"){ } else if(largestSubmittedTimeStamp.cause === "save"){
largestArrayForRange = submissionsSaves; largestArrayForRange = submissionsSaves;
x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true); x.domain([0,largestArrayForRange[largestArrayForRange.length - 1]]).clamp(true);
} }
@ -163,6 +163,7 @@ $(document).on('turbolinks:load', function() {
.call(yAxis); .call(yAxis);
svg.append("text") // y axis label svg.append("text") // y axis label
.attr("class", "y axis")
.attr("transform", "rotate(-90)") .attr("transform", "rotate(-90)")
.attr("x", -height / 2) .attr("x", -height / 2)
.attr("dy", "-3em") .attr("dy", "-3em")
@ -180,12 +181,12 @@ $(document).on('turbolinks:load', function() {
.style('font-size', 20) .style('font-size', 20)
.style('text-decoration', 'underline'); .style('text-decoration', 'underline');
svg.append("path") svg.append("path")
//.datum() //.datum()
.attr("class", "line") .attr("class", "line")
.attr('id', 'myPath')// new .attr('id', 'myPath')// new
.attr("stroke", "black") .attr("stroke", "var(--bs-emphasis-color)")
.attr("stroke-width", 5) .attr("stroke-width", 5)
.attr("fill", "none")// end new .attr("fill", "none")// end new
.attr("d", line(submissionsScoreAndTimeAssess));//--- .attr("d", line(submissionsScoreAndTimeAssess));//---
@ -194,7 +195,7 @@ $(document).on('turbolinks:load', function() {
.datum(submissionsScoreAndTimeAssess) .datum(submissionsScoreAndTimeAssess)
.attr("class", "line") .attr("class", "line")
.attr('id', 'myPath')// new .attr('id', 'myPath')// new
.attr("stroke", "orange") .attr("stroke", "var(--bs-warning)")
.attr("stroke-width", 5) .attr("stroke-width", 5)
.attr("fill", "none")// end new .attr("fill", "none")// end new
.attr("d", line);//--- .attr("d", line);//---
@ -203,6 +204,7 @@ $(document).on('turbolinks:load', function() {
svg.selectAll("dot") // Add dots to assesses svg.selectAll("dot") // Add dots to assesses
.data(submissionsScoreAndTimeAssess) .data(submissionsScoreAndTimeAssess)
.enter().append("circle") .enter().append("circle")
.attr("fill", "var(--bs-secondary)")
.attr("r", 3.5) .attr("r", 3.5)
.attr("cx", function(d) { return x(d[1]); }) .attr("cx", function(d) { return x(d[1]); })
.attr("cy", function(d) { return y(d[0]); }); .attr("cy", function(d) { return y(d[0]); });
@ -216,14 +218,14 @@ $(document).on('turbolinks:load', function() {
.data(submissionsScoreAndTimeSubmits) .data(submissionsScoreAndTimeSubmits)
.enter().append("circle") .enter().append("circle")
.attr("r", 6) .attr("r", 6)
.attr("stroke", "black") .attr("stroke", "var(--bs-emphasis-color)")
.attr("fill", "blue") .attr("fill", "var(--bs-blue)")
.attr("cx", function(d) { return x(d[1]); }) .attr("cx", function(d) { return x(d[1]); })
.attr("cy", function(d) { return y(d[0]); }); .attr("cy", function(d) { return y(d[0]); });
for (var i = 0; i < submissionsScoreAndTimeRuns.length; i++) { for (var i = 0; i < submissionsScoreAndTimeRuns.length; i++) {
svg.append("line") svg.append("line")
.attr("stroke", "red") .attr("stroke", "var(--bs-red)")
.attr("stroke-width", 1) .attr("stroke-width", 1)
.attr("fill", "none")// end new .attr("fill", "none")// end new
.attr("y1", y(0)) .attr("y1", y(0))
@ -232,9 +234,9 @@ $(document).on('turbolinks:load', function() {
.attr("x2", x(submissionsScoreAndTimeRuns[i])); .attr("x2", x(submissionsScoreAndTimeRuns[i]));
} }
var color_hash = { 0 : ["Submissions", "blue"], var color_hash = { 0 : ["Submissions", "var(--bs-blue)"],
1 : ["Assesses", "orange"], 1 : ["Assesses", "var(--bs-orange)"],
2 : ["Runs", "red"] 2 : ["Runs", "var(--bs-red)"]
}; };
// add legend // add legend

View File

@ -1,17 +1,13 @@
$(document).on('turbolinks:load', function () { $(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 TAB_KEY_CODE = 9;
var execution_environments; var execution_environments;
var file_types; var file_types;
const editors = [];
var configureEditors = function () { var configureEditors = function () {
_.each(['modePath', 'themePath', 'workerPath'], function (attribute) { _.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); // document.removeLines(document.getLength() - 1, document.getLength() - 1);
editor.setReadOnly($(element).data('read-only') !== undefined); editor.setReadOnly($(element).data('read-only') !== undefined);
editor.setShowPrintMargin(false); editor.setShowPrintMargin(false);
editor.setTheme(THEME); editor.setTheme(CodeOceanEditor.THEME);
editors.push(editor);
// For creating / editing an exercise // For creating / editing an exercise
var textarea = $('textarea[id="exercise_files_attributes_' + index + '_content"]'); var textarea = $('textarea[id="exercise_files_attributes_' + index + '_content"]');
@ -52,6 +49,14 @@ $(document).on('turbolinks:load', function () {
session.setUseWrapMode(true); 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 () { 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. // 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. // this one must NOT! be initialized.

View File

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

View File

@ -70,6 +70,7 @@ $(document).on('turbolinks:load', function () {
// set editor mode (used for syntax highlighting // set editor mode (used for syntax highlighting
currentEditor.getSession().setMode($(editor).data('mode')); currentEditor.getSession().setMode($(editor).data('mode'));
currentEditor.getSession().setOption("useWorker", false); currentEditor.getSession().setOption("useWorker", false);
currentEditor.setTheme(CodeOceanEditor.THEME);
currentEditor.commentVisualsByLine = {}; currentEditor.commentVisualsByLine = {};
setAnnotations(currentEditor, $(editor).data('file-id')); setAnnotations(currentEditor, $(editor).data('file-id'));
@ -77,6 +78,14 @@ $(document).on('turbolinks:load', function () {
currentEditor.on("guttermousemove", showPopover); 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) { function preprocess(commentText) {
// sanitize comments to deal with XSS attacks: // sanitize comments to deal with XSS attacks:
commentText = $('div.sanitizer').text(commentText).html(); 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.removeClass('my-3 justify-content-center');
fileTree.jstree({ fileTree.jstree({
'core': { 'core': {
'themes': {
'name': window.getCurrentTheme() === "dark" ? "default-dark" : "default"
},
'data': { 'data': {
'url': function (node) { 'url': function (node) {
const params = {sudo: sudo.is(':checked')}; const params = {sudo: sudo.is(':checked')};
return Routes.list_files_in_execution_environment_path(id, params); return Routes.list_files_in_execution_environment_path(id, params);
}, },
'data': function (node) { '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; window.location = downloadPath;
} }
}.bind(this)); }.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) { $(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 currentSubmission = 0;
var active_file = undefined; var active_file = undefined;
var fileTrees = []; var fileTrees = [];
@ -24,7 +20,7 @@ $(document).on('turbolinks:load', function(event) {
var selectFileInJsTree = function() { var selectFileInJsTree = function() {
if (!filetree.hasClass('jstree-loading')) { if (!filetree.hasClass('jstree-loading')) {
filetree.jstree("deselect_all"); filetree.jstree("deselect_all");
filetree.jstree().select_node(active_file.file_id); filetree.jstree("select_node", active_file.file_id);
} else { } else {
setTimeout(selectFileInJsTree, 250); setTimeout(selectFileInJsTree, 250);
} }
@ -38,8 +34,10 @@ $(document).on('turbolinks:load', function(event) {
var initializeFileTree = function() { var initializeFileTree = function() {
$('.files').each(function(index, element) { $('.files').each(function(index, element) {
fileTree = $(element).jstree($(element).data('entries')); const jsTreeConfig = $(element).data('entries')
fileTree.on('click', 'li.jstree-leaf', function() { 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')); var id = parseInt($(this).attr('id'));
_.each(files[currentSubmission], function(file) { _.each(files[currentSubmission], function(file) {
if (file.file_id === id) { if (file.file_id === id) {
@ -48,6 +46,11 @@ $(document).on('turbolinks:load', function(event) {
}); });
showActiveFile(); 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); fileTrees.push(fileTree);
}); });
}; };
@ -60,7 +63,7 @@ $(document).on('turbolinks:load', function(event) {
if ($.isController('exercises') && $('#timeline').isPresent() && event.originalEvent.data.url.includes("/statistics")) { if ($.isController('exercises') && $('#timeline').isPresent() && event.originalEvent.data.url.includes("/statistics")) {
_.each(['modePath', 'themePath', 'workerPath'], function(attribute) { _.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'); var slider = $('#submissions-slider>input');
@ -72,7 +75,7 @@ $(document).on('turbolinks:load', function(event) {
editor = ace.edit('current-file'); editor = ace.edit('current-file');
editor.setShowPrintMargin(false); editor.setShowPrintMargin(false);
editor.setTheme(THEME); editor.setTheme(CodeOceanEditor.THEME);
editor.$blockScrolling = Infinity; editor.$blockScrolling = Infinity;
editor.setReadOnly(true); 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) { const onSliderChange = function(event) {
currentSubmission = slider.val(); currentSubmission = slider.val();
var currentFiles = files[currentSubmission]; var currentFiles = files[currentSubmission];

View File

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

View File

@ -9,7 +9,7 @@ h1, h2, h3, h4, h5, h6 {
.lead { .lead {
font-size: 16px; font-size: 16px;
color: rgba(70, 70, 70, 1); color: var(--bs-dark-text-emphasis);
} }
a:not(.dropdown-item, .dropdown-toggle, .dropdown-link, .btn, .page-link), .btn-link { a:not(.dropdown-item, .dropdown-toggle, .dropdown-link, .btn, .page-link), .btn-link {
@ -26,10 +26,10 @@ i.fa-solid, i.fa-regular, i.fa-solid {
} }
pre, .output-element { pre, .output-element {
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
margin: 0; margin: 0;
padding: .25rem!important; padding: .25rem!important;
border: 1px solid #CCCCCC; border: 1px solid var(--bs-border-color-translucent);
} }
span.caret { span.caret {
@ -50,14 +50,14 @@ span.caret {
.progress { .progress {
margin: 0; margin: 0;
border: 1px solid #CCCCCC; border: 1px solid var(--bs-border-color-translucent);
padding: 0.125rem !important; padding: 0.125rem !important;
height: 1.25rem !important; height: 1.25rem !important;
.progress-bar { .progress-bar {
line-height: initial; line-height: initial;
min-width: 2em; min-width: 2em;
color: white; color: var(--bs-white);
} }
} }
@ -96,10 +96,17 @@ span.caret {
.flash { .flash {
font-size: 100%; font-size: 100%;
}
a, a:hover { html[data-bs-theme="dark"] {
color: white; .alert .alert-link:hover {
font-weight: bold; filter: brightness(135%);
}
}
html[data-bs-theme="light"] {
.alert .alert-link:hover {
filter: brightness(175%);
} }
} }
@ -110,7 +117,7 @@ span.caret {
.spinner { .spinner {
width: 40px; width: 40px;
height: 40px; height: 40px;
background-color: #333; background-color: var(--bs-body-color);
margin: 100px auto; margin: 100px auto;
-webkit-animation: sk-rotateplane 1.2s infinite ease-in-out; -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;

View File

@ -20,13 +20,13 @@
border-color: transparent; border-color: transparent;
border-style: solid; border-style: solid;
border-width: 5px 0 5px 5px; border-width: 5px 0 5px 5px;
border-left-color: #cccccc; border-left-color: var(--bs-border-color-translucent);
margin-top: 5px; margin-top: 5px;
margin-right: -10px; margin-right: -10px;
} }
.dropdown-submenu:hover > a:after { .dropdown-submenu:hover > a:after {
border-left-color: #ffffff; border-left-color: var(--bs-dropdown-link-active-color);
} }
.dropdown-submenu.float-start { .dropdown-submenu.float-start {

View File

@ -6,8 +6,11 @@
.own-editor { .own-editor {
height: 100%; height: 100%;
width: 100%; width: 100%;
.ace_scroller .ace_content { }
background: #FAFAFA;
html[data-bs-theme="light"] {
.own-editor .ace_scroller .ace_content {
background-color: var(--bs-secondary-border-subtle);
} }
} }
@ -51,7 +54,7 @@
} }
#editor-buttons { #editor-buttons {
background-color: #008CBA; background-color: var(--bs-primary);
margin-top: 0; margin-top: 0;
width: 100%; width: 100%;
display: flex; display: flex;
@ -97,7 +100,7 @@
visibility: hidden; visibility: hidden;
margin-top: .2em; margin-top: .2em;
height: 1.6em; height: 1.6em;
color: #777; color: var(--bs-tertiary-color);
font-size: 0.8em; font-size: 0.8em;
} }
@ -188,7 +191,7 @@
#error-hints { #error-hints {
display: none; display: none;
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
.heading { .heading {
font-weight: bold; font-weight: bold;

View File

@ -1,7 +1,7 @@
$time-color: #008cba; $time-color: var(--bs-blue);
$min-color: #8efa00; $min-color: var(--bs-yellow);
$avg-color: #ffca00; $avg-color: var(--bs-teal);
$max-color: #ff2600; $max-color: var(--bs-red);
path.line.minimum-working-time { path.line.minimum-working-time {
stroke: $min-color; stroke: $min-color;
@ -31,7 +31,7 @@ rect.value-bar {
.box { .box {
width: 20px; width: 20px;
height: 20px; height: 20px;
border: solid 1px #000; border: solid 1px var(--bs-emphasis-color);
} }
.box.time { .box.time {
@ -62,8 +62,8 @@ rect.value-bar {
display: none; display: none;
min-width: 80px; min-width: 80px;
height: auto; height: auto;
background: none repeat scroll 0 0 #ffffff; background: none repeat scroll 0 0 var(--bs-body-bg);
border: 1px solid #008cba; border: 1px solid var(--bs-primary);
padding: 14px; padding: 14px;
text-align: center; text-align: center;
} }

View File

@ -1,5 +1,5 @@
code { code {
background-color: #F8F8F8 !important; background-color: var(--bs-light-bg-subtle) !important;
max-height: 100px; max-height: 100px;
overflow: scroll; overflow: scroll;
} }
@ -14,7 +14,7 @@ input[type='file'] {
.exercise { .exercise {
border-radius: 3px; border-radius: 3px;
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2); box-shadow: 0 2px 4px 0 rgba(var(--bs-black-rgb), 0.2);
padding: 1px 10px 1px 10px; padding: 1px 10px 1px 10px;
margin-bottom: 10px; margin-bottom: 10px;
@ -50,15 +50,17 @@ input[type='file'] {
// Graph Settings // Graph Settings
text.axis, {
fill: var(--bs-body-color);
}
.axis path { .axis path {
fill: none; fill: none;
stroke: #100;
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }
.axis line { .axis line {
fill: none; fill: none;
stroke: #999; stroke: var(--bs-tertiary-color);
//shape-rendering: crispEdges;
} }
.y.axis path { .y.axis path {
@ -77,29 +79,29 @@ input[type='file'] {
} }
div#chart_1 { div#chart_1 {
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
} }
div#chart_2 { div#chart_2 {
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
} }
div#chart_stacked { div#chart_stacked {
max-height: 500px; max-height: 500px;
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
} }
a.file-heading { a.file-heading {
color: black !important; color: var(--bs-body-color) !important;
text-decoration: none; text-decoration: none;
} }
.bar { .bar {
fill: orange; fill: var(--bs-warning);
} }
.bar:hover { .bar:hover {
fill: #ffd897; fill: var(--bs-warning-border-subtle);
} }
.container > form > .actions { .container > form > .actions {
@ -110,8 +112,8 @@ a.file-heading {
line-height: 1; line-height: 1;
font-weight: bold; font-weight: bold;
padding: 12px; padding: 12px;
background: rgba(0, 0, 0, 0.8); background: rgba(var(--bs-black-rgb), 0.8);
color: #fff; color: var(--bs-white);
border-radius: 2px; border-radius: 2px;
} }
@ -122,7 +124,7 @@ a.file-heading {
font-size: 14px; font-size: 14px;
width: 100%; width: 100%;
line-height: 1; line-height: 1;
color: rgba(0, 0, 0, 0.8); color: rgba(var(--bs-black-rgb), 0.8);
content: "\25BC"; content: "\25BC";
position: absolute; position: absolute;
text-align: center; text-align: center;
@ -142,7 +144,7 @@ a.file-heading {
} }
.value { .value {
border: 1px solid grey; border: 1px solid var(--bs-border-color-translucent);
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -216,11 +218,11 @@ a.file-heading {
} }
.export-success { .export-success {
color: darkgreen; color: var(--bs-success);
font-size: 12pt; font-size: 12pt;
font-weight: 600; font-weight: 600;
} }
.export-failure { .export-failure {
color: darkred; color: var(--bs-danger);
} }

View File

@ -31,3 +31,7 @@
.toggle-input { .toggle-input {
font-size: 80%; font-size: 80%;
} }
.wmd-preview {
background-color: var(--bs-secondary-bg);
}

View File

@ -1,7 +1,7 @@
.rfc { .rfc {
h5 { h5 {
color: #008CBA; color: var(--bs-primary);
} }
.text { .text {
@ -25,8 +25,8 @@
.text { .text {
padding: 5px; padding: 5px;
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
border: 1px solid #CCCCCC; border: 1px solid var(--bs-border-color-translucent);
} }
} }
@ -44,8 +44,8 @@
.text { .text {
padding: 5px; padding: 5px;
background-color: #FAFAFA; background-color: var(--bs-light-bg-subtle);
border: 1px solid #CCCCCC; border: 1px solid var(--bs-border-color-translucent);
} }
pre { pre {
@ -77,26 +77,26 @@
.passed { .passed {
border-radius: 50%; border-radius: 50%;
background-color: #8efa00; background-color: var(--bs-success);
-webkit-box-shadow: 0 0 11px 1px rgba(44,222,0,1); -webkit-box-shadow: 0 0 11px 1px rgba(var(--bs-success-rgb), 1);
-moz-box-shadow: 0 0 11px 1px rgba(44,222,0,1); -moz-box-shadow: 0 0 11px 1px rgba(var(--bs-success-rgb), 1);
box-shadow: 0 0 11px 1px rgba(44,222,0,1); box-shadow: 0 0 11px 1px rgba(var(--bs-success-rgb), 1);
} }
.unknown { .unknown {
border-radius: 50%; border-radius: 50%;
background-color: #ffca00; background-color: var(--bs-warning);
-webkit-box-shadow: 0 0 11px 1px rgb(255, 202, 0); -webkit-box-shadow: 0 0 11px 1px rgba(var(--bs-warning-rgb), 1);
-moz-box-shadow: 0 0 11px 1px rgb(255, 202, 0); -moz-box-shadow: 0 0 11px 1px rgba(var(--bs-warning-rgb), 1);
box-shadow: 0 0 11px 1px rgb(255, 202, 0); box-shadow: 0 0 11px 1px rgba(var(--bs-warning-rgb), 1);
} }
.failed { .failed {
border-radius: 50%; border-radius: 50%;
background-color: #ff2600; background-color: var(--bs-danger);
-webkit-box-shadow: 0 0 11px 1px rgba(222,0,0,1); -webkit-box-shadow: 0 0 11px 1px rgba(var(--bs-danger-rgb), 1);
-moz-box-shadow: 0 0 11px 1px rgba(222,0,0,1); -moz-box-shadow: 0 0 11px 1px rgba(var(--bs-danger-rgb), 1);
box-shadow: 0 0 11px 1px rgba(222,0,0,1); box-shadow: 0 0 11px 1px rgba(var(--bs-danger-rgb), 1);
} }
} }
@ -109,8 +109,8 @@
display: none; display: none;
margin-top: 20px; margin-top: 20px;
padding: 5px; padding: 5px;
border: solid lightgrey 1px; border: solid var(--bs-border-color-translucent) 1px;
background-color: rgba(20, 180, 20, 0.2); background-color: rgba(var(--bs-success-rgb),0.2);
border-radius: 4px; border-radius: 4px;
button { button {
@ -127,7 +127,12 @@
#commentitor { #commentitor {
margin-bottom: 2rem; margin-bottom: 2rem;
height: 600px; height: 600px;
background-color:#f9f9f9 }
html[data-bs-theme="light"] {
#commentitor {
background-color: var(--bs-secondary-border-subtle);
}
} }
:not(.allow_ace_tooltip) > .ace_tooltip { :not(.allow_ace_tooltip) > .ace_tooltip {
@ -180,7 +185,7 @@
.comment-date { .comment-date {
text-align: right; text-align: right;
color: #008cba; color: var(--bs-primary);
margin-left: 60%; margin-left: 60%;
font-size: x-small; font-size: x-small;
} }
@ -212,7 +217,7 @@
.comment-divider { .comment-divider {
width: 100%; width: 100%;
height: 1px; height: 1px;
background-color: #008cba; background-color: var(--bs-primary);
overflow: hidden; overflow: hidden;
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@ -226,7 +231,7 @@
.container { .container {
width: 100%; width: 100%;
overflow-y: auto; overflow-y: auto;
border: 1px solid #cccccc; border: 1px solid var(--bs-border-color-translucent);
padding: 15px; padding: 15px;
.comment-removed { .comment-removed {
@ -264,14 +269,10 @@ input#subscribe {
} }
.popover-footer { .popover-footer {
color: #008cba; color: var(--bs-primary);
margin-top: 10px; margin-top: 10px;
} }
.do-not-answer {
background-color: #ea2f1085;
}
#q_submission_study_group_id_in_chosen { #q_submission_study_group_id_in_chosen {
margin-right: 20px; margin-right: 20px;
} }

View File

@ -36,51 +36,54 @@ div.unit-test-result {
div.positive-result { div.positive-result {
border-radius: 50%; border-radius: 50%;
background-color: #8efa00; background-color: var(--bs-success);
-webkit-box-shadow: 0px 0px 11px 1px rgba(44,222,0,1); -webkit-box-shadow: 0px 0px 11px 1px rgba(var(--bs-success-rgb), 1);
-moz-box-shadow: 0px 0px 11px 1px rgba(44,222,0,1); -moz-box-shadow: 0px 0px 11px 1px rgba(var(--bs-success-rgb), 1);
box-shadow: 0px 0px 11px 1px rgba(44,222,0,1); box-shadow: 0px 0px 11px 1px rgba(var(--bs-success-rgb), 1);
} }
div.unknown-result { div.unknown-result {
border-radius: 50%; border-radius: 50%;
background-color: #ffca00; background-color: var(--bs-warning);
-webkit-box-shadow: 0px 0px 11px 1px rgb(255, 202, 0); -webkit-box-shadow: 0px 0px 11px 1px rgba(var(--bs-warning-rgb), 1);
-moz-box-shadow: 0px 0px 11px 1px rgb(255, 202, 0); -moz-box-shadow: 0px 0px 11px 1px rgba(var(--bs-warning-rgb), 1);
box-shadow: 0px 0px 11px 1px rgb(255, 202, 0); box-shadow: 0px 0px 11px 1px rgba(var(--bs-warning-rgb), 1);
} }
div.negative-result { div.negative-result {
border-radius: 50%; border-radius: 50%;
background-color: #ff2600; background-color: var(--bs-danger);
-webkit-box-shadow: 0px 0px 11px 1px rgba(222,0,0,1); -webkit-box-shadow: 0px 0px 11px 1px rgba(var(--bs-danger-rgb), 1);
-moz-box-shadow: 0px 0px 11px 1px rgba(222,0,0,1); -moz-box-shadow: 0px 0px 11px 1px rgba(var(--bs-danger-rgb), 1);
box-shadow: 0px 0px 11px 1px rgba(222,0,0,1); box-shadow: 0px 0px 11px 1px rgba(var(--bs-danger-rgb), 1);
} }
tr.active { html[data-bs-theme="dark"] {
filter: brightness(85%); tr.active {
color: #000000; filter: brightness(175%);
}
} }
tr:not(.before_deadline,.within_grace_period,.after_late_deadline) { html[data-bs-theme="light"] {
background-color: #ffffff; tr.active {
filter: brightness(85%);
}
} }
tr.highlight { tr.highlight {
border-top: 2px solid rgba(222,0,0,1); border-top: 2px solid var(--bs-red);
} }
.before_deadline { .before_deadline, .before_deadline > * {
background-color: #DAF7A6; background-color: var(--bs-success-bg-subtle) !important;
} }
.within_grace_period { .within_grace_period, .within_grace_period > * {
background-color: #F7DC6F; background-color: var(--bs-warning-bg-subtle) !important;
} }
.after_late_deadline { .after_late_deadline, .after_late_deadline > * {
background-color: #EC7063; background-color: var(--bs-danger-bg-subtle) !important;
} }
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
@ -97,13 +100,13 @@ tr.highlight {
grid-gap: 10px; grid-gap: 10px;
> a { > a {
color: #fff !important; color: var(--bs-white) !important;
text-decoration: none !important; text-decoration: none !important;
> div { > div {
border: 2px solid #0055ba; border: 2px solid var(--bs-primary-text-emphasis);
border-radius: 5px; border-radius: 5px;
background-color: #008cba; background-color: var(--bs-primary);
padding: 1em; padding: 1em;
display: flex; display: flex;
flex-flow: column-reverse; flex-flow: column-reverse;

View File

@ -37,7 +37,9 @@ window.SentryUtils = { dynamicSamplingContextToSentryBaggageHeader, startIdleTra
// CSS // CSS
import 'chosen-js/chosen.css'; import 'chosen-js/chosen.css';
import 'chosen-dark.scss';
import 'jstree/dist/themes/default/style.min.css'; import 'jstree/dist/themes/default/style.min.css';
import 'jstree/dist/themes/default-dark/style.min.css';
// custom jquery-ui library for minimal mouse interaction support // custom jquery-ui library for minimal mouse interaction support
import 'jquery-ui/ui/widget' import 'jquery-ui/ui/widget'

View File

@ -0,0 +1,140 @@
/*!
Chosen, a Select Box Enhancer for jQuery and Prototype
by Patrick Filler for Harvest, http://getharvest.com
Version 1.7.0
Full source at https://github.com/harvesthq/chosen
Copyright (c) 2011-2017 Harvest http://getharvest.com
MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
This file is generated by `grunt build`, do not edit it by hand.
*/
/*
Modified to dark version by Daniel Ziegler https://daniel-ziegler.com
MIT License
Full source at https://github.com/nook24/chosen-dark
*/
/*
Changed to work in conjunction with Bootstrap 5 for CodeOcean
*/
html[data-bs-theme="dark"] {
.chosen-container .chosen-drop {
border-color: #333;
background: #212121;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
}
/* @end */
/* @group Single Chosen */
.chosen-container-single .chosen-single {
border-color: #333;
background: #212121;
background-image: linear-gradient(#353535 1%, #212121 15%);
box-shadow: 0 0 2px #5d5d5d inset, 0 1px 0 rgba(0, 0, 0, 0.05);
color: #e3e3e3;
}
.chosen-container-single .chosen-default {
color: #999;
}
.chosen-container-single .chosen-search input[type="text"] {
border-color: #333;
color: #e3e3e3;
}
/* @end */
/* @group Results */
.chosen-container .chosen-results {
color: #e3e3e3;
}
.chosen-container .chosen-results li.disabled-result {
color: #505050;
}
.chosen-container .chosen-results li.highlighted {
background-color: #3875d7;
background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
color: #fff;
}
.chosen-container .chosen-results li.no-results {
color: #e3e3e3;
background: #1f1d1d;
}
/* @end */
/* @group Multi Chosen */
.chosen-container-multi .chosen-choices {
border-color: #333;
background: #212121;
background-image: linear-gradient(#353535 1%, #212121 15%);
}
.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
color: #e3e3e3;
}
.chosen-container-multi .chosen-choices li.search-choice {
border-color: #000;
background-color: #212121;
background-image: linear-gradient(#353535 1%, #212121 15%);
box-shadow: 0 0 2px #5d5d5d inset, 0 1px 0 rgba(0, 0, 0, 0.05);
color: #e3e3e3;
}
.chosen-container-multi .chosen-choices li.search-choice-disabled {
border: 1px solid #ccc;
background-color: #e4e4e4;
background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
color: #666;
}
.chosen-container-multi .chosen-choices li.search-choice-focus {
background: #d4d4d4;
}
.chosen-container-multi .chosen-drop .result-selected {
color: #505050;
}
/* @end */
/* @group Active */
.chosen-container-active .chosen-single {
border: 1px solid #5897fb;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}
.chosen-container-active.chosen-with-drop .chosen-single {
border-color: #333;
background-image: linear-gradient(#353535 1%, #212121 15%);
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.3) inset;
}
.chosen-container-active .chosen-choices {
border: 1px solid #5897fb;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}
.chosen-container-active .chosen-choices li.search-field input[type="text"] {
color: #e3e3e3 !important;
}
/* @end */
/* @group Disabled Support */
.chosen-disabled {
opacity: 0.5 !important;
}
/* @end */
}

View File

@ -5,6 +5,3 @@ import hljs from 'highlight.js/lib/common'
import julia from 'highlight.js/lib/languages/julia'; import julia from 'highlight.js/lib/languages/julia';
hljs.registerLanguage('julia', julia); hljs.registerLanguage('julia', julia);
window.hljs = hljs; window.hljs = hljs;
// CSS
import 'highlight.js/styles/base16/tomorrow.css'

View File

@ -0,0 +1,9 @@
// CSS for highlight.js
html[data-bs-theme="light"] {
@import 'highlight.js/styles/base16/tomorrow';
}
html[data-bs-theme="dark"] {
@import 'highlight.js/styles/base16/tomorrow-night';
}

View File

@ -11,6 +11,29 @@ $web-font-path: '//';
@import '~bootswatch/dist/yeti/variables'; @import '~bootswatch/dist/yeti/variables';
@import '~bootstrap/scss/bootstrap'; @import '~bootstrap/scss/bootstrap';
@import '~bootswatch/dist/yeti/bootswatch'; @import '~bootswatch/dist/yeti/bootswatch';
// We define our own button style here, since `btn-outline-dark` and `btn-outline-light` do not switch colors.
html[data-bs-theme="dark"] {
.btn-outline-contrast {
@extend .btn-outline-light;
}
.bg-contrast {
@extend .bg-light;
}
}
html[data-bs-theme="light"] {
.btn-outline-contrast {
@extend .btn-outline-dark;
}
.bg-contrast {
@extend .bg-dark;
}
}
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts/'; $fa-font-path: '~@fortawesome/fontawesome-free/webfonts/';
@import '~@fortawesome/fontawesome-free/scss/fontawesome'; @import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/solid'; @import '~@fortawesome/fontawesome-free/scss/solid';

View File

@ -3,6 +3,3 @@
// JS // JS
import * as vis from 'vis'; import * as vis from 'vis';
window.vis = vis; window.vis = vis;
// CSS
import 'vis-timeline/dist/vis-timeline-graph2d.css';

19
app/javascript/vis.scss Normal file
View File

@ -0,0 +1,19 @@
// CSS
@import 'vis-timeline/dist/vis-timeline-graph2d';
html[data-bs-theme="dark"] {
// Color overwrites for dark mode
.vis-legend {
background-color: rgba(var(--bs-secondary-bg-rgb), 0.65) !important;
}
.vis-timeline .vis-outline {
fill: var(--bs-body-bg) !important;
}
.vis-data-axis .vis-major, .vis-time-axis .vis-text {
color: var(--bs-secondary-text-emphasis) !important;
}
}

View File

@ -20,7 +20,7 @@
- title = "#{active_action} - #{application_name}" - title = "#{active_action} - #{application_name}"
- content_for :breadcrumbs do - content_for :breadcrumbs do
.container.mb-4 .container.mb-4
ul.breadcrumb.bg-light.px-3.py-2 ul.breadcrumb.bg-body-secondary.px-3.py-2
- if root_element.present? - if root_element.present?
li.breadcrumb-item.small li.breadcrumb-item.small
= root_element = root_element

View File

@ -0,0 +1,17 @@
li.nav-item.dropdown
a.nav-link.dropdown-toggle.me-3 data-bs-toggle='dropdown' href='#'
= t('shared.color_mode.title')
span.caret
ul.dropdown-menu.p-0.mt-1 role='menu'
li
button.dropdown-item.d-flex.align-items-center data={ 'bs-theme-value': 'light' }
i.fa-fw.fa-solid.fa-sun
= t('shared.color_mode.light')
li
button.dropdown-item.d-flex.align-items-center data={ 'bs-theme-value': 'dark' }
i.fa-fw.fa-solid.fa-moon
= t('shared.color_mode.dark')
li
button.dropdown-item.d-flex.align-items-center data={ 'bs-theme-value': 'auto' }
i.fa-fw.fa-solid.fa-wand-magic-sparkles
= t('shared.color_mode.auto')

View File

@ -1,5 +1,5 @@
li.nav-item.dropdown li.nav-item.dropdown
a.nav-link.dropdown-toggle.mx-3 data-bs-toggle='dropdown' href='#' a.nav-link.dropdown-toggle.me-3 data-bs-toggle='dropdown' href='#'
= t("locales.#{I18n.locale}") = t("locales.#{I18n.locale}")
span.caret span.caret
ul.dropdown-menu.p-0.mt-1 role='menu' ul.dropdown-menu.p-0.mt-1 role='menu'

View File

@ -42,7 +42,7 @@
= render('exercises/editor_frame', exercise: @community_solution.exercise, file: file) = render('exercises/editor_frame', exercise: @community_solution.exercise, file: file)
.col-xl-6.container-fluid .col-xl-6.container-fluid
div.bg-dark.h-100.float-start.row style="width: 1px" div.bg-contrast.h-100.float-start.row style="width: 1px"
div div
h4 h4
= t('community_solutions.your_submission') = t('community_solutions.your_submission')

View File

@ -5,7 +5,7 @@ h1
= row(label: 'consumer.name', value: @consumer.name) = row(label: 'consumer.name', value: @consumer.name)
- %w[oauth_key oauth_secret].each do |attribute| - %w[oauth_key oauth_secret].each do |attribute|
= row(label: "consumer.#{attribute}") do = row(label: "consumer.#{attribute}") do
= content_tag(:input, nil, class: 'form-control bg-secondary', readonly: true, value: @consumer.send(attribute)) = content_tag(:input, nil, class: 'form-control bg-body-secondary', readonly: true, value: @consumer.send(attribute))
= row(label: 'consumer.rfc_visibility', value: t("activerecord.attributes.consumer.rfc_visibility_type.#{@consumer.rfc_visibility}")) = row(label: 'consumer.rfc_visibility', value: t("activerecord.attributes.consumer.rfc_visibility_type.#{@consumer.rfc_visibility}"))
= render('study_groups/table', study_groups: @consumer.study_groups.sort) = render('study_groups/table', study_groups: @consumer.study_groups.sort)

View File

@ -3,10 +3,10 @@ h1.d-inline-block = @execution_environment
= render('shared/edit_button', object: @execution_environment) = render('shared/edit_button', object: @execution_environment)
button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button' button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button'
ul.dropdown-menu.dropdown-menu-end role='menu' ul.dropdown-menu.dropdown-menu-end role='menu'
li = link_to(t('execution_environments.index.synchronize.button'), sync_to_runner_management_execution_environment_path(@execution_environment), method: :post, class: 'dropdown-item text-dark') if policy(@execution_environment).sync_to_runner_management? li = link_to(t('execution_environments.index.synchronize.button'), sync_to_runner_management_execution_environment_path(@execution_environment), method: :post, class: 'dropdown-item') if policy(@execution_environment).sync_to_runner_management?
li = link_to(t('execution_environments.index.shell'), shell_execution_environment_path(@execution_environment), class: 'dropdown-item text-dark') if policy(@execution_environment).shell? li = link_to(t('execution_environments.index.shell'), shell_execution_environment_path(@execution_environment), class: 'dropdown-item') if policy(@execution_environment).shell?
li = link_to(t('shared.statistics'), statistics_execution_environment_path(@execution_environment), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@execution_environment).statistics? li = link_to(t('shared.statistics'), statistics_execution_environment_path(@execution_environment), 'data-turbolinks' => "false", class: 'dropdown-item') if policy(@execution_environment).statistics?
li = link_to(t('shared.destroy'), @execution_environment, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item text-dark') if policy(@execution_environment).destroy? li = link_to(t('shared.destroy'), @execution_environment, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(@execution_environment).destroy?
= row(label: 'execution_environment.name', value: @execution_environment.name) = row(label: 'execution_environment.name', value: @execution_environment.name)
= row(label: 'execution_environment.user', value: link_to_if(policy(@execution_environment.author).show?, @execution_environment.author, @execution_environment.author)) = row(label: 'execution_environment.user', value: link_to_if(policy(@execution_environment.author).show?, @execution_environment.author, @execution_environment.author))

View File

@ -35,8 +35,8 @@
#statusbar.d-flex.justify-content-between #statusbar.d-flex.justify-content-between
div div
- if !@embed_options[:disable_download] && @exercise.hide_file_tree? - if !@embed_options[:disable_download] && !@exercise.hide_file_tree?
button#download.p-0.border-0.btn-link.visible.bg-white.text-primary button#download.p-0.border-0.btn-link.visible.bg-body.text-primary
i.fa-solid.fa-arrow-down i.fa-solid.fa-arrow-down
= t('exercises.editor.download') = t('exercises.editor.download')
@ -47,7 +47,7 @@
= " | " = " | "
button#start-over-active-file.p-0.border-0.btn-link.bg-white.text-primary data-message-confirm=t('exercises.editor.confirm_start_over_active_file') data-url=reload_exercise_path(@exercise) button#start-over-active-file.p-0.border-0.btn-link.bg-body.text-primary data-message-confirm=t('exercises.editor.confirm_start_over_active_file') data-url=reload_exercise_path(@exercise)
i.fa-solid.fa-circle-notch.fa-spin.d-none i.fa-solid.fa-circle-notch.fa-spin.d-none
i.fa-solid.fa-clock-rotate-left i.fa-solid.fa-clock-rotate-left
= t('exercises.editor.start_over_active_file') = t('exercises.editor.start_over_active_file')

View File

@ -1,11 +1,11 @@
div.d-grid.gap-2 id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none') div.d-grid.gap-2 id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none')
= render('editor_button', classes: 'btn-outline-dark', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-square-plus', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar')) = render('editor_button', classes: 'btn-outline-contrast', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-square-plus', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar'))
- unless @embed_options[:disable_hints] or @tips.blank? - unless @embed_options[:disable_hints] or @tips.blank?
= render('editor_button', classes: 'btn-secondary btn mb-4', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips')) = render('editor_button', classes: 'btn-secondary btn mb-4', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips'))
div.d-grid.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '') div.d-grid.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '')
= render('editor_button', classes: 'btn-outline-dark overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar')) = render('editor_button', classes: 'btn-outline-contrast overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar'))
#content-left-sidebar.overflow-scroll #content-left-sidebar.overflow-scroll
- unless @exercise.hide_file_tree - unless @exercise.hide_file_tree
div.overflow-scroll div.overflow-scroll

View File

@ -1,7 +1,7 @@
div.d-grid id='output_sidebar_collapsed' div.d-grid id='output_sidebar_collapsed'
= render('editor_button', classes: 'btn-outline-dark btn', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa-solid fa-square-plus', id: 'toggle-sidebar-output-collapsed', label: '') = render('editor_button', classes: 'btn-outline-contrast btn', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa-solid fa-square-plus', id: 'toggle-sidebar-output-collapsed', label: '')
div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output_yet') div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output_yet')
= render('editor_button', classes: 'btn-outline-dark btn overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar')) = render('editor_button', classes: 'btn-outline-contrast btn overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar'))
#content-right-sidebar.overflow-scroll #content-right-sidebar.overflow-scroll
@ -17,7 +17,7 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
li.card.mt-2 li.card.mt-2
.card-header.py-2 .card-header.py-2
h5.card-title.m-0 == t('exercises.implement.test_file', filename: '', number: 0) h5.card-title.m-0 == t('exercises.implement.test_file', filename: '', number: 0)
.card-body.bg-white.text-dark .card-body
= row(label: 'exercises.implement.passed_tests') do = row(label: 'exercises.implement.passed_tests') do
span.number span.number
| 0 | 0
@ -37,7 +37,7 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
li.card.mt-2 li.card.mt-2
.card-header.py-2 .card-header.py-2
h5.card-title.m-0 == t('exercises.implement.linter_file', filename: '', number: 0) h5.card-title.m-0 == t('exercises.implement.linter_file', filename: '', number: 0)
.card-body.bg-white.text-dark .card-body
= row(label: 'exercises.implement.code_rating') do = row(label: 'exercises.implement.code_rating') do
span.number span.number
| 0 | 0
@ -84,6 +84,6 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
#output #output
.output-element.overflow-scroll = t('exercises.implement.no_output_yet') .output-element.overflow-scroll = t('exercises.implement.no_output_yet')
- if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled] && !@embed_options[:disable_hints] && !@embed_options[:hide_test_results] - if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled] && !@embed_options[:disable_hints] && !@embed_options[:hide_test_results]
#flowrHint.mb-2.card.text-white.bg-info data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab' #flowrHint.mb-2.card data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.card-header = t('exercises.implement.flowr.heading') .card-header.text-white.bg-info = t('exercises.implement.flowr.heading')
.card-body.text-dark.bg-white .card-body

View File

@ -9,5 +9,5 @@
.card-header.py-2 .card-header.py-2
i.fa-solid.fa-lightbulb i.fa-solid.fa-lightbulb
= t('exercises.implement.tips.heading') = t('exercises.implement.tips.heading')
.card-body.text-dark.bg-white.p-2 .card-body.p-2
= render(partial: 'tips/collapsed_card', collection: @tips, as: :exercise_tip, locals: { tip_prefix: '' }) = render(partial: 'tips/collapsed_card', collection: @tips, as: :exercise_tip, locals: { tip_prefix: '' })

View File

@ -40,17 +40,17 @@ h1
=index =index
- index += 1 - index += 1
- if policy(@exercise).detailed_statistics? - if policy(@exercise).detailed_statistics?
.bg-light.w-100.p-2.mb-4.align-items-center.d-flex.justify-content-between .bg-body-secondary.w-100.p-2.mb-4.align-items-center.d-flex.justify-content-between
- if @show_autosaves - if @show_autosaves
span.ps-1.pb-1 span.ps-1.pb-1
i.fa-solid.fa-circle-info.align-middle i.fa-solid.fa-circle-info.align-middle
small.me-5.ms-1 = t('.toggle_status_on') small.me-5.ms-1 = t('.toggle_status_on')
= link_to t('.toggle_autosave_off'), statistics_external_user_exercise_path(show_autosaves: false), class: "btn btn-outline-dark float-end btn-sm" = link_to t('.toggle_autosave_off'), statistics_external_user_exercise_path(show_autosaves: false), class: "btn btn-outline-contrast float-end btn-sm"
- else - else
span.ps-1.pb-1 span.ps-1.pb-1
i.fa-solid.fa-circle-info.align-middle i.fa-solid.fa-circle-info.align-middle
small.me-5.ms-1 = t('.toggle_status_off') small.me-5.ms-1 = t('.toggle_status_off')
= link_to t('.toggle_autosave_on'), statistics_external_user_exercise_path(show_autosaves: true), class: "btn btn-outline-dark float-end btn-sm" = link_to t('.toggle_autosave_on'), statistics_external_user_exercise_path(show_autosaves: true), class: "btn btn-outline-contrast float-end btn-sm"
#timeline #timeline
.table-responsive .table-responsive
table.table table.table

View File

@ -10,13 +10,13 @@ h1.d-inline-block = @exercise
= render('shared/edit_button', object: @exercise) = render('shared/edit_button', object: @exercise)
button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button' button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button'
ul.dropdown-menu.dropdown-menu-end role='menu' ul.dropdown-menu.dropdown-menu-end role='menu'
li = link_to(t('exercises.index.implement'), implement_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@exercise).implement? li = link_to(t('exercises.index.implement'), implement_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item') if policy(@exercise).implement?
li = link_to(t('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@exercise).statistics? li = link_to(t('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item') if policy(@exercise).statistics?
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(@exercise), class: 'dropdown-item text-dark') if policy(@exercise).feedback? li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(@exercise), class: 'dropdown-item') if policy(@exercise).feedback?
li = link_to(t('activerecord.models.request_for_comment.other'), rfcs_for_exercise_path(@exercise), class: 'dropdown-item text-dark') if policy(@exercise).rfcs_for_exercise? li = link_to(t('activerecord.models.request_for_comment.other'), rfcs_for_exercise_path(@exercise), class: 'dropdown-item') if policy(@exercise).rfcs_for_exercise?
li = link_to(t('shared.destroy'), @exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item text-dark') if policy(@exercise).destroy? li = link_to(t('shared.destroy'), @exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(@exercise).destroy?
li = link_to(t('exercises.index.clone'), clone_exercise_path(@exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item text-dark') if policy(@exercise).clone? li = link_to(t('exercises.index.clone'), clone_exercise_path(@exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(@exercise).clone?
li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start text-dark', data: {'exercise-id' => @exercise.id}) if policy(@exercise).export_external_confirm? li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id' => @exercise.id}) if policy(@exercise).export_external_confirm?
= row(label: 'exercise.title', value: @exercise.title) = row(label: 'exercise.title', value: @exercise.title)
= row(label: 'exercise.user', value: link_to_if(policy(@exercise.author).show?, @exercise.author, @exercise.author)) = row(label: 'exercise.user', value: link_to_if(policy(@exercise.author).show?, @exercise.author, @exercise.author))
@ -35,7 +35,7 @@ h1.d-inline-block = @exercise
= row(label: 'exercise.uuid', value: @exercise.uuid) = row(label: 'exercise.uuid', value: @exercise.uuid)
= row(label: 'exercise.tags', value: @exercise.exercise_tags.map{|et| "#{et.tag.name} (#{et.factor})"}.sort.join(", ")) = row(label: 'exercise.tags', value: @exercise.exercise_tags.map{|et| "#{et.tag.name} (#{et.factor})"}.sort.join(", "))
= row(label: 'exercise.embedding_parameters', class: 'mb-4') do = row(label: 'exercise.embedding_parameters', class: 'mb-4') do
= content_tag(:input, nil, class: 'form-control bg-secondary mb-4', readonly: true, value: @exercise.unpublished? ? t('exercises.show.is_unpublished') : embedding_parameters(@exercise)) = content_tag(:input, nil, class: 'form-control bg-body-secondary mb-4', readonly: true, value: @exercise.unpublished? ? t('exercises.show.is_unpublished') : embedding_parameters(@exercise))
- unless @tips.blank? - unless @tips.blank?
.mt-2 .mt-2

View File

@ -81,10 +81,10 @@ h1 = @exercise
- latest_user_submission = submissions.where(user: user).final.latest - latest_user_submission = submissions.where(user: user).final.latest
- if latest_user_submission.present? - if latest_user_submission.present?
- if latest_user_submission.before_deadline? - if latest_user_submission.before_deadline?
.unit-test-result.positive-result.before_deadline .unit-test-result.positive-result
- elsif latest_user_submission.within_grace_period? - elsif latest_user_submission.within_grace_period?
.unit-test-result.unknown-result.within_grace_period .unit-test-result.unknown-result
- elsif latest_user_submission.after_late_deadline? - elsif latest_user_submission.after_late_deadline?
.unit-test-result.negative-result.after_late_deadline .unit-test-result.negative-result
td = us['runs'] if policy(@exercise).detailed_statistics? td = us['runs'] if policy(@exercise).detailed_statistics?
td = @exercise.average_working_time_for(user) or 0 if policy(@exercise).detailed_statistics? td = @exercise.average_working_time_for(user) or 0 if policy(@exercise).detailed_statistics?

View File

@ -29,6 +29,7 @@ html lang="#{I18n.locale || I18n.default_locale}" data-default-locale="#{I18n.de
#navbar-collapse.collapse.navbar-collapse #navbar-collapse.collapse.navbar-collapse
= render('navigation', cached: true) = render('navigation', cached: true)
ul.nav.navbar-nav.ms-auto ul.nav.navbar-nav.ms-auto
= render('color_mode_selector', cached: true)
= render('locale_selector', cached: true) = render('locale_selector', cached: true)
li.nav-item.me-3 = link_to(t('shared.help.link'), '#modal-help', data: {'bs-toggle': 'modal'}, class: 'nav-link') li.nav-item.me-3 = link_to(t('shared.help.link'), '#modal-help', data: {'bs-toggle': 'modal'}, class: 'nav-link')
= render('session') = render('session')

View File

@ -9,7 +9,7 @@ h1
= row(label: 'exercise.public', value: @proxy_exercise.public?) = row(label: 'exercise.public', value: @proxy_exercise.public?)
= row(label: 'exercise.description', value: @proxy_exercise.description) = row(label: 'exercise.description', value: @proxy_exercise.description)
= row(label: 'exercise.embedding_parameters', class: 'mb-4') do = row(label: 'exercise.embedding_parameters', class: 'mb-4') do
= content_tag(:input, nil, class: 'form-control bg-secondary mb-4', readonly: true, value: embedding_parameters(@proxy_exercise)) = content_tag(:input, nil, class: 'form-control bg-body-secondary mb-4', readonly: true, value: embedding_parameters(@proxy_exercise))
h2.mt-4 Exercises h2.mt-4 Exercises
.table-responsive .table-responsive

View File

@ -3,7 +3,7 @@ tr.table-row-clickable data-id=request_for_comment.id data-href=request_for_comm
- if request_for_comment.solved? - if request_for_comment.solved?
span.fa-solid.fa-check.fa-2x.text-success aria-hidden="true" span.fa-solid.fa-check.fa-2x.text-success aria-hidden="true"
- elsif request_for_comment.full_score_reached - elsif request_for_comment.full_score_reached
span.fa-solid.fa-check.fa-2x style="color:darkgrey" aria-hidden="true" span.fa-solid.fa-check.fa-2x style="color: var(--bs-secondary-text-emphasis);" aria-hidden="true"
- else - else
= '' = ''
td.text-center = request_for_comment.comments_count td.text-center = request_for_comment.comments_count

View File

@ -37,7 +37,7 @@ h1 = RequestForComment.model_name.human(count: 2)
span class="fa-solid fa-check" aria-hidden="true" span class="fa-solid fa-check" aria-hidden="true"
- elsif request_for_comment.full_score_reached - elsif request_for_comment.full_score_reached
td td
span class="fa-solid fa-check" style="color:darkgrey" aria-hidden="true" span class="fa-solid fa-check" style="color: var(--bs-secondary-text-emphasis);" aria-hidden="true"
- else - else
td = '' td = ''
td = link_to_if(policy(request_for_comment).show?, request_for_comment.submission.exercise.title, request_for_comment) td = link_to_if(policy(request_for_comment).show?, request_for_comment.submission.exercise.title, request_for_comment)

View File

@ -1,7 +1,7 @@
.list-group .list-group
h4#exercise_caption.list-group-item-heading data-exercise-id="#{@request_for_comment.exercise.id}" data-rfc-id="#{@request_for_comment.id}" h4#exercise_caption.list-group-item-heading data-exercise-id="#{@request_for_comment.exercise.id}" data-rfc-id="#{@request_for_comment.id}"
- if @request_for_comment.solved? - if @request_for_comment.solved?
span.fa-solid.fa-check aria-hidden="true" span.fa-solid.fa-check.me-2 aria-hidden="true"
= link_to_if(policy(@request_for_comment.exercise).show?, @request_for_comment.exercise.title, [:implement, @request_for_comment.exercise]) = link_to_if(policy(@request_for_comment.exercise).show?, @request_for_comment.exercise.title, [:implement, @request_for_comment.exercise])
p.list-group-item-text p.list-group-item-text
- user = @request_for_comment.user - user = @request_for_comment.user

View File

@ -1,4 +1,4 @@
.card.card-body.bg-light.flex-row.container.justify-content-center .card.card-body.bg-body-secondary.flex-row.container.justify-content-center
= search_form_for(@search, class: 'clearfix filter-form align-items-center row g-2 w-100') do |f| = search_form_for(@search, class: 'clearfix filter-form align-items-center row g-2 w-100') do |f|
= yield(f) = yield(f)
.col-sm.ge-4.gy-2 .col-sm.ge-4.gy-2

View File

@ -817,7 +817,7 @@ de:
runtime_output: "Programmausgabe" runtime_output: "Programmausgabe"
test_results: "Testergebnisse" test_results: "Testergebnisse"
sessions: sessions:
expired: Ihre Session ist abgelaufen. Bitte <a href="" class="reloadCurrentPage">laden Sie diese Seite neu</a> bevor Sie fortfahren. expired: Ihre Session ist abgelaufen. Bitte <a href="" class="reloadCurrentPage alert-link">laden Sie diese Seite neu</a> bevor Sie fortfahren.
create: create:
failure: Fehlerhafte E-Mail oder Passwort. failure: Fehlerhafte E-Mail oder Passwort.
success: Sie haben sich erfolgreich angemeldet. success: Sie haben sich erfolgreich angemeldet.
@ -859,6 +859,11 @@ de:
confirm_destroy: Sind Sie sicher? confirm_destroy: Sind Sie sicher?
create: '%{model} erstellen' create: '%{model} erstellen'
created_at: Erstellt created_at: Erstellt
color_mode:
title: Erscheinungsbild
light: Hell
dark: Dunkel
auto: Automatisch
destroy: Löschen destroy: Löschen
edit: Bearbeiten edit: Bearbeiten
actions_button: 'Andere Aktionen' actions_button: 'Andere Aktionen'
@ -873,7 +878,7 @@ de:
privacy_policy: Datenschutzerklärung privacy_policy: Datenschutzerklärung
index: Index index: Index
message_failure: Leider ist ein Fehler auf unserer Plattform aufgetreten. Bitte probieren Sie es später noch einmal. message_failure: Leider ist ein Fehler auf unserer Plattform aufgetreten. Bitte probieren Sie es später noch einmal.
websocket_failure: Leider ist ein Verbindungsproblem aufgetreten. <a href="https://websocketstest.com" target="_blank" rel="noopener">Bitte überprüfen Sie Websocket-Verbindungen mit diesem Tool</a> und versuchen Sie es erneut. websocket_failure: Leider ist ein Verbindungsproblem aufgetreten. <a href="https://websocketstest.com" target="_blank" rel="noopener" class="alert-link">Bitte überprüfen Sie Websocket-Verbindungen mit diesem Tool</a> und versuchen Sie es erneut.
new: Hinzufügen new: Hinzufügen
new_model: '%{model} hinzufügen' new_model: '%{model} hinzufügen'
number: Nummer number: Nummer

View File

@ -817,7 +817,7 @@ en:
runtime_output: "Runtime Output" runtime_output: "Runtime Output"
test_results: "Test Results" test_results: "Test Results"
sessions: sessions:
expired: Your session has expired. Please <a href="" class="reloadCurrentPage">reload this page</a> before continuing. expired: Your session has expired. Please <a href="" class="reloadCurrentPage alert-link">reload this page</a> before continuing.
create: create:
failure: Invalid email or password. failure: Invalid email or password.
success: Successfully signed in. success: Successfully signed in.
@ -859,6 +859,11 @@ en:
confirm_destroy: Are you sure? confirm_destroy: Are you sure?
create: 'Create %{model}' create: 'Create %{model}'
created_at: Created At created_at: Created At
color_mode:
title: Appearance
light: Light
dark: Dark
auto: Auto
destroy: Delete destroy: Delete
edit: Edit edit: Edit
actions_button: 'Other actions' actions_button: 'Other actions'
@ -873,7 +878,7 @@ en:
privacy_policy: Privacy Policy privacy_policy: Privacy Policy
index: Index index: Index
message_failure: 'Sorry, something went wrong.' message_failure: 'Sorry, something went wrong.'
websocket_failure: Sorry, a connection issue occoured. <a href="https://websocketstest.com" target="_blank" rel="noopener">Please check WebSocket connections with this tool</a> and try again. websocket_failure: Sorry, a connection issue occoured. <a href="https://websocketstest.com" target="_blank" rel="noopener" class="alert-link">Please check WebSocket connections with this tool</a> and try again.
new: Add new: Add
new_model: 'Add %{model}' new_model: 'Add %{model}'
number: Number number: Number

View File

@ -0,0 +1,95 @@
/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
* Taken from https://getbootstrap.com/docs/5.3/customize/color-modes/#javascript
*/
const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)
const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
const setTheme = theme => {
let currentTheme = theme || 'auto';
if (theme === 'auto') {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
currentTheme = 'dark'
} else {
currentTheme = 'light'
}
}
const event = new CustomEvent('theme:change', {
bubbles: true,
cancelable: false,
detail: {
preferredTheme: theme,
currentTheme: currentTheme,
}
})
document.dispatchEvent(event)
document.documentElement.setAttribute('data-bs-theme', currentTheme)
}
window.getCurrentTheme = () => {
return document.documentElement.getAttribute('data-bs-theme');
}
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 use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})
btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
if (focus) {
themeSwitcher.focus()
}
}
$(document).on('turbolinks:load', function() {
setTheme(getPreferredTheme())
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
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)
})
})
})