add support for dark mode - resolves #730

Sat, 21 Feb 2026 15:27:17 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 21 Feb 2026 15:27:17 +0100
changeset 415
f0a1631eaf00
parent 414
1f1bce90127e
child 416
a01dbf277f89

add support for dark mode - resolves #730

src/main/webapp/WEB-INF/changelogs/changelog-de.jspf file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/changelogs/changelog.jspf file | annotate | diff | comparison | revisions
src/main/webapp/lightpit.css file | annotate | diff | comparison | revisions
--- a/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf	Sat Feb 21 13:41:41 2026 +0100
+++ b/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf	Sat Feb 21 15:27:17 2026 +0100
@@ -27,6 +27,7 @@
 <h3>Version 1.6.0 (Vorschau)</h3>
 
 <ul>
+    <li>Support für Dark-Mode hinzugefügt.</li>
     <li>Neues Feature zur Planung von Versionen hinzugefügt.</li>
     <li>Pop-Up hinzugefügt, das über eine neue LightPIT-Version informiert.</li>
     <li>Neue Schaltflächen zur Vorgangsansicht hinzugefügt, mit denen der Status und die Zuweisung des Vorgangs schnell geändert werden können.</li>
--- a/src/main/webapp/WEB-INF/changelogs/changelog.jspf	Sat Feb 21 13:41:41 2026 +0100
+++ b/src/main/webapp/WEB-INF/changelogs/changelog.jspf	Sat Feb 21 15:27:17 2026 +0100
@@ -27,6 +27,7 @@
 <h3>Version 1.6.0 (preview)</h3>
 
 <ul>
+    <li>Add support for dark mode.</li>
     <li>Add new version planning UI.</li>
     <li>Add popup informing about a new LightPIT release.</li>
     <li>Add convenience buttons to the issue view to quickly change the issue status and assignee.</li>
--- a/src/main/webapp/lightpit.css	Sat Feb 21 13:41:41 2026 +0100
+++ b/src/main/webapp/lightpit.css	Sat Feb 21 15:27:17 2026 +0100
@@ -27,11 +27,78 @@
  * 
  */
 
+:root {
+    --color-background: white;
+    --color-background-popup: ghostwhite;
+    --color-foreground: #1c204e;
+    --color-foreground-inverted: white;
+    --color-link: #3060f8;
+    --color-background-mainmenu: #e0e0e5;
+    --color-background-mainmenu-active: #d0d0d5;
+    --color-background-sidemenu: #f7f7ff;
+    --color-background-sidemenu-active: #e7e7ef;
+    --color-background-th: #f0f0f0;
+    --color-background-tr-even: #f7f7ff;
+    --color-border-primary: #606060;
+    --color-border-primary-fade: #d0d0d5;
+    --color-border-secondary: #c0c0c0;
+    --color-border-secondary-fade: #d3d3d3;
+    --color-button-secondary: #f0f0f0;
+    --color-button-secondary-hover: #f0f0ff;
+    --color-button-primary: #20a0ff;
+    --color-button-primary-text: white;
+    --color-button-primary-hover: #1090cf;
+    --color-background-issue-data: #f7f7f7;
+    --color-background-comment-author: #e7e7ef;
+}
+
+@media (prefers-color-scheme: dark) {
+    :root {
+        --color-background: #2c404e;
+        --color-foreground: #fefaf7;
+        --color-foreground-inverted: #1c204e;
+        --color-background-popup: #4f6778;
+        --color-link: #90e8ff;
+        --color-background-mainmenu: #3c3c49;
+        --color-background-mainmenu-active: #5c5c69;
+        --color-background-sidemenu: #5a5a80;
+        --color-background-sidemenu-active: #7a7aa0;
+        --color-background-th: #595970;
+        --color-background-tr-even: #3c505e;
+        --color-border-primary: #ececec;
+        --color-border-primary-fade: #a9a9a9;
+        --color-border-secondary: #d0d0d0;
+        --color-border-secondary-fade: #959595;
+        --color-button-secondary: #595970;
+        --color-button-secondary-hover: #656585;
+        --color-button-primary: #20a0ff;
+        --color-button-primary-text: white;
+        --color-button-primary-hover: #1090cf;
+        --color-background-issue-data: #4c606e;
+        --color-background-comment-author: #7a7aa0;
+    }
+}
+
+.light-text {
+    color: white;
+}
+
+.dark-text {
+    color: #1c204e;
+}
+
+input, select, textarea {
+    background: var(--color-background);
+    color: var(--color-foreground);
+    border: var(--color-border-primary) solid thin;
+    border-radius: 2pt;
+}
+
 html {
     font-family: sans-serif;
     font-size: 11pt;
-    background: white;
-    color: #1c204e;
+    background: var(--color-background);
+    color: var(--color-foreground);
     margin: 0;
     padding: 0;
     height: 100vh;
@@ -51,14 +118,6 @@
     margin: 0.25em 0;
 }
 
-.light-text {
-    color: white;
-}
-
-.dark-text {
-    color: #1c204e;
-}
-
 .edit-icon {
     margin-left: 1ex;
     margin-right: 1ex;
@@ -85,7 +144,7 @@
 
 a {
     cursor: pointer;
-    color: #3060f8;
+    color: var(--color-link);
     text-decoration: none;
 }
 
@@ -104,11 +163,11 @@
 #mainMenu {
     display: flex;
     flex-flow: row nowrap;
-    border-image-source: linear-gradient(to right, #606060, rgba(60, 60, 60, .25));
+    border-image-source: linear-gradient(to right, var(--color-border-primary), var(--color-border-primary-fade));
     border-image-slice: 1;
     border-bottom-style: solid;
     border-bottom-width: thin;
-    background: #e0e0e5;
+    background: var(--color-background-mainmenu);
 }
 
 #sideMenu {
@@ -116,12 +175,12 @@
     width: 15vw;
     display: flex;
     flex-flow: column;
-    color: #3060f8;
-    border-image-source: linear-gradient(to bottom, #606060, rgba(60, 60, 60, .25));
+    color: var(--color-link);
+    border-image-source: linear-gradient(to bottom, var(--color-border-primary), var(--color-border-primary-fade));
     border-image-slice: 1;
     border-right-style: solid;
     border-right-width: thin;
-    background: #f7f7ff;
+    background: var(--color-background-sidemenu);
 }
 
 #mainMenu .menuEntry {
@@ -158,11 +217,11 @@
 }
 
 #mainMenu .menuEntry[data-active] {
-    background: #d0d0d5;
+    background: var(--color-background-mainmenu-active);
 }
 
 #sideMenu .menuEntry[data-active] {
-    background: #e7e7ef
+    background: var(--color-background-sidemenu-active);
 }
 
 #sideMenu .level-0 {
@@ -183,13 +242,13 @@
 }
 
 #whats-new {
-    background: ghostwhite;
+    background: var(--color-background-popup);
     position: fixed;
     top: 10%;
     left: 50%;
     transform: translate(-50%, 0);
     padding: 1.5em;
-    border: #1c204e solid 2px;
+    border: var(--color-foreground) solid 2px;
     border-radius: 4px;
 }
 
@@ -202,9 +261,9 @@
     font-size: medium;
     border-style: solid;
     border-width: thin;
-    border-color: #606060;
+    border-color: var(--color-border-primary);
     color: inherit;
-    background: #f0f0f0;
+    background: var(--color-button-secondary);
 
     padding: .25em .5em .25em .5em;
     cursor: default;
@@ -214,21 +273,16 @@
 }
 
 button:hover, a.button:hover {
-    background: #f0f0ff;
-}
-
-button[data-toggle], a.button[data-toggle] {
-    border-color: #1040a0;
-    background: #d0d0d5;
+    background: var(--color-button-secondary-hover);
 }
 
 button[type=submit], a.button.submit {
-    background: #20a0ff;
-    color: white;
+    background: var(--color-button-primary);
+    color: var(--color-button-primary-text);
 }
 
 button[type=submit]:hover, a.button.submit:hover {
-    background: #1090cf;
+    background: var(--color-button-primary-hover);
 }
 
 th {
@@ -238,25 +292,25 @@
 table.datatable {
     border-style: solid;
     border-width: thin;
-    border-color: silver;
+    border-color: var(--color-border-secondary);
     border-collapse: collapse;
 }
 
 table.datatable th {
     white-space: nowrap;
     font-weight: bold;
-    background: #f7f7ff;
+    background: var(--color-background-th);
 }
 
 table.datatable th, table.datatable td {
     border-style: solid;
     border-width: thin;
-    border-color: lightgray;
+    border-color: var(--color-border-secondary-fade);
     padding: .4em;
 }
 
 table.datatable tr:nth-child(2n) {
-    background: #faffff;
+    background: var(--color-background-tr-even);
 }
 
 table.formtable {
@@ -322,7 +376,7 @@
     margin-top: 1.5em;
 }
 
-.info-box, .error-box, .warn-box {
+.info-box, .error-box {
     margin: 1.5em;
     border-style: dashed;
     border-width: thin;
@@ -336,12 +390,6 @@
     background: lightcoral;
 }
 
-.warn-box {
-    border-style: outset;
-    border-color: gold;
-    background: lightgoldenrodyellow;
-}
-
 .table {
     display: table;
     border-spacing: .5em;
@@ -478,7 +526,7 @@
     box-sizing: border-box;
     border-style: solid;
     border-width: thin;
-    border-color: silver;
+    border-color: var(--color-border-secondary);
     border-radius: 4pt;
     background: darkgray;
     text-align: center;
@@ -549,7 +597,7 @@
 }
 
 hr.issue-view-separator {
-    border-image-source: linear-gradient(to right, rgba(60, 60, 60, .1), rgba(96, 96, 96, 1), rgba(60, 60, 60, .1));
+    border-image-source: linear-gradient(to right, var(--color-border-primary-fade), var(--color-border-primary), var(--color-border-primary-fade));
     border-image-slice: 1;
     border-width: thin;
     border-style: none;
@@ -562,8 +610,8 @@
 }
 
 .comment-author {
-    color: #3060f8;
-    background: #e7e7ef;
+    color: var(--color-link);
+    background: var(--color-background-comment-author);
     margin-left: -.25rem;
     padding: .25rem;
 }
@@ -588,7 +636,7 @@
 div.mde-preview {
     border-style: solid;
     border-width: 2px;
-    border-color: silver;
+    border-color: var(--color-border-secondary);
     padding: .25em;
     border-radius: 8px;
 }
@@ -603,8 +651,8 @@
 }
 
 table.issue-view td, table.issue-view th {
-    background: #f7f7f7;
-    border: solid silver 1pt;
+    background: var(--color-background-issue-data);
+    border: solid var(--color-border-secondary) 1pt;
     padding: .5em;
 }
 

mercurial