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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions app/views/settings/_redmine_dark_settings.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<p>
<%= check_box_tag 'settings[follow_browser_theme]', '1',
@settings['follow_browser_theme'].to_s == '1' || @settings['follow_browser_theme'].to_s == 'true' %>
<label for="settings_follow_browser_theme">
Follow browser/OS dark theme preference
</label>
</p>
<p class="info">
When enabled, dark mode will automatically activate based on your browser or operating system's dark theme setting,
in addition to the manual toggle. When disabled, dark mode can only be activated using the manual toggle.
</p>
46 changes: 28 additions & 18 deletions assets/javascripts/dark.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,36 @@ function clickdarkmode() {
}

$(document).ready(function() {
console.log("dark.js");
var topmenu = document.getElementById("top-menu");
var divdark = document.createElement("div");
divdark.id = "dark";
var adivdark = document.createElement("a");
adivdark.innerText = "dark mode";
adivdark.href = "";
divdark.appendChild(adivdark);
topmenu.insertBefore(divdark, topmenu.firstChild)
adivdark.onclick = clickdarkmode;
// Add to desktop top menu - as a list item in the account menu
var accountUl = document.querySelector("#account ul");
if (accountUl) {
var lidark = document.createElement("li");
var adivdark = document.createElement("a");
adivdark.innerText = "dark mode";
adivdark.href = "#";
adivdark.className = "dark-mode-toggle";
lidark.appendChild(adivdark);
accountUl.appendChild(lidark);
adivdark.onclick = clickdarkmode;
}

// Add to mobile flyout menu
try {
var ulmobil = document.querySelectorAll('#wrapper .js-profile-menu ul')[0];
var lidark = document.createElement("li");
var alidark = document.createElement("a");
alidark.innerText = "dark mode";
alidark.href = "";
lidark.appendChild(alidark);
ulmobil.appendChild(lidark);
alidark.onclick = clickdarkmode;
} catch (e) {}
if (ulmobil) {
var lidark = document.createElement("li");
var alidark = document.createElement("a");
alidark.innerText = "dark mode";
alidark.href = "#";
lidark.appendChild(alidark);
ulmobil.appendChild(lidark);
alidark.onclick = clickdarkmode;
}
} catch (e) {
// Silent fail for mobile menu
}

// Initialize dark mode from cookie
let initdark = getCookie(getCookieName());
if (initdark == "on") {
clickdarkmode();
Expand Down
226 changes: 112 additions & 114 deletions assets/stylesheets/dark.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#dark {
float: right;
color: #fff;
margin-right: 8px;
margin-left: 8px;
font-weight: bold;
/* Dark mode toggle styling */
a.dark-mode-toggle {
cursor: pointer;
}

html.dark {
Expand Down Expand Up @@ -144,189 +141,190 @@ body.dark.theme-Rtmaterial tr.priority-highest td.priority {
border-color: #29B6F6;
}

body.dark.theme-Rtmaterial tr.overdue td:first-child,
body.dark.theme-Rtmaterial tr.overdue td:first-child,
body.dark.theme-Rtmaterial #my-page tr.overdue td.id {
border-left: 3px solid #29B6F6 !important;
}

/* Only follow browser dark theme preference when setting is enabled */
@media (prefers-color-scheme: dark) {
#dark {
body.follow-browser-theme:not(.dark) #dark {
display:none;
}
html {

body.follow-browser-theme:not(.dark) html {
background-color: #191919;
}
body {

body.follow-browser-theme:not(.dark) {
filter: invert(90%);
}
body:not(.theme-Rtmaterial) .icon{

body.follow-browser-theme:not(.dark):not(.theme-Rtmaterial) .icon{
filter: invert(100%);
color: #555 !important;
}
body .flyout-menu {

body.follow-browser-theme:not(.dark) .flyout-menu {
background-color: #ccc
}
body .badge,
body img.gravatar,
body .wiki img,
body img.filecontent.image,
body table.indicator.summary,
body .attachments .images img,
body canvas.chartjs-render-monitor {

body.follow-browser-theme:not(.dark) .badge,
body.follow-browser-theme:not(.dark) img.gravatar,
body.follow-browser-theme:not(.dark) .wiki img,
body.follow-browser-theme:not(.dark) img.filecontent.image,
body.follow-browser-theme:not(.dark) table.indicator.summary,
body.follow-browser-theme:not(.dark) .attachments .images img,
body.follow-browser-theme:not(.dark) canvas.chartjs-render-monitor {
filter: invert(100%);
}
body table.list tr.overdue td.due_date,
body div.issue.overdue .due-date .value {

body.follow-browser-theme:not(.dark) table.list tr.overdue td.due_date,
body.follow-browser-theme:not(.dark) div.issue.overdue .due-date .value {
filter: invert(100%);
color: lightcoral;
}
body #sidebar a.selected {

body.follow-browser-theme:not(.dark) #sidebar a.selected {
color: #000;
}
body #header,
body #top-menu,
body #project-jump .drdn-trigger {

body.follow-browser-theme:not(.dark) #header,
body.follow-browser-theme:not(.dark) #top-menu,
body.follow-browser-theme:not(.dark) #project-jump .drdn-trigger {
color: #555;
background-color: white;
}

body .diff_out,
body .diff_in {
body.follow-browser-theme:not(.dark) .diff_out,
body.follow-browser-theme:not(.dark) .diff_in {
filter: invert(1);
}
body #header a, body #top-menu a,
body #content h1, body h2, body h3, body h4, body h5, body h6 {

body.follow-browser-theme:not(.dark) #header a, body.follow-browser-theme:not(.dark) #top-menu a,
body.follow-browser-theme:not(.dark) #content h1, body.follow-browser-theme:not(.dark) h2, body.follow-browser-theme:not(.dark) h3, body.follow-browser-theme:not(.dark) h4, body.follow-browser-theme:not(.dark) h5, body.follow-browser-theme:not(.dark) h6 {
color: #555 !important;
}
body #main a.user {

body.follow-browser-theme:not(.dark) #main a.user {
color: #205D86;
}
body a.issue,
body a.issue:link,
body a.issue:visited,
body div.wiki .wiki-page,
body div.wiki .external {

body.follow-browser-theme:not(.dark) a.issue,
body.follow-browser-theme:not(.dark) a.issue:link,
body.follow-browser-theme:not(.dark) a.issue:visited,
body.follow-browser-theme:not(.dark) div.wiki .wiki-page,
body.follow-browser-theme:not(.dark) div.wiki .external {
color: #205D86;
}

body .highlight {
body.follow-browser-theme:not(.dark) .highlight {
color: #000;
}
body input[type="submit"],
body div.flash.notice,
body table.list:not(.odd-even) tbody tr:nth-child(odd):hover,
body .odd:hover,
body #issue-changesets div.changeset:nth-child(odd):hover,
body table.list:not(.odd-even) tbody tr:nth-child(even):hover,
body .even:hover,
body #issue-changesets div.changeset:nth-child(even):hover,
body #main-menu .menu-children li a:hover,
body .pagination ul.pages li.page:hover {

body.follow-browser-theme:not(.dark) input[type="submit"],
body.follow-browser-theme:not(.dark) div.flash.notice,
body.follow-browser-theme:not(.dark) table.list:not(.odd-even) tbody tr:nth-child(odd):hover,
body.follow-browser-theme:not(.dark) .odd:hover,
body.follow-browser-theme:not(.dark) #issue-changesets div.changeset:nth-child(odd):hover,
body.follow-browser-theme:not(.dark) table.list:not(.odd-even) tbody tr:nth-child(even):hover,
body.follow-browser-theme:not(.dark) .even:hover,
body.follow-browser-theme:not(.dark) #issue-changesets div.changeset:nth-child(even):hover,
body.follow-browser-theme:not(.dark) #main-menu .menu-children li a:hover,
body.follow-browser-theme:not(.dark) .pagination ul.pages li.page:hover {
background-color: darkgrey;
}
body ,
body #main-menu,
body #main-menu li a,
body #main-menu li a.selected,
body #main-menu li a:hover,
body .nodata,
body .warning,
body #errorExplanation,
body #flash_error,
body a,
body a:link,
body a:visited,
body a:hover,
body a:focus,
body div.flash.notice,
body #main-menu .menu-children li a:hover {

body.follow-browser-theme:not(.dark),
body.follow-browser-theme:not(.dark) #main-menu,
body.follow-browser-theme:not(.dark) #main-menu li a,
body.follow-browser-theme:not(.dark) #main-menu li a.selected,
body.follow-browser-theme:not(.dark) #main-menu li a:hover,
body.follow-browser-theme:not(.dark) .nodata,
body.follow-browser-theme:not(.dark) .warning,
body.follow-browser-theme:not(.dark) #errorExplanation,
body.follow-browser-theme:not(.dark) #flash_error,
body.follow-browser-theme:not(.dark) a,
body.follow-browser-theme:not(.dark) a:link,
body.follow-browser-theme:not(.dark) a:visited,
body.follow-browser-theme:not(.dark) a:hover,
body.follow-browser-theme:not(.dark) a:focus,
body.follow-browser-theme:not(.dark) div.flash.notice,
body.follow-browser-theme:not(.dark) #main-menu .menu-children li a:hover {
color: rgb(17,17,17);
}
body #main-menu,
body #main-menu li a.selected,
body #main-menu li a:hover,
body #main-menu li a.new-object {

body.follow-browser-theme:not(.dark) #main-menu,
body.follow-browser-theme:not(.dark) #main-menu li a.selected,
body.follow-browser-theme:not(.dark) #main-menu li a:hover,
body.follow-browser-theme:not(.dark) #main-menu li a.new-object {
background: white;
}
body #main-menu li a.selected,
body #content .tabs ul li a.selected,
body input[type="submit"],
body input[type="submit"]:hover,
body div.flash.notice,
body .ui-widget-header,
body #main-menu .menu-children {

body.follow-browser-theme:not(.dark) #main-menu li a.selected,
body.follow-browser-theme:not(.dark) #content .tabs ul li a.selected,
body.follow-browser-theme:not(.dark) input[type="submit"],
body.follow-browser-theme:not(.dark) input[type="submit"]:hover,
body.follow-browser-theme:not(.dark) div.flash.notice,
body.follow-browser-theme:not(.dark) .ui-widget-header,
body.follow-browser-theme:not(.dark) #main-menu .menu-children {
border-color: #78909c !important;
}

body input[type="date"] {
body.follow-browser-theme:not(.dark) input[type="date"] {
color-scheme: dark;
}

body input[type="date"]::-webkit-calendar-picker-indicator {
body.follow-browser-theme:not(.dark) input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(100%);
}

body .pagination ul.pages li:first-child {
body.follow-browser-theme:not(.dark) .pagination ul.pages li:first-child {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
body .pagination ul.pages li {

body.follow-browser-theme:not(.dark) .pagination ul.pages li {
border: 1px solid #ddd;
}
body .pagination ul.pages li.current {

body.follow-browser-theme:not(.dark) .pagination ul.pages li.current {
color: white;
background-color: #ddd ;
border-color: #ddd;
}

body select option,
body select optgroup {
body.follow-browser-theme:not(.dark) select option,
body.follow-browser-theme:not(.dark) select optgroup {
color: #ccc;
background-color: #191919;
}

body #activity .issue a,
body #activity .issue-note a,
body #activity .issue-edit a,
body #activity .issue-closed a,
body #activity .wiki-page a,
body #activity .news a,
body #activity .attachment a,
body #search-results dt a {
body.follow-browser-theme:not(.dark) #activity .issue a,
body.follow-browser-theme:not(.dark) #activity .issue-note a,
body.follow-browser-theme:not(.dark) #activity .issue-edit a,
body.follow-browser-theme:not(.dark) #activity .issue-closed a,
body.follow-browser-theme:not(.dark) #activity .wiki-page a,
body.follow-browser-theme:not(.dark) #activity .news a,
body.follow-browser-theme:not(.dark) #activity .attachment a,
body.follow-browser-theme:not(.dark) #search-results dt a {
color: #ccc;
}

body.theme-Rtmaterial tr.priority-default td.priority {
body.follow-browser-theme:not(.dark).theme-Rtmaterial tr.priority-default td.priority {
border-color: #AB47BC;
}
body.theme-Rtmaterial tr.priority-lowest td.priority {
border-color: #F57F17;

body.follow-browser-theme:not(.dark).theme-Rtmaterial tr.priority-lowest td.priority {
border-color: #F57F17;
}
body.theme-Rtmaterial tr.priority-highest td.priority {

body.follow-browser-theme:not(.dark).theme-Rtmaterial tr.priority-highest td.priority {
border-color: #29B6F6;
}
body.theme-Rtmaterial tr.overdue td:first-child,
body.theme-Rtmaterial #my-page tr.overdue td.id {

body.follow-browser-theme:not(.dark).theme-Rtmaterial tr.overdue td:first-child,
body.follow-browser-theme:not(.dark).theme-Rtmaterial #my-page tr.overdue td.id {
border-left: 3px solid #29B6F6 !important;
}
}
4 changes: 4 additions & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Settings for redmine_dark plugin
follow_browser_theme:
default: false
description: 'Automatically apply dark mode based on browser/OS dark theme preference'
4 changes: 4 additions & 0 deletions init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,8 @@ def init_redmine_dark
url 'https://github.com/fraoustin/redmine_dark'
author_url 'https://github.com/fraoustin'
requires_redmine :version_or_higher => '2.0.0'

settings :default => {
'follow_browser_theme' => false
}, :partial => 'settings/redmine_dark_settings'
end
Loading