mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge branch 'main' into dev
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
@import "/src/theme";
|
||||
/*
|
||||
* Sidebar
|
||||
*/
|
||||
@@ -36,10 +35,15 @@
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
|
||||
&:hover, &.active {
|
||||
&:hover, &.active, &:focus {
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
background-color: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import "/src/theme";
|
||||
|
||||
.badge-corner {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import "/src/theme";
|
||||
|
||||
form {
|
||||
position: relative;
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import "/src/theme";
|
||||
|
||||
.result-content {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import "/src/theme";
|
||||
|
||||
.card-text {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import "/src/theme";
|
||||
|
||||
::ng-deep app-document-list app-page-header > div.mb-3 {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
<ul ngbNav #nav="ngbNav" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<a ngbNavLink i18n>General settings</a>
|
||||
<a ngbNavLink i18n>General</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<h4 i18n>Appearance</h4>
|
||||
@@ -104,7 +104,7 @@
|
||||
<div class="col-md-3 col-form-label">
|
||||
<span i18n>Theme Color</span>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="col col-md-3">
|
||||
<app-input-color i18n-title formControlName="themeColor" [error]="error?.color"></app-input-color>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
|
@@ -9,7 +9,11 @@ import {
|
||||
} from '@angular/core'
|
||||
import { Meta } from '@angular/platform-browser'
|
||||
import { CookieService } from 'ngx-cookie-service'
|
||||
import { hexToHsl } from 'src/app/utils/color'
|
||||
import {
|
||||
BRIGHTNESS,
|
||||
estimateBrightnessForColor,
|
||||
hexToHsl,
|
||||
} from 'src/app/utils/color'
|
||||
|
||||
export interface PaperlessSettings {
|
||||
key: string
|
||||
@@ -132,28 +136,41 @@ export class SettingsService {
|
||||
: this.renderer.removeClass(this.document.body, 'color-scheme-dark')
|
||||
}
|
||||
|
||||
// remove these in case they were there
|
||||
this.renderer.removeClass(this.document.body, 'primary-dark')
|
||||
this.renderer.removeClass(this.document.body, 'primary-light')
|
||||
|
||||
if (themeColor) {
|
||||
const hsl = hexToHsl(themeColor)
|
||||
const bgBrightnessEstimate = estimateBrightnessForColor(themeColor)
|
||||
|
||||
if (bgBrightnessEstimate == BRIGHTNESS.DARK) {
|
||||
this.renderer.addClass(this.document.body, 'primary-dark')
|
||||
this.renderer.removeClass(this.document.body, 'primary-light')
|
||||
} else {
|
||||
this.renderer.addClass(this.document.body, 'primary-light')
|
||||
this.renderer.removeClass(this.document.body, 'primary-dark')
|
||||
}
|
||||
this.renderer.setStyle(
|
||||
document.documentElement,
|
||||
document.body,
|
||||
'--pngx-primary',
|
||||
`${+hsl.h * 360},${hsl.s * 100}%`,
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
this.renderer.setStyle(
|
||||
document.documentElement,
|
||||
document.body,
|
||||
'--pngx-primary-lightness',
|
||||
`${hsl.l * 100}%`,
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
} else {
|
||||
this.renderer.removeStyle(
|
||||
document.documentElement,
|
||||
document.body,
|
||||
'--pngx-primary',
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
this.renderer.removeStyle(
|
||||
document.documentElement,
|
||||
document.body,
|
||||
'--pngx-primary-lightness',
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
|
@@ -1,4 +1,9 @@
|
||||
import { HSL } from 'ngx-color'
|
||||
import { HSL, RGB } from 'ngx-color'
|
||||
|
||||
export const BRIGHTNESS = {
|
||||
LIGHT: 'light',
|
||||
DARK: 'dark',
|
||||
}
|
||||
|
||||
function componentToHex(c) {
|
||||
var hex = Math.floor(c).toString(16)
|
||||
@@ -86,14 +91,42 @@ export function rgbToHsl(r, g, b) {
|
||||
}
|
||||
|
||||
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('#', '')
|
||||
let aRgbHex = hex.match(/.{1,2}/g)
|
||||
const hsl = rgbToHsl(
|
||||
parseInt(aRgbHex[0], 16),
|
||||
parseInt(aRgbHex[1], 16),
|
||||
parseInt(aRgbHex[2], 16)
|
||||
)
|
||||
return { h: hsl[0], s: hsl[1], l: hsl[2] }
|
||||
return {
|
||||
r: parseInt(aRgbHex[0], 16),
|
||||
g: parseInt(aRgbHex[1], 16),
|
||||
b: parseInt(aRgbHex[2], 16),
|
||||
}
|
||||
}
|
||||
|
||||
export function computeLuminance(color: RGB) {
|
||||
// Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
||||
const colorKeys = Object.keys(color)
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var rgb = color[colorKeys[i]]
|
||||
rgb /= 255
|
||||
rgb = rgb < 0.03928 ? rgb / 12.92 : Math.pow((rgb + 0.055) / 1.055, 2.4)
|
||||
color[i] = rgb
|
||||
}
|
||||
return 0.2126 * color[0] + 0.7152 * color[1] + 0.0722 * color[2]
|
||||
}
|
||||
|
||||
export function estimateBrightnessForColor(colorHex: string) {
|
||||
// See <https://www.w3.org/TR/WCAG20/#contrast-ratiodef>
|
||||
// Adapted from https://api.flutter.dev/flutter/material/ThemeData/estimateBrightnessForColor.html
|
||||
const rgb = hexToRGB(colorHex)
|
||||
const luminance = computeLuminance(rgb)
|
||||
const kThreshold = 0.15
|
||||
return (luminance + 0.05) * (luminance + 0.05) > kThreshold
|
||||
? BRIGHTNESS.LIGHT
|
||||
: BRIGHTNESS.DARK
|
||||
}
|
||||
|
||||
export function randomColor() {
|
||||
|
Reference in New Issue
Block a user