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")
@ -185,7 +186,7 @@ $(document).on('turbolinks:load', function() {
//.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")

View File

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

View File

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

View File

@ -6,8 +6,11 @@
.own-editor {
height: 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 {
background-color: #008CBA;
background-color: var(--bs-primary);
margin-top: 0;
width: 100%;
display: flex;
@ -97,7 +100,7 @@
visibility: hidden;
margin-top: .2em;
height: 1.6em;
color: #777;
color: var(--bs-tertiary-color);
font-size: 0.8em;
}
@ -188,7 +191,7 @@
#error-hints {
display: none;
background-color: #FAFAFA;
background-color: var(--bs-light-bg-subtle);
.heading {
font-weight: bold;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,7 +37,9 @@ window.SentryUtils = { dynamicSamplingContextToSentryBaggageHeader, startIdleTra
// CSS
import 'chosen-js/chosen.css';
import 'chosen-dark.scss';
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
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';
hljs.registerLanguage('julia', julia);
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 '~bootstrap/scss/bootstrap';
@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/';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/solid';

View File

@ -3,6 +3,3 @@
// JS
import * as vis from '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}"
- content_for :breadcrumbs do
.container.mb-4
ul.breadcrumb.bg-light.px-3.py-2
ul.breadcrumb.bg-body-secondary.px-3.py-2
- if root_element.present?
li.breadcrumb-item.small
= 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
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}")
span.caret
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)
.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
h4
= t('community_solutions.your_submission')

View File

@ -5,7 +5,7 @@ h1
= row(label: 'consumer.name', value: @consumer.name)
- %w[oauth_key oauth_secret].each do |attribute|
= 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}"))
= 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)
button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button'
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.shell'), shell_execution_environment_path(@execution_environment), class: 'dropdown-item text-dark') 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.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('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') if policy(@execution_environment).shell?
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') if policy(@execution_environment).destroy?
= 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))

View File

@ -35,8 +35,8 @@
#statusbar.d-flex.justify-content-between
div
- if !@embed_options[:disable_download] && @exercise.hide_file_tree?
button#download.p-0.border-0.btn-link.visible.bg-white.text-primary
- if !@embed_options[:disable_download] && !@exercise.hide_file_tree?
button#download.p-0.border-0.btn-link.visible.bg-body.text-primary
i.fa-solid.fa-arrow-down
= 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-clock-rotate-left
= 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')
= 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?
= 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' : '')
= 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
- unless @exercise.hide_file_tree
div.overflow-scroll

View File

@ -1,7 +1,7 @@
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')
= 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
@ -17,7 +17,7 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
li.card.mt-2
.card-header.py-2
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
span.number
| 0
@ -37,7 +37,7 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
li.card.mt-2
.card-header.py-2
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
span.number
| 0
@ -84,6 +84,6 @@ div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-botto
#output
.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]
#flowrHint.mb-2.card.text-white.bg-info data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.card-header = t('exercises.implement.flowr.heading')
.card-body.text-dark.bg-white
#flowrHint.mb-2.card data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.card-header.text-white.bg-info = t('exercises.implement.flowr.heading')
.card-body

View File

@ -9,5 +9,5 @@
.card-header.py-2
i.fa-solid.fa-lightbulb
= 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: '' })

View File

@ -40,17 +40,17 @@ h1
=index
- index += 1
- 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
span.ps-1.pb-1
i.fa-solid.fa-circle-info.align-middle
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
span.ps-1.pb-1
i.fa-solid.fa-circle-info.align-middle
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
.table-responsive
table.table

View File

@ -10,13 +10,13 @@ h1.d-inline-block = @exercise
= render('shared/edit_button', object: @exercise)
button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button'
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('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') 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.request_for_comment.other'), rfcs_for_exercise_path(@exercise), class: 'dropdown-item text-dark') 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('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.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.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') if policy(@exercise).statistics?
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') if policy(@exercise).rfcs_for_exercise?
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') if policy(@exercise).clone?
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.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.tags', value: @exercise.exercise_tags.map{|et| "#{et.tag.name} (#{et.factor})"}.sort.join(", "))
= 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?
.mt-2

View File

@ -81,10 +81,10 @@ h1 = @exercise
- latest_user_submission = submissions.where(user: user).final.latest
- if latest_user_submission.present?
- 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?
.unit-test-result.unknown-result.within_grace_period
.unit-test-result.unknown-result
- 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 = @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
= render('navigation', cached: true)
ul.nav.navbar-nav.ms-auto
= render('color_mode_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')
= render('session')

View File

@ -9,7 +9,7 @@ h1
= row(label: 'exercise.public', value: @proxy_exercise.public?)
= row(label: 'exercise.description', value: @proxy_exercise.description)
= 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
.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?
span.fa-solid.fa-check.fa-2x.text-success aria-hidden="true"
- 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
= ''
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"
- elsif request_for_comment.full_score_reached
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
td = ''
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
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?
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])
p.list-group-item-text
- 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|
= yield(f)
.col-sm.ge-4.gy-2

View File

@ -817,7 +817,7 @@ de:
runtime_output: "Programmausgabe"
test_results: "Testergebnisse"
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:
failure: Fehlerhafte E-Mail oder Passwort.
success: Sie haben sich erfolgreich angemeldet.
@ -859,6 +859,11 @@ de:
confirm_destroy: Sind Sie sicher?
create: '%{model} erstellen'
created_at: Erstellt
color_mode:
title: Erscheinungsbild
light: Hell
dark: Dunkel
auto: Automatisch
destroy: Löschen
edit: Bearbeiten
actions_button: 'Andere Aktionen'
@ -873,7 +878,7 @@ de:
privacy_policy: Datenschutzerklärung
index: Index
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_model: '%{model} hinzufügen'
number: Nummer

View File

@ -817,7 +817,7 @@ en:
runtime_output: "Runtime Output"
test_results: "Test Results"
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:
failure: Invalid email or password.
success: Successfully signed in.
@ -859,6 +859,11 @@ en:
confirm_destroy: Are you sure?
create: 'Create %{model}'
created_at: Created At
color_mode:
title: Appearance
light: Light
dark: Dark
auto: Auto
destroy: Delete
edit: Edit
actions_button: 'Other actions'
@ -873,7 +878,7 @@ en:
privacy_policy: Privacy Policy
index: Index
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_model: 'Add %{model}'
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)
})
})
})