diff --git a/gradle/changelog/introduce_darkmode.yaml b/gradle/changelog/introduce_darkmode.yaml new file mode 100644 index 0000000000..5f07fad7d9 --- /dev/null +++ b/gradle/changelog/introduce_darkmode.yaml @@ -0,0 +1,4 @@ +- type: added + description: Introduce darkmode theme ([#1969](https://github.com/scm-manager/scm-manager/pull/1969)) +- type: changed + description: Default theme is selected according to system defaults ([#1969](https://github.com/scm-manager/scm-manager/pull/1969)) diff --git a/scm-ui/ui-components/.storybook/preview.js b/scm-ui/ui-components/.storybook/preview.js index 34b830a079..a92350ca98 100644 --- a/scm-ui/ui-components/.storybook/preview.js +++ b/scm-ui/ui-components/.storybook/preview.js @@ -87,7 +87,8 @@ export const parameters = { default: "light", list: [ { name: "light", color: "#fff" }, - { name: "highcontrast", color: "#000" }, + { name: "highcontrast", color: "#050514" }, + { name: "dark", color: "#121212" }, ], }, options: { diff --git a/scm-ui/ui-components/src/DangerZone.tsx b/scm-ui/ui-components/src/DangerZone.tsx index c57dcb2697..55a65b112c 100644 --- a/scm-ui/ui-components/src/DangerZone.tsx +++ b/scm-ui/ui-components/src/DangerZone.tsx @@ -41,10 +41,9 @@ export const DangerZone = styled.div` } } - // TODO ersetzen? > *:not(:last-child) { padding-bottom: 1.5rem; - border-bottom: solid 2px whitesmoke; + border-bottom: solid 2px var(--scm-border-color); } @media screen and (max-width: ${devices.tablet.width}px) { .button { diff --git a/scm-ui/ui-components/src/SyntaxHighlighter.tsx b/scm-ui/ui-components/src/SyntaxHighlighter.tsx index 7ee9f6026d..4068f08cee 100644 --- a/scm-ui/ui-components/src/SyntaxHighlighter.tsx +++ b/scm-ui/ui-components/src/SyntaxHighlighter.tsx @@ -34,10 +34,12 @@ import useScrollToElement from "./useScrollToElement"; import styled from "styled-components"; import { useTranslation } from "react-i18next"; import copyToClipboard from "./CopyToClipboard"; +import { Button } from "./buttons"; const LINE_NUMBER_URL_HASH_REGEX = /^#line-(.*)$/; -const TopRightButton = styled.button` +const TopRightButton = styled(Button)` + height: inherit; position: absolute; display: none; top: 0; @@ -90,7 +92,6 @@ const SyntaxHighlighter: FC = ({ language = defaultLanguage, showLineNumb if (value && value.length > 1 && value.endsWith("\n")) { valueWithoutTrailingLineBreak = value.substr(0, value.length - 1); } - return ( = ({ language = defaultLanguage, showLineNumb > {valueWithoutTrailingLineBreak} - + diff --git a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap index c13f279dbf..80fc739d54 100644 --- a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap +++ b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap @@ -891,7 +891,7 @@ exports[`Storyshots Buttons/CreateButton Default 1`] = ` className="indexstories__Spacing-bpoict-0 ieMGHp" >
@@ -1132,6 +1134,7 @@

Success

Warning

Danger

+

Default

@@ -1152,6 +1155,7 @@

Success

Warning

Danger

+

Default

@@ -1176,6 +1180,7 @@

Success

Warning

Danger

+

Default

@@ -1197,6 +1202,7 @@

Success

Warning

Danger

+

Default

@@ -1362,7 +1368,7 @@
-
+
@@ -1699,7 +1705,6 @@ @@ -1717,7 +1722,6 @@ @@ -1738,7 +1742,6 @@ @@ -1753,15 +1756,15 @@ -
+
-
+
- @@ -1781,7 +1784,6 @@ @@ -1812,7 +1814,7 @@
-
-
-
+
+
1.1.0-SNAPSHOT
-
-
+
+
2.6.0
  • mmuster
  • belefant
  • aschultz
  • zgummi
  • nobody
  • diff --git a/scm-ui/ui-styles/src/components/_main.scss b/scm-ui/ui-styles/src/components/_main.scss index a795ebf7fd..fad58dbac5 100644 --- a/scm-ui/ui-styles/src/components/_main.scss +++ b/scm-ui/ui-styles/src/components/_main.scss @@ -21,6 +21,30 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +:root { + --scm-white-color: #{$white}; + --scm-light-color: #{$light}; + --scm-dark-color: #{$dark}; + --scm-primary-color: #{$primary}; + --scm-link-color: #{$link}; + --scm-info-color: #{$info}; + --scm-success-color: #{$success}; + --scm-warning-color: #{$warning}; + --scm-danger-color: #{$danger}; + + --scm-secondary-least-color: #{$secondary-least}; + --scm-secondary-less-color: #{$secondary-less}; + --scm-secondary-color: #{$secondary}; + --scm-secondary-more-color: #{$secondary-more}; + --scm-secondary-most-color: #{$secondary-most}; + + --scm-border-color: #{$border}; + --scm-border: #{$border-width} solid #{$border}; + + --scm-popover-border-color: #{$white}; +} + // TODO split into multiple files .is-ellipsis-overflow { @@ -84,15 +108,6 @@ hr.header-with-actions { } } -footer.footer { - background-color: $white-ter; - padding: inherit; - - a { - color: darken($info, 15%); - } -} - .has-hover-background-blue:hover { background-color: scale-color($blue, $alpha: -90%); } @@ -113,6 +128,61 @@ footer.footer { background-color: $blue-light; } +.has-text-secondary-least { + color: $secondary-least !important; +} +a.has-text-secondary-least:hover, +a.has-text-secondary-least:focus { + color: lighten($secondary-least, 10%) !important; +} +.has-background-secondary-least { + background-color: $secondary-least !important; +} + +.has-text-secondary-less { + color: $secondary-less !important; +} +a.has-text-secondary-less:hover, +a.has-text-secondary-less:focus { + color: lighten($secondary-less, 10%) !important; +} +.has-background-secondary-less { + background-color: $secondary-less !important; +} + +.has-text-secondary { + color: $secondary !important; +} +a.has-text-secondary:hover, +a.has-text-secondary:focus { + color: lighten($secondary, 10%) !important; +} +.has-background-secondary { + background-color: $secondary !important; +} + +.has-text-secondary-more { + color: $secondary-more !important; +} +a.has-text-secondary-more:hover, +a.has-text-secondary-more:focus { + color: lighten($secondary-more, 10%) !important; +} +.has-background-secondary-more { + background-color: $secondary-more !important; +} + +.has-text-secondary-most { + color: $secondary-most !important; +} +a.has-text-secondary-most:hover, +a.has-text-secondary-most:focus { + color: lighten($secondary-most, 10%) !important; +} +.has-background-secondary-most { + background-color: $secondary-most !important; +} + // border and background colors .has-background-dark-75 { background-color: $dark-75; @@ -181,7 +251,7 @@ footer.footer { // tags .tag:not(body) { border: 1px solid transparent; - background-color: $white; + background-color: $scheme-main; &.is-delete { background-color: $light; @@ -193,7 +263,7 @@ footer.footer { } &.is-outlined { - background-color: $white; + background-color: $scheme-main; } &.is-black.is-outlined { color: $black; @@ -237,6 +307,13 @@ footer.footer { } } +.popover { + &:before { + border-bottom-color: $popover-background-color; + border-left-color: $popover-background-color; + } +} + // buttons .button { padding-left: 1.5em; @@ -251,7 +328,7 @@ footer.footer { &.is-warning, &.is-danger { &.is-outlined { - background-color: $white; + background-color: inherit; } } @@ -347,8 +424,14 @@ footer.footer { } } -.notifications .dropdown-menu:before { - border: 0.4rem solid transparent; +.notifications .dropdown-menu { + border: 1px solid $border; + + &:before { + border: 0.4rem solid transparent; + border-bottom-color: $border; + border-left-color: $border; + } } @import "~@fortawesome/fontawesome-free/scss/fontawesome"; @@ -480,7 +563,7 @@ ul.is-separated { tr { a { - color: #363636; + color: $grey-darker; } &.border-is-green td:first-child { border-left-color: $green; @@ -510,7 +593,7 @@ ul.is-separated { &:hover { td { - background-color: whitesmoke; + background-color: $white-ter; &.is-darker { background-color: #e1e1e1; @@ -531,15 +614,15 @@ ul.is-separated { } td { padding: 1em 1.25em; - background-color: #fafafa; - border-bottom: 1px solid whitesmoke; + background-color: $white-bis; + border-bottom: 1px solid $white-ter; border-left-color: $grey; &:first-child { border-left: 3px solid; } &.is-darker { - background-color: whitesmoke; + background-color: $white-ter; } // Explicitly "remove" styles from td element to use it as an empty table column header, which is necessary for // a11y because an empty th element is not allowed. @@ -550,7 +633,7 @@ ul.is-separated { } } &.is-hoverable tbody tr:not(.is-selected):hover { - background-color: whitesmoke; + background-color: $white-ter; } thead th { background-color: transparent; @@ -579,8 +662,8 @@ ul.is-separated { } .panel-footer { - background-color: whitesmoke; - color: #363636; + background-color: $panel-heading-background-color; + color: $panel-heading-color; font-size: 1.25em; font-weight: 300; line-height: 1.25; @@ -667,7 +750,7 @@ form .field:not(.is-grouped) { .tabs.is-toggle li.is-active a:hover { background-color: #28b1e8; border-color: #28b1e8; - color: #fff; + color: $white; } } @@ -678,7 +761,7 @@ form .field:not(.is-grouped) { position: absolute; right: 0; top: 0; - background-color: whitesmoke; + background-color: $white-ter; } // menu @@ -692,7 +775,6 @@ form .field:not(.is-grouped) { display: flex; height: 3.2rem; align-items: center; - color: #fff; font-size: 1em; font-weight: 600; background-color: $blue; @@ -707,12 +789,11 @@ form .field:not(.is-grouped) { } .menu-list { a { - color: #333; padding: 1rem; &.is-active { - color: $info; - background-color: #fff; + color: $link; + background-color: $scheme-main; } } diff --git a/scm-ui/ui-styles/src/dark.scss b/scm-ui/ui-styles/src/dark.scss new file mode 100644 index 0000000000..561b505f53 --- /dev/null +++ b/scm-ui/ui-styles/src/dark.scss @@ -0,0 +1,308 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@import "utils/_pre.scss"; + +$turquoise: #55abad; +$blue: #599dad; +$cyan: $blue; +$green: #419374; +$yellow: #ccad5e; +$red: #ae4e6b; +$white: $grey-lighter; +$light: $grey-dark; + +$primary-invert: $white; +$link-invert: $white; +$info-invert: $white; +$success-invert: $white; +$warning-invert: #583708; +$danger-invert: $white; +$light-invert: $white; +$dark-invert: $white; + +$scheme-main: #121212; +$background: $grey-dark; + +$border: $grey-dark; +$border-width: 1px; + +$text: $grey-lighter; +$text-strong: $grey-lighter; + +$code: lighten($red, 10%); +$code-background: lighten($scheme-main, 10%); + +$link-hover: $grey; +$link-focus: $grey; +$link-active: $grey; + +$secondary-least: $scheme-main; +$secondary-less: $black-ter; +$secondary: $grey; +$secondary-more: $grey-light; +$secondary-most: $white-ter; + +// layout +$footer-background-color: $black-ter; +$footer-color: $text; + +// element +$box-background-color: lighten($scheme-main, 2.5%); + +$button-hover-color: lighten($text-strong, 2.5%); +$button-active-color: lighten($text-strong, 2.5%); + +// component +$card-background-color: $box-background-color; + +$menu-label-color: $text; +$menu-item-color: $text; +$menu-item-hover-background-color: $grey-dark; + +$modal-card-head-background-color: $black-ter; +$modal-card-body-background-color: #17181c; + +$navbar-item-color: $grey-lighter; +$navbar-item-hover-color: $navbar-item-color; +$navbar-item-active-color: $navbar-item-color; + +$panel-heading-background-color: $black-ter; + +// form +$input-placeholder-color: $grey-light; +$input-disabled-color: #7A7A7A; + +// extension +$popover-background-color: $grey-dark; +$popover-border-color: $grey-dark; + +$table-row-hover-background-color: $grey-darker; + +@import "utils/_post.scss"; + +:root { + --scm-popover-border-color: #{$popover-border-color}; +} + +$dark-75: scale-color($dark, $lightness: -25%); +$dark-50: scale-color($dark, $lightness: -50%); +$dark-25: scale-color($dark, $lightness: -75%); +$info-75: scale-color($info, $lightness: -25%); +$info-50: scale-color($info, $lightness: -50%); +$info-25: scale-color($info, $lightness: -75%); +$link-75: scale-color($link, $lightness: -25%); +$link-50: scale-color($link, $lightness: -50%); +$link-25: scale-color($link, $lightness: -75%); +$primary-75: scale-color($primary, $lightness: -25%); +$primary-50: scale-color($primary, $lightness: -50%); +$primary-25: scale-color($primary, $lightness: -75%); +$success-75: scale-color($success, $lightness: -25%); +$success-50: scale-color($success, $lightness: -50%); +$success-25: scale-color($success, $lightness: -75%); +$warning-75: scale-color($warning, $lightness: -25%); +$warning-50: scale-color($warning, $lightness: -50%); +$warning-25: scale-color($warning, $lightness: -75%); +$danger-75: scale-color($danger, $lightness: -25%); +$danger-50: scale-color($danger, $lightness: -50%); +$danger-25: scale-color($danger, $lightness: -75%); + +.has-background-dark-75 { + background-color: $dark-75; +} +.has-background-dark-50 { + background-color: $dark-50; +} +.has-background-dark-25 { + background-color: $dark-25; +} +.has-background-info-75 { + background-color: $info-75; +} +.has-background-info-50 { + background-color: $info-50; +} +.has-background-info-25 { + background-color: $info-25; +} +.has-background-link-75 { + background-color: $link-75; +} +.has-background-link-50 { + background-color: $link-50; +} +.has-background-link-25 { + background-color: $link-25; +} +.has-background-primary-75 { + background-color: $primary-75; +} +.has-background-primary-50 { + background-color: $primary-50; +} +.has-background-primary-25 { + background-color: $primary-25; +} +.has-background-success-75 { + background-color: $success-75; +} +.has-background-success-50 { + background-color: $success-50; +} +.has-background-success-25 { + background-color: $success-25; +} +.has-background-warning-75 { + background-color: $warning-75; +} +.has-background-warning-50 { + background-color: $warning-50; +} +.has-background-warning-25 { + background-color: $warning-25; +} +.has-background-danger-75 { + background-color: $danger-75; +} +.has-background-danger-50 { + background-color: $danger-50; +} +.has-background-danger-25 { + background-color: $danger-25; +} + +:root { + --scm-secondary-background: #{$scheme-main}; + --scm-secondary-text: #{$white}; + --scm-border: 2px solid #{$white-ter}; + --scm-hover-color: #{$grey}; + --scm-column-selection: #{$link-dark}; + + --sh-base-color: #{$white}; + --sh-font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; + --sh-block-background: #{$scheme-main}; + --sh-inline-code-color: #ff3860; + --sh-inline-code-background: #fbe7eb; + --sh-comment-color: #9a9a9a; + --sh-punctuation-color: #999999; + --sh-property-color: #2c99c7; + --sh-selector-color: #009dff; + --sh-operator-color: #999999; + --sh-operator-bg: inherit; + --sh-variable-color: #c386ca; + --sh-function-color: #ff6181; + --sh-keyword-color: #00a984; + --sh-selected-color: #{$warning-dark}; + --sh-highlight-background: #f5f5f5; + --sh-highlight-accent: #99d8f3; + + --diff-background-color: #{$scheme-main}; + --diff-text-color: #{$white-bis}; + --diff-font-family: Consolas, Courier, monospace; + --diff-selection-background-color: #{desaturate(#b3d7ff, 20%)}; + --diff-gutter-insert-background-color: #{desaturate(#05c71d, 20%)}; + --diff-gutter-delete-background-color: #{desaturate(#eb7a85, 20%)}; + --diff-gutter-selected-background-color: #{desaturate(#fffce0, 20%)}; + --diff-code-insert-background-color: #{desaturate(#05240b, 20%)}; + --diff-code-delete-background-color: #{desaturate(#230608, 20%)}; + --diff-code-insert-edit-background-color: #{desaturate(#c0dc91, 20%)}; + --diff-code-delete-edit-background-color: #{desaturate(#000, 20%)}; + --diff-code-selected-background-color: #{desaturate(#fffce0, 20%)}; + --diff-omit-gutter-line-color: #cb2a1d; +} + +.menu-list { + a { + > li { + border-color: $grey-light; + } + li:last-child { + border-color: $grey-light; + } + } +} + +//popover +.popover { + border: 1px solid $popover-border-color; +} + +.modal-card { + border: 1px solid $border; + + & .modal-close, + & .delete { + background-color: $background; + } +} + +.card-table { + tr { + a { + color: $grey-light; + } + + &:hover { + td { + background-color: $grey-darker; + + &.is-darker { + background-color: $black-ter; + } + } + } + } + td { + background-color: $black-ter; + border-bottom: none; + + &.is-darker { + background-color: $grey-dark; + } + } + &.is-hoverable tbody tr:not(.is-selected):hover { + background-color: $grey-darker; + } +} + +.diff-code-conflict { + background-color: #332900; +} + +.diff-gutter-conflict { + background-color: #bc9f2a; +} + +.diff-decoration-content div { + color: $scheme-main; +} + +//Display darker version of background image +.has-scm-background { + background-image: url(images/scmManagerHeroDark.jpg) !important; +} + +.has-hover-visible:hover { + color: $grey !important; +} diff --git a/scm-ui/ui-styles/src/highcontrast.scss b/scm-ui/ui-styles/src/highcontrast.scss index 88db29ca82..94fd4356c9 100644 --- a/scm-ui/ui-styles/src/highcontrast.scss +++ b/scm-ui/ui-styles/src/highcontrast.scss @@ -24,14 +24,20 @@ @import "utils/_pre.scss"; -// $text: $white; +$red: #e63453; + $scheme-main: #050514; $background: $grey-dark; $text: $white-ter; $text-strong: $white-bis; -$danger: #e63453; -$code: lighten($danger, 25%); +$secondary-least: $scheme-main; +$secondary-less: $black-ter; +$secondary: $white-bis; +$secondary-more: $white-ter; +$secondary-most: $white; + +$code: lighten($red, 25%); $primary-invert: #050514; $info-invert: #050514; $link-invert: #050514; @@ -41,7 +47,7 @@ $danger-invert: #050514; $light-gray: #f2f2f2; -$footer-background-color: $grey-dark; +$footer-background-color: $black-ter; $footer-color: $white-ter; //make horizontal lines pop more @@ -50,6 +56,11 @@ $hr-background-color: $white-bis; $box-background-color: scale-color($scheme-main, $lightness: 15%); $box-background-color: $grey-darker; +$menu-label-color: $scheme-main; +$menu-item-color: $white-ter; + +$panel-heading-background-color: $black-ter; + $modal-card-head-background-color: $black-ter; $modal-card-body-background-color: $scheme-main; @@ -64,13 +75,14 @@ $tooltip-background-color: $white-bis; $tooltip-background-opacity: 0.9 !default; $tooltip-color: $scheme-main; +$border-width: 2px; +$border: $white-ter; + @import "utils/_post.scss"; :root { --scm-secondary-background: #{$scheme-main}; --scm-secondary-text: #{$white}; - --scm-border: 2px solid #{$white-ter}; - --scm-info-color: #{$info}; --scm-hover-color: #{$grey}; --scm-column-selection: #{$link-dark}; @@ -108,17 +120,6 @@ $tooltip-color: $scheme-main; } .button { - &.is-primary, - &.is-info, - &.is-link, - &.is-success, - &.is-warning, - &.is-danger { - &.is-outlined { - background-color: inherit; - } - } - &.is-primary:hover, &.is-primary.is-hovered { background-color: scale-color($primary, $lightness: -5%); @@ -205,36 +206,21 @@ $tooltip-color: $scheme-main; } } -.menu-label { - color: $scheme-main; -} - -.menu-list { - a { - color: $white-ter; - - &.is-active { - background-color: $scheme-main; - } - } -} - //footer is overwritten in _main.scss footer.footer { - background-color: $black-ter; a { color: scale-color($link, $lightness: 25%); } } .card { - border: 1px solid $white-ter; + border: 1px solid $border; box-shadow: none; } //card .modal-card { - border: 1px solid $white-ter; + border: 1px solid $border; & .modal-close, & .delete { @@ -257,9 +243,6 @@ footer.footer { background-color: $grey-darker; } } - a { - color: $link; - } } } td { @@ -278,18 +261,8 @@ footer.footer { } } -// panels .panel { border-color: $white-bis; - - .panel-heading { - background-color: $black-ter; - } - - .panel-footer { - background-color: $black-ter; - color: $white-bis; - } } //diffs @@ -338,9 +311,6 @@ td:first-child.diff-gutter-conflict:before { //inline member tags .tag:not(body) { - border: 1px solid transparent; - background-color: $white; - &.is-delete { &::before, &::after { @@ -363,11 +333,6 @@ td:first-child.diff-gutter-conflict:before { &.is-light .has-text-link { color: scale-color($link, $lightness: -50%) !important; } - - //outline-tags - &.is-outlined { - background-color: $scheme-main; - } } //cards receive white border @@ -376,21 +341,7 @@ td:first-child.diff-gutter-conflict:before { } .popover { - border: 1px solid $white-ter; - - &:before { - border-bottom-color: $grey-dark; - border-left-color: $grey-dark; - } -} - -.notifications .dropdown-menu { - border: 1px solid $white-ter; - - &:before { - border-bottom-color: $white-ter; - border-left-color: $white-ter; - } + border: 1px solid $border; } //Display darker version of background image @@ -398,61 +349,6 @@ td:first-child.diff-gutter-conflict:before { background-image: url(images/scmManagerHeroDark.jpg) !important; } -.has-text-secondary-least { - color: $scheme-main !important; -} -a.has-text-secondary-least:hover, -a.has-text-secondary-least:focus { - color: lighten($scheme-main, 10%) !important; -} -.has-background-secondary-least { - background-color: $scheme-main !important; -} - -.has-text-secondary-less { - color: $black-ter !important; -} -a.has-text-secondary-less:hover, -a.has-text-secondary-less:focus { - color: lighten($black-ter, 10%) !important; -} -.has-background-secondary-less { - background-color: $black-ter !important; -} - -.has-text-secondary { - color: $white-bis !important; -} -a.has-text-secondary:hover, -a.has-text-secondary:focus { - color: lighten($white-bis, 10%) !important; -} -.has-background-secondary { - background-color: $white-bis !important; -} - -.has-text-secondary-more { - color: $white-ter !important; -} -a.has-text-secondary-more:hover, -a.has-text-secondary-more:focus { - color: lighten($white-ter, 10%) !important; -} -.has-background-secondary-more { - background-color: $white-ter !important; -} - -.has-text-secondary-most { - color: $white !important; -} -a.has-text-secondary-most:hover, -a.has-text-secondary-most:focus { - color: lighten($white, 10%) !important; -} -.has-background-secondary-most { - background-color: $white !important; -} - .has-background-light { color: $grey-dark; } @@ -461,15 +357,8 @@ a.has-text-secondary-most:focus { color: $white-bis !important; } -[disabled].textarea::placeholder, -[disabled].input::placeholder, -fieldset[disabled] .textarea::placeholder, -fieldset[disabled] .input::placeholder { - color: $white-bis; -} - .repository-export-info-box { - background-color: $high-contrast-info-25; + background-color: scale-color($info, $lightness: -75%); border: 0.2rem solid; } diff --git a/scm-ui/ui-styles/src/light.scss b/scm-ui/ui-styles/src/light.scss index 68766ba5dd..84b79a14de 100644 --- a/scm-ui/ui-styles/src/light.scss +++ b/scm-ui/ui-styles/src/light.scss @@ -23,18 +23,38 @@ */ @import "utils/_pre.scss"; -// colors defined in variables/commons.scss -$subtitle-color: #666; + $warning-invert: #88550d; + +$border: $grey-lighter; +$border-width: 1px; + +$secondary-least: $white; +$secondary-less: $white-ter; +$secondary: $grey-light; +$secondary-more: $grey-darker; +$secondary-most: $black; + +// layout +$footer-background-color: $white-ter; + +// element $button-disabled-opacity: 0.25; +$subtitle-color: #666; + +// component +$menu-label-color: $white; +$menu-item-color: #333; + +// extension +$popover-background-color: $grey-light; + @import "utils/_post.scss"; :root { --scm-secondary-background: #{$white}; --scm-secondary-text: #{$black}; - --scm-border: 1px solid #dbdbdb; - --scm-info-color: #{$info}; --scm-hover-color: #{$black-ter}; --scm-column-selection: #{$link-25}; @@ -57,72 +77,31 @@ $button-disabled-opacity: 0.25; --sh-highlight-accent: #99d8f3; } +.button { + &.is-primary, + &.is-info, + &.is-link, + &.is-success, + &.is-warning, + &.is-danger { + &.is-outlined { + background-color: $white; + } + } +} + +footer.footer { + a { + color: darken($info, 15%); + } +} + .popover:before { border-bottom-color: white; border-left-color: white; box-shadow: -1px 1px 2px rgba(10, 10, 10, 0.2); } -.notifications .dropdown-menu:before { - border-bottom-color: white; - border-left-color: white; -} - -.has-text-secondary-least { - color: $white !important; -} -a.has-text-secondary-least:hover, -a.has-text-secondary-least:focus { - color: lighten($white, 10%) !important; -} -.has-background-secondary-least { - background-color: $white !important; -} - -.has-text-secondary-less { - color: $white-ter !important; -} -a.has-text-secondary-less:hover, -a.has-text-secondary-less:focus { - color: lighten($white-ter, 10%) !important; -} -.has-background-secondary-less { - background-color: $white-ter !important; -} - -.has-text-secondary { - color: $grey-light !important; -} -a.has-text-secondary:hover, -a.has-text-secondary:focus { - color: lighten($grey-light, 10%) !important; -} -.has-background-secondary { - background-color: $grey-light !important; -} - -.has-text-secondary-more { - color: $grey-darker !important; -} -a.has-text-secondary-more:hover, -a.has-text-secondary-more:focus { - color: lighten($grey-darker, 10%) !important; -} -.has-background-secondary-more { - background-color: $grey-darker !important; -} - -.has-text-secondary-most { - color: $black !important; -} -a.has-text-secondary-most:hover, -a.has-text-secondary-most:focus { - color: lighten($black, 10%) !important; -} -.has-background-secondary-most { - background-color: $black !important; -} - .has-hover-visible:hover { color: $grey-darker !important; } diff --git a/scm-ui/ui-styles/src/variables/_commons.scss b/scm-ui/ui-styles/src/variables/_commons.scss index 8b4f156d4b..74c2d8b48f 100644 --- a/scm-ui/ui-styles/src/variables/_commons.scss +++ b/scm-ui/ui-styles/src/variables/_commons.scss @@ -21,16 +21,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -//$link: #007EB0; -$info: #33b2e8; + $turquoise: #00d1df; $blue: #33b2e8; $cyan: $blue; $green: #00c79b; -$warning: #ffdd57; +$yellow: #ffdd57; +$red: #ff3860; + $blue-light: #98d8f3; -$danger: #ff3860; $family-monospace: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; $input-border-color: $blue-light; + +$navbar-background-color: transparent; +$navbar-item-color: $white; +$navbar-item-hover-color: $navbar-item-color; +$navbar-item-active-color: $navbar-item-color; +$navbar-item-hover-background-color: rgba(10, 10, 10, 0.1); + +$footer-padding: inherit; + +$popover-border-color: $white; diff --git a/scm-ui/ui-styles/src/variables/_derived.scss b/scm-ui/ui-styles/src/variables/_derived.scss index d730e9d3b5..cc7d66d8a1 100644 --- a/scm-ui/ui-styles/src/variables/_derived.scss +++ b/scm-ui/ui-styles/src/variables/_derived.scss @@ -43,24 +43,3 @@ $danger-75: scale-color($danger, $lightness: 25%); $danger-50: scale-color($danger, $lightness: 50%); $danger-25: scale-color($danger, $lightness: 75%); -$high-contrast-dark-75: scale-color($dark, $lightness: -25%); -$high-contrast-dark-50: scale-color($dark, $lightness: -50%); -$high-contrast-dark-25: scale-color($dark, $lightness: -75%); -$high-contrast-info-75: scale-color($info, $lightness: -25%); -$high-contrast-info-50: scale-color($info, $lightness: -50%); -$high-contrast-info-25: scale-color($info, $lightness: -75%); -$high-contrast-link-75: scale-color($link, $lightness: -25%); -$high-contrast-link-50: scale-color($link, $lightness: -50%); -$high-contrast-link-25: scale-color($link, $lightness: -75%); -$high-contrast-primary-75: scale-color($primary, $lightness: -25%); -$high-contrast-primary-25: scale-color($primary, $lightness: -75%); -$high-contrast-primary-50: scale-color($primary, $lightness: -50%); -$high-contrast-success-75: scale-color($success, $lightness: -25%); -$high-contrast-success-50: scale-color($success, $lightness: -50%); -$high-contrast-success-25: scale-color($success, $lightness: -75%); -$high-contrast-warning-75: scale-color($warning, $lightness: -25%); -$high-contrast-warning-50: scale-color($warning, $lightness: -50%); -$high-contrast-warning-25: scale-color($warning, $lightness: -75%); -$high-contrast-danger-75: scale-color($danger, $lightness: -25%); -$high-contrast-danger-50: scale-color($danger, $lightness: -50%); -$high-contrast-danger-25: scale-color($danger, $lightness: -75%); diff --git a/scm-ui/ui-webapp/public/images/blibSmallLightBackground.svg b/scm-ui/ui-webapp/public/images/blibSmallLightBackground.svg new file mode 100644 index 0000000000..35b8e4dfb8 --- /dev/null +++ b/scm-ui/ui-webapp/public/images/blibSmallLightBackground.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scm-ui/ui-webapp/public/index.mustache b/scm-ui/ui-webapp/public/index.mustache index 6926c8c4ce..6733576363 100644 --- a/scm-ui/ui-webapp/public/index.mustache +++ b/scm-ui/ui-webapp/public/index.mustache @@ -29,10 +29,18 @@ linkElement.rel = 'stylesheet'; linkElement.type = 'text/css'; var theme = localStorage.getItem('scm.theme'); - if (theme === 'highcontrast') { + if (theme === 'light') { + linkElement.href = "{{ contextPath }}/assets/ui-theme-light.css" + } else if (theme === 'dark') { + linkElement.href = "{{ contextPath }}/assets/ui-theme-dark.css" + } else if (theme === 'highcontrast') { linkElement.href = "{{ contextPath }}/assets/ui-theme-highcontrast.css" } else { - linkElement.href = "{{ contextPath }}/assets/ui-theme-light.css" + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + linkElement.href = "{{ contextPath }}/assets/ui-theme-dark.css" + } else { + linkElement.href = "{{ contextPath }}/assets/ui-theme-light.css" + } } document.head.appendChild(linkElement); diff --git a/scm-ui/ui-webapp/public/locales/de/commons.json b/scm-ui/ui-webapp/public/locales/de/commons.json index 7cdda9eb94..22588cf11d 100644 --- a/scm-ui/ui-webapp/public/locales/de/commons.json +++ b/scm-ui/ui-webapp/public/locales/de/commons.json @@ -105,11 +105,19 @@ "submit": "Anwenden", "light": { "displayName": "Hell", - "description": "'Hell' is das Standard-Design des SCM-Managers" + "description": "„Hell“ is das Standard-Design des SCM-Managers" }, "highcontrast": { "displayName": "Hoher Kontrast", - "description": "'Hoher Kontrast' ist ein dunkles Design mit einem hohen Kontrast" + "description": "„Hoher Kontrast“ ist ein dunkles Design mit einem hohen Kontrast" + }, + "dark": { + "displayName": "Dunkel", + "description": "„Dunkel“ ist ein entspannteres, dunkles Design" + }, + "systemdefault": { + "displayName": "Systemstandard", + "description": "Verwendet die Standardeinstellung des Systems" } } }, diff --git a/scm-ui/ui-webapp/public/locales/en/commons.json b/scm-ui/ui-webapp/public/locales/en/commons.json index b9913f14c2..df449379be 100644 --- a/scm-ui/ui-webapp/public/locales/en/commons.json +++ b/scm-ui/ui-webapp/public/locales/en/commons.json @@ -111,6 +111,14 @@ "highcontrast": { "displayName": "High contrast", "description": "The high contrast mode is a dark theme with a high contrast between the colors" + }, + "dark": { + "displayName": "Dark", + "description": "The dark mode is a more relaxed, dark theme" + }, + "systemdefault": { + "displayName": "System default", + "description": "Use the default setting of the system" } } }, diff --git a/scm-ui/ui-webapp/src/admin/plugins/components/PluginBottomActions.tsx b/scm-ui/ui-webapp/src/admin/plugins/components/PluginBottomActions.tsx index 2882af543a..41ec4e8225 100644 --- a/scm-ui/ui-webapp/src/admin/plugins/components/PluginBottomActions.tsx +++ b/scm-ui/ui-webapp/src/admin/plugins/components/PluginBottomActions.tsx @@ -30,7 +30,7 @@ type Props = { }; const ActionWrapper = styled.div` - border: 2px solid #e9f7fd; + border: 2px solid var(--scm-border-color); `; export default class PluginBottomActions extends React.Component { diff --git a/scm-ui/ui-webapp/src/components/HeaderButton.tsx b/scm-ui/ui-webapp/src/components/HeaderButton.tsx index b68bfc7928..b4641439aa 100644 --- a/scm-ui/ui-webapp/src/components/HeaderButton.tsx +++ b/scm-ui/ui-webapp/src/components/HeaderButton.tsx @@ -26,9 +26,8 @@ import styled from "styled-components"; import { devices } from "@scm-manager/ui-components"; const HeaderButton = styled.div` - // TODO: ersetzen? @media screen and (max-width: ${devices.desktop.width - 1}px) { - border-top: 1px solid white; + border-top: 1px solid var(--scm-white-color); margin-top: 1rem; padding-top: 1rem; padding-bottom: 1rem; diff --git a/scm-ui/ui-webapp/src/components/HeaderButtonContent.tsx b/scm-ui/ui-webapp/src/components/HeaderButtonContent.tsx index 430680d62c..43bef6d319 100644 --- a/scm-ui/ui-webapp/src/components/HeaderButtonContent.tsx +++ b/scm-ui/ui-webapp/src/components/HeaderButtonContent.tsx @@ -30,12 +30,13 @@ type Props = { icon: string; }; -export const headerButtonContentClassName = "is-flex is-align-items-center is-justify-content-flex-start"; +export const headerButtonContentClassName = + "is-flex is-align-items-center is-justify-content-flex-start has-text-inherit"; const HeaderButtonContent: FC = ({ burgerMode, icon, label }) => ( <> - - {" " + label} + + {" " + label} ); diff --git a/scm-ui/ui-webapp/src/components/InfoBox.tsx b/scm-ui/ui-webapp/src/components/InfoBox.tsx index 426b20d217..e77b6213c3 100644 --- a/scm-ui/ui-webapp/src/components/InfoBox.tsx +++ b/scm-ui/ui-webapp/src/components/InfoBox.tsx @@ -86,9 +86,9 @@ class InfoBox extends React.Component { "is-align-items-center" )} > - -
    {t("login." + type)}
    -
    {t("login.tip")}
    + +
    {t("login." + type)}
    +
    {t("login.tip")}
    {this.renderBody()} diff --git a/scm-ui/ui-webapp/src/components/LoginForm.tsx b/scm-ui/ui-webapp/src/components/LoginForm.tsx index 0455702bb7..419937fec8 100644 --- a/scm-ui/ui-webapp/src/components/LoginForm.tsx +++ b/scm-ui/ui-webapp/src/components/LoginForm.tsx @@ -42,17 +42,20 @@ const TopMarginBox = styled.div` `; const AvatarWrapper = styled.figure` - margin-top: -70px; - padding-bottom: 20px; + display: flex; + justify-content: center; + margin: -70px auto 20px; + width: 128px; + height: 128px; + background: var(--scm-white-color); + border: 1px solid lightgray; + border-radius: 50%; `; const AvatarImage = styled(Image)` - width: 128px; - height: 128px; + width: 75%; + margin-left: 0.25rem; padding: 5px; - background: white; - border: 1px solid lightgray; - border-radius: 50%; `; class LoginForm extends React.Component { @@ -104,7 +107,7 @@ class LoginForm extends React.Component {

    {t("login.subtitle")}

    - + diff --git a/scm-ui/ui-webapp/src/containers/Alerts.tsx b/scm-ui/ui-webapp/src/containers/Alerts.tsx index 7046d02b4f..f079e5f3d1 100644 --- a/scm-ui/ui-webapp/src/containers/Alerts.tsx +++ b/scm-ui/ui-webapp/src/containers/Alerts.tsx @@ -86,7 +86,7 @@ const AlertsList: FC = ({ data }) => ( const ShieldNotificationIcon: FC = () => { const [t] = useTranslation("commons"); - return ; + return ; }; type ComponentAlert = Alert & { diff --git a/scm-ui/ui-webapp/src/containers/NavigationBar.tsx b/scm-ui/ui-webapp/src/containers/NavigationBar.tsx index 9ab844b13f..4209568130 100644 --- a/scm-ui/ui-webapp/src/containers/NavigationBar.tsx +++ b/scm-ui/ui-webapp/src/containers/NavigationBar.tsx @@ -87,31 +87,15 @@ const StyledNavBar = styled.nav` padding: 0; } - //TODO Ersetzen? .navbar-brand { @media screen and (max-width: ${devices.desktop.width - 1}px) { - border-bottom: 1px solid white; + border-bottom: 1px solid var(--scm-white-color); } } .navbar-menu.is-active .navbar-end .navbar-item { border-left: solid 5px transparent; } - - .navbar-burger { - color: #fff !important; - } - - .navbar-item { - :hover:not(.logo) { - background-color: rgba(10, 10, 10, 0.1) !important; - color: #fff; - } - color: #fff !important; - background-color: transparent !important; - } - color: #fff; - background-color: transparent !important; `; type Props = { diff --git a/scm-ui/ui-webapp/src/containers/Notifications.tsx b/scm-ui/ui-webapp/src/containers/Notifications.tsx index 43cf713fb2..4f31481f03 100644 --- a/scm-ui/ui-webapp/src/containers/Notifications.tsx +++ b/scm-ui/ui-webapp/src/containers/Notifications.tsx @@ -222,7 +222,7 @@ const BellNotificationIcon: FC = ({ data }) => { className="is-size-4" iconStyle={counter === 0 ? "far" : "fas"} name="bell" - color="white" + color="inherit" alt={t("notifications.bellTitle")} /> ); diff --git a/scm-ui/ui-webapp/src/containers/Theme.tsx b/scm-ui/ui-webapp/src/containers/Theme.tsx index 7407cc2d8d..d393033526 100644 --- a/scm-ui/ui-webapp/src/containers/Theme.tsx +++ b/scm-ui/ui-webapp/src/containers/Theme.tsx @@ -23,15 +23,16 @@ */ import React, { FC, useState } from "react"; -import { createA11yId, Radio, SubmitButton, Subtitle } from "@scm-manager/ui-components"; +import { ButtonGroup, createA11yId, Radio, SubmitButton, Subtitle } from "@scm-manager/ui-components"; import { useForm } from "react-hook-form"; import styled from "styled-components"; import { useTranslation } from "react-i18next"; +import classNames from "classnames"; const LS_KEY = "scm.theme"; const useThemeState = () => { - const [theme] = useState(localStorage.getItem(LS_KEY) || "light"); + const [theme] = useState(localStorage.getItem(LS_KEY) || "systemdefault"); const [isLoading, setLoading] = useState(false); const setTheme = (name: string) => { @@ -47,7 +48,7 @@ type ThemeForm = { theme: string; }; -const themes = ["light", "highcontrast"]; +const themes = ["light", "dark", "highcontrast", "systemdefault"]; const RadioColumn = styled.div` flex: none; @@ -60,7 +61,8 @@ const Theme: FC = () => { register, setValue, handleSubmit, - formState: { isDirty } + formState: { isDirty }, + watch } = useForm({ mode: "onChange", defaultValues: { @@ -76,14 +78,23 @@ const Theme: FC = () => { return ( <> {t("profile.theme.subtitle")} - + {themes.map(theme => { const a11yId = createA11yId("theme"); return (
    setValue("theme", theme, { shouldDirty: true })} - className="card ml-1 mb-5 control columns is-vcentered has-cursor-pointer" + className={classNames( + "card", + "ml-1", + "mb-5", + "control", + "columns", + "is-vcentered", + "has-cursor-pointer", + { "has-background-secondary-less": theme === watch().theme } + )} > @@ -95,7 +106,9 @@ const Theme: FC = () => {
    ); })} - + + + ); diff --git a/scm-ui/ui-webapp/src/repos/codeSection/components/CodeActionBar.tsx b/scm-ui/ui-webapp/src/repos/codeSection/components/CodeActionBar.tsx index d0361861b5..682083d6bc 100644 --- a/scm-ui/ui-webapp/src/repos/codeSection/components/CodeActionBar.tsx +++ b/scm-ui/ui-webapp/src/repos/codeSection/components/CodeActionBar.tsx @@ -30,7 +30,7 @@ import { useTranslation } from "react-i18next"; import { Branch } from "@scm-manager/ui-types"; const ActionBar = styled.div` - border: 1px solid #dbdbdb; + border: 1px solid var(--scm-border-color); border-radius: 4px; font-size: 1.25em; font-weight: 300; diff --git a/scm-ui/ui-webapp/src/repos/components/form/RepositoryFormSwitcher.tsx b/scm-ui/ui-webapp/src/repos/components/form/RepositoryFormSwitcher.tsx index f57bd735b1..cbe9417d78 100644 --- a/scm-ui/ui-webapp/src/repos/components/form/RepositoryFormSwitcher.tsx +++ b/scm-ui/ui-webapp/src/repos/components/form/RepositoryFormSwitcher.tsx @@ -45,7 +45,7 @@ const RepositoryFormButton: FC = ({ path, icon, label }) => { color={isSelected ? "link is-selected" : undefined} link={!isSelected ? href : undefined} > - +

    {t(`plugins:${label}`, label)}

    ); diff --git a/scm-ui/ui-webapp/src/repos/containers/ExportRepository.tsx b/scm-ui/ui-webapp/src/repos/containers/ExportRepository.tsx index f147d11366..72b48923f4 100644 --- a/scm-ui/ui-webapp/src/repos/containers/ExportRepository.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/ExportRepository.tsx @@ -43,7 +43,7 @@ const InfoBox = styled.div` white-space: pre-line; border-radius: 2px; border-left: 0.2rem solid; - border-color: #33b2e8; + border-color: var(--scm-info-color); `; type Props = { diff --git a/scm-ui/ui-webapp/src/repos/sources/containers/Content.tsx b/scm-ui/ui-webapp/src/repos/sources/containers/Content.tsx index cfa6c7f555..05364c9074 100644 --- a/scm-ui/ui-webapp/src/repos/sources/containers/Content.tsx +++ b/scm-ui/ui-webapp/src/repos/sources/containers/Content.tsx @@ -42,7 +42,7 @@ type Props = { }; const HeaderWrapper = styled.div` - border-bottom: solid 1px #dbdbdb; + border-bottom: 1px solid var(--scm-border-color); font-size: 1.25em; font-weight: 300; line-height: 1.25; @@ -50,7 +50,7 @@ const HeaderWrapper = styled.div` `; const BorderBottom = styled.div` - border-bottom: solid 1px #dbdbdb; + border-bottom: 1px solid var(--scm-border-color); `; const FullWidthTitleHeader = styled.div` diff --git a/scm-ui/ui-webapp/src/search/Syntax.tsx b/scm-ui/ui-webapp/src/search/Syntax.tsx index 1de57ecc4f..c13ed62e1c 100644 --- a/scm-ui/ui-webapp/src/search/Syntax.tsx +++ b/scm-ui/ui-webapp/src/search/Syntax.tsx @@ -184,6 +184,7 @@ const TimestampConverter: FC = () => {
    { - - {copying ? ( - - ) : ( - - )} - +
    + + {copying ? ( + + ) : ( + + )} + +
    );