Initial build of primary color contrast

This commit is contained in:
Michael Shamoon 2022-04-12 19:21:55 -07:00
parent d5d7e2edbc
commit d98a016087
5 changed files with 237 additions and 179 deletions

View File

@ -132,8 +132,22 @@ export class SettingsService {
: this.renderer.removeClass(this.document.body, 'color-scheme-dark') : this.renderer.removeClass(this.document.body, 'color-scheme-dark')
} }
// remove these in case they were there
this.renderer.removeClass(this.document.body, 'text-bg-dark')
this.renderer.removeClass(this.document.body, 'text-bg-light')
if (themeColor) { if (themeColor) {
const hsl = hexToHsl(themeColor) const hsl = hexToHsl(themeColor)
const useDarkTextColor =
parseInt(themeColor.replace('#', ''), 16) > 0xffffff / 1.5
if (useDarkTextColor) {
this.renderer.addClass(this.document.body, 'text-bg-dark')
this.renderer.removeClass(this.document.body, 'text-bg-light')
} else {
this.renderer.addClass(this.document.body, 'text-bg-light')
this.renderer.removeClass(this.document.body, 'text-bg-dark')
}
this.renderer.setStyle( this.renderer.setStyle(
document.documentElement, document.documentElement,
'--pngx-primary', '--pngx-primary',

View File

@ -1,4 +1,4 @@
import { HSL } from 'ngx-color' import { HSL, RGB } from 'ngx-color'
function componentToHex(c) { function componentToHex(c) {
var hex = Math.floor(c).toString(16) var hex = Math.floor(c).toString(16)
@ -86,14 +86,19 @@ export function rgbToHsl(r, g, b) {
} }
export function hexToHsl(hex: string): HSL { export function hexToHsl(hex: string): HSL {
const rgb = hexToRGB(hex)
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b)
return { h: hsl[0], s: hsl[1], l: hsl[2] }
}
export function hexToRGB(hex: string): RGB {
hex = hex.replace('#', '') hex = hex.replace('#', '')
let aRgbHex = hex.match(/.{1,2}/g) let aRgbHex = hex.match(/.{1,2}/g)
const hsl = rgbToHsl( return {
parseInt(aRgbHex[0], 16), r: parseInt(aRgbHex[0], 16),
parseInt(aRgbHex[1], 16), g: parseInt(aRgbHex[1], 16),
parseInt(aRgbHex[2], 16) b: parseInt(aRgbHex[2], 16),
) }
return { h: hsl[0], s: hsl[1], l: hsl[2] }
} }
export function randomColor() { export function randomColor() {

View File

@ -4,7 +4,6 @@ $enable-negative-margins: true;
@import "node_modules/bootstrap/scss/bootstrap"; @import "node_modules/bootstrap/scss/bootstrap";
@import "~@ng-select/ng-select/themes/default.theme.css"; @import "~@ng-select/ng-select/themes/default.theme.css";
@import "theme"; @import "theme";
@import "theme_dark";
@import "print"; @import "print";
// Paperless-ngx styles // Paperless-ngx styles
@ -36,9 +35,19 @@ svg.logo {
.bg-primary { .bg-primary {
background-color: var(--bs-primary) !important; background-color: var(--bs-primary) !important;
color: var(--pngx-primary-text-contrast);
}
.navbar-brand {
color: var(--pngx-primary-text-contrast) !important;
}
.navbar .dropdown .btn {
color: var(--pngx-primary-text-contrast) !important;
} }
.btn-primary { .btn-primary {
color: var(--pngx-primary-text-contrast);
background-color: var(--bs-primary); background-color: var(--bs-primary);
border-color: var(--bs-primary); border-color: var(--bs-primary);
@ -48,6 +57,7 @@ svg.logo {
} }
&:disabled, &.disabled { &:disabled, &.disabled {
color: var(--pngx-primary-text-contrast);
background-color: var(--pngx-primary-darken-10) !important; background-color: var(--pngx-primary-darken-10) !important;
border-color: var(--pngx-primary-darken-10) !important; border-color: var(--pngx-primary-darken-10) !important;
} }
@ -350,6 +360,14 @@ table.table {
} }
} }
.toast {
color: var(--pngx-primary-text-contrast);
.toast-header {
color: var(--pngx-primary-text-contrast);
}
}
.close { .close {
color: var(--bs-body-color); color: var(--bs-body-color);
} }

View File

@ -15,3 +15,195 @@
--pngx-bg-darker: var(--bs-gray-100); --pngx-bg-darker: var(--bs-gray-100);
--pngx-focus-alpha: 0.3; --pngx-focus-alpha: 0.3;
} }
// Dark text colors allow for maintain contrast with theme color changes
$text-color-light-bg: #212529;
$text-color-dark-bg: #abb2bf;
$text-color-dark-bg-accent: lighten($text-color-dark-bg, 10%);
// Taken from bootstrap
$form-check-input-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#212529' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/></svg>");
$form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#212529'/></svg>");
.text-bg-light {
--pngx-primary-text-contrast: #{$text-color-light-bg} !important;
.form-check-input:checked[type=checkbox] {
background-image: escape-svg($form-check-input-checked-bg-image-dark);
}
.form-check-input:checked[type=radio] {
background-image: escape-svg($form-check-radio-checked-bg-image-dark);
}
}
.text-bg-dark {
--pngx-primary-text-contrast: #{$text-color-dark-bg} !important;
}
// Dark mode
$primary-dark-mode: #45973a;
$primary-dark-mode-rgb: 69, 151, 58;
$primary-dark-mode-darken-10: darken($primary-dark-mode, 10%);
$danger-dark-mode: #b71631;
$danger-dark-mode-rgb: 183, 22, 49;
$bg-dark-mode: #161618;
$bg-dark-mode-rgb: 22, 22, 24;
$bg-dark-mode-accent: #101216;
$bg-dark-mode-alt: #242529;
$bg-light-dark-mode: #1c1c1f;
$bg-light-dark-mode-rgb: 28, 28, 31;
$border-color-dark-mode: #47494f;
@mixin dark-mode {
--bs-primary: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) + 10%));
--bs-body-color: #{$text-color-dark-bg};
--pngx-body-color-accent: #{$text-color-dark-bg-accent};
--bs-danger: #{$danger-dark-mode};
--bs-danger-rgb: #{$danger-dark-mode-rgb};
--bs-body-bg: #{$bg-dark-mode};
--bs-body-bg-rgb: #{$bg-dark-mode-rgb};
--bs-light: #{$bg-light-dark-mode};
--bs-light-rgb: #{$bg-light-dark-mode-rgb};
--bs-border-color: #{$border-color-dark-mode};
--pngx-bg-darker: #{$bg-dark-mode-accent};
--pngx-bg-alt: #{$bg-dark-mode-alt};
--pngx-focus-alpha: 0.7;
--pngx-primary-faded: var(--pngx-primary-darken-15);
--pngx-primary-text-contrast: var(--bs-body-color);
.navbar.bg-primary {
--bs-primary: hsl(var(--pngx-primary),var(--pngx-primary-lightness));
--bs-primary-rgb: var(--bs-primary);
}
.border {
border-color: var(--bs-border-color) !important;
}
.border-end {
border-right: 1px solid var(--bs-border-color) !important;
}
.border-start {
border-left: 1px solid var(--bs-border-color) !important;
}
.border-bottom {
border-bottom: 1px solid var(--bs-border-color) !important;
}
.text-dark, .text-light {
color: var(--bs-body-color) !important;
}
.btn-outline-primary, .btn-primary {
&:hover, &:focus, &.active, &:active {
color: var(--bs-light) !important;
}
}
.btn-outline-secondary {
&:hover, &:focus, &.active, &:active {
background-color: var(--pngx-bg-darker);
color: var(--bs-primary);
}
}
.search-form-container {
input, input:focus {
color: var(--bs-body-color) !important;
}
}
.card {
background-color: var(--bs-body-bg);
.card-header {
background-color: rgba(0, 0, 0, 0.12);
}
}
.modal-content, .modal-header, .modal-body, .modal-footer {
background-color: var(--bs-body-bg);
border-color: var(--bs-border-color);
}
app-tag .badge {
filter: brightness(.8);
}
.doc-img-container {
border: none !important;
border-top-left-radius: .25rem;
border-top-right-radius: .25rem;
overflow: hidden;
}
.doc-img {
mix-blend-mode: normal;
border-radius: 0;
border-color: var(--bs-border-color);
filter: invert(10%);
&.border-end {
border-right: none !important;
}
}
.doc-img.inverted {
filter: invert(95%) hue-rotate(180deg);
}
.card-selected .doc-img {
mix-blend-mode: luminosity;
}
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option:hover,
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
background-color: $bg-light-dark-mode;
}
table {
.des,
.asc {
&::after {
filter: invert(0.8); /* arrow is a black inline png bkgd image (!) so use filter */
}
}
&.table-hover > tbody > tr:hover > * {
background-color: $bg-light-dark-mode;
color: var(--pngx-body-color-accent);
}
}
.table-striped > tbody > tr:nth-of-type(odd) > * {
color: var(--pngx-body-color-accent);
}
.close, .modal .btn-close, .alert .btn-close {
text-shadow: 0 1px 0 #666;
}
.modal .btn-close, .alert .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
.toast {
background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 18%), 0.9);
}
.toast-header {
background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 10%), 0.9);
}
}
body.color-scheme-dark {
@include dark-mode;
}
body.color-scheme-system {
@media (prefers-color-scheme: dark) {
@include dark-mode;
}
}

View File

@ -1,171 +0,0 @@
$primary-dark-mode: #45973a;
$primary-dark-mode-rgb: 69, 151, 58;
$primary-dark-mode-darken-10: darken($primary-dark-mode, 10%);
$danger-dark-mode: #b71631;
$danger-dark-mode-rgb: 183, 22, 49;
$bg-dark-mode: #161618;
$bg-dark-mode-rgb: 22, 22, 24;
$bg-dark-mode-accent: #101216;
$bg-dark-mode-alt: #242529;
$bg-light-dark-mode: #1c1c1f;
$bg-light-dark-mode-rgb: 28, 28, 31;
$text-color-dark-mode: #abb2bf;
$text-color-dark-mode-accent: lighten($text-color-dark-mode, 10%);
$border-color-dark-mode: #47494f;
@mixin dark-mode {
--bs-primary: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) + 10%));
--bs-danger: #{$danger-dark-mode};
--bs-danger-rgb: #{$danger-dark-mode-rgb};
--bs-body-bg: #{$bg-dark-mode};
--bs-body-bg-rgb: #{$bg-dark-mode-rgb};
--bs-body-color: #{$text-color-dark-mode};
--bs-light: #{$bg-light-dark-mode};
--bs-light-rgb: #{$bg-light-dark-mode-rgb};
--bs-border-color: #{$border-color-dark-mode};
--pngx-bg-darker: #{$bg-dark-mode-accent};
--pngx-bg-alt: #{$bg-dark-mode-alt};
--pngx-body-color-accent: #{$text-color-dark-mode-accent};
--pngx-focus-alpha: 0.7;
--pngx-primary-faded: var(--pngx-primary-darken-15);
--pngx-primary-text-contrast: var(--bs-body-color);
.navbar.bg-primary{
--bs-primary: hsl(var(--pngx-primary),var(--pngx-primary-lightness));
--bs-primary-rgb: var(--bs-primary);
}
.navbar-brand {
color: var(--bs-body-color);
}
.border {
border-color: var(--bs-border-color) !important;
}
.border-end {
border-right: 1px solid var(--bs-border-color) !important;
}
.border-start {
border-left: 1px solid var(--bs-border-color) !important;
}
.border-bottom {
border-bottom: 1px solid var(--bs-border-color) !important;
}
.text-dark, .text-light {
color: var(--bs-body-color) !important;
}
.btn-outline-primary, .btn-primary {
&:hover, &:focus, &.active, &:active {
color: var(--bs-light) !important;
}
}
.btn-outline-secondary {
&:hover, &:focus, &.active, &:active {
background-color: var(--pngx-bg-darker);
color: var(--bs-primary);
}
}
.search-form-container {
input, input:focus {
color: var(--bs-body-color) !important;
}
}
.card {
background-color: var(--bs-body-bg);
.card-header {
background-color: rgba(0, 0, 0, 0.12);
}
}
.modal-content, .modal-header, .modal-body, .modal-footer {
background-color: var(--bs-body-bg);
border-color: var(--bs-border-color);
}
app-tag .badge {
filter: brightness(.8);
}
.doc-img-container {
border: none !important;
border-top-left-radius: .25rem;
border-top-right-radius: .25rem;
overflow: hidden;
}
.doc-img {
mix-blend-mode: normal;
border-radius: 0;
border-color: var(--bs-border-color);
filter: invert(10%);
&.border-end {
border-right: none !important;
}
}
.doc-img.inverted {
filter: invert(95%) hue-rotate(180deg);
}
.card-selected .doc-img {
mix-blend-mode: luminosity;
}
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option:hover,
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
background-color: $bg-light-dark-mode;
}
table {
.des,
.asc {
&::after {
filter: invert(0.8); /* arrow is a black inline png bkgd image (!) so use filter */
}
}
&.table-hover > tbody > tr:hover > * {
background-color: $bg-light-dark-mode;
color: $text-color-dark-mode-accent;
}
}
.table-striped > tbody > tr:nth-of-type(odd) > * {
color: $text-color-dark-mode-accent;
}
.close, .modal .btn-close, .alert .btn-close {
text-shadow: 0 1px 0 #666;
}
.modal .btn-close, .alert .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
.toast {
background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 18%), 0.9);
}
.toast-header {
background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 10%), 0.9);
}
}
body.color-scheme-dark {
@include dark-mode;
}
body.color-scheme-system {
@media (prefers-color-scheme: dark) {
@include dark-mode;
}
}