Resolve some change detection issues
This commit is contained in:
parent
0d7474d4af
commit
a34404eac0
@ -94,7 +94,7 @@ The following files need to be changed:
|
|||||||
|
|
||||||
- src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key)
|
- src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key)
|
||||||
- src/paperless/settings.py (in the _LANGUAGES_ array)
|
- src/paperless/settings.py (in the _LANGUAGES_ array)
|
||||||
- src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method)
|
- src-ui/src/app/services/settings.service.ts (inside the _LANGUAGE_OPTIONS_ array)
|
||||||
- src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_)
|
- src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_)
|
||||||
|
|
||||||
Please add the language in the correct order, alphabetically by locale.
|
Please add the language in the correct order, alphabetically by locale.
|
||||||
|
@ -277,27 +277,17 @@ Adding new languages requires adding the translated files in the
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Add the language to the available options in
|
2. Add the language to the `LANGUAGE_OPTIONS` array in
|
||||||
`src-ui/src/app/services/settings.service.ts`:
|
`src-ui/src/app/services/settings.service.ts`:
|
||||||
|
|
||||||
```typescript
|
|
||||||
getLanguageOptions(): LanguageOption[] {
|
|
||||||
return [
|
|
||||||
{code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"},
|
|
||||||
{code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"},
|
|
||||||
{code: "de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"},
|
|
||||||
{code: "nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"},
|
|
||||||
{code: "fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"},
|
|
||||||
{code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"}
|
|
||||||
// Add your new language here
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`dateInputFormat` is a special string that defines the behavior of
|
`dateInputFormat` is a special string that defines the behavior of
|
||||||
the date input fields and absolutely needs to contain "dd", "mm"
|
the date input fields and absolutely needs to contain "dd", "mm"
|
||||||
and "yyyy".
|
and "yyyy".
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
3. Import and register the Angular data for this locale in
|
3. Import and register the Angular data for this locale in
|
||||||
`src-ui/src/app/app.module.ts`:
|
`src-ui/src/app/app.module.ts`:
|
||||||
|
|
||||||
|
@ -48,6 +48,12 @@ enum SettingsNavIDs {
|
|||||||
SavedViews = 4,
|
SavedViews = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const systemLanguage = { code: '', name: $localize`Use system language` }
|
||||||
|
const systemDateFormat = {
|
||||||
|
code: '',
|
||||||
|
name: $localize`Use date format of display language`,
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pngx-settings',
|
selector: 'pngx-settings',
|
||||||
templateUrl: './settings.component.html',
|
templateUrl: './settings.component.html',
|
||||||
@ -512,15 +518,11 @@ export class SettingsComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
get displayLanguageOptions(): LanguageOption[] {
|
get displayLanguageOptions(): LanguageOption[] {
|
||||||
return [{ code: '', name: $localize`Use system language` }].concat(
|
return [systemLanguage].concat(this.settings.getLanguageOptions())
|
||||||
this.settings.getLanguageOptions()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get dateLocaleOptions(): LanguageOption[] {
|
get dateLocaleOptions(): LanguageOption[] {
|
||||||
return [
|
return [systemDateFormat].concat(this.settings.getDateLocaleOptions())
|
||||||
{ code: '', name: $localize`Use date format of display language` },
|
|
||||||
].concat(this.settings.getDateLocaleOptions())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get today() {
|
get today() {
|
||||||
|
@ -27,6 +27,24 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
|
|||||||
import { UploadFileWidgetComponent } from './upload-file-widget.component'
|
import { UploadFileWidgetComponent } from './upload-file-widget.component'
|
||||||
import { DragDropModule } from '@angular/cdk/drag-drop'
|
import { DragDropModule } from '@angular/cdk/drag-drop'
|
||||||
|
|
||||||
|
const FAILED_STATUSES = [new FileStatus()]
|
||||||
|
const WORKING_STATUSES = [new FileStatus(), new FileStatus()]
|
||||||
|
const STARTED_STATUSES = [new FileStatus(), new FileStatus(), new FileStatus()]
|
||||||
|
const SUCCESS_STATUSES = [
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
]
|
||||||
|
const DEFAULT_STATUSES = [
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
new FileStatus(),
|
||||||
|
]
|
||||||
|
|
||||||
describe('UploadFileWidgetComponent', () => {
|
describe('UploadFileWidgetComponent', () => {
|
||||||
let component: UploadFileWidgetComponent
|
let component: UploadFileWidgetComponent
|
||||||
let fixture: ComponentFixture<UploadFileWidgetComponent>
|
let fixture: ComponentFixture<UploadFileWidgetComponent>
|
||||||
@ -150,41 +168,22 @@ function mockConsumerStatuses(consumerStatusService) {
|
|||||||
.mockImplementation((phase) => {
|
.mockImplementation((phase) => {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case FileStatusPhase.FAILED:
|
case FileStatusPhase.FAILED:
|
||||||
return [new FileStatus()]
|
return FAILED_STATUSES
|
||||||
case FileStatusPhase.WORKING:
|
case FileStatusPhase.WORKING:
|
||||||
return [new FileStatus(), new FileStatus()]
|
return WORKING_STATUSES
|
||||||
case FileStatusPhase.STARTED:
|
case FileStatusPhase.STARTED:
|
||||||
return [new FileStatus(), new FileStatus(), new FileStatus()]
|
return STARTED_STATUSES
|
||||||
case FileStatusPhase.SUCCESS:
|
case FileStatusPhase.SUCCESS:
|
||||||
return [
|
return SUCCESS_STATUSES
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
]
|
|
||||||
case FileStatusPhase.UPLOADING:
|
case FileStatusPhase.UPLOADING:
|
||||||
return [partialUpload1, partialUpload2]
|
return [partialUpload1, partialUpload2]
|
||||||
default:
|
default:
|
||||||
return [
|
return DEFAULT_STATUSES
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
jest
|
jest
|
||||||
.spyOn(consumerStatusService, 'getConsumerStatusNotCompleted')
|
.spyOn(consumerStatusService, 'getConsumerStatusNotCompleted')
|
||||||
.mockImplementation(() => {
|
.mockImplementation(() => {
|
||||||
return [
|
return DEFAULT_STATUSES
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
new FileStatus(),
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,51 @@ const RELATIVE_DATE_QUERYSTRINGS = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const DEFAULT_TEXT_FILTER_TARGET_OPTIONS = [
|
||||||
|
{ id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title` },
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_TARGET_TITLE_CONTENT,
|
||||||
|
name: $localize`Title & content`,
|
||||||
|
},
|
||||||
|
{ id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` },
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_TARGET_CUSTOM_FIELDS,
|
||||||
|
name: $localize`Custom fields`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_TARGET_FULLTEXT_QUERY,
|
||||||
|
name: $localize`Advanced search`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const TEXT_FILTER_TARGET_MORELIKE_OPTION = {
|
||||||
|
id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE,
|
||||||
|
name: $localize`More like`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_TEXT_FILTER_MODIFIER_OPTIONS = [
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_MODIFIER_EQUALS,
|
||||||
|
label: $localize`equals`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_MODIFIER_NULL,
|
||||||
|
label: $localize`is empty`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_MODIFIER_NOTNULL,
|
||||||
|
label: $localize`is not empty`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_MODIFIER_GT,
|
||||||
|
label: $localize`greater than`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TEXT_FILTER_MODIFIER_LT,
|
||||||
|
label: $localize`less than`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pngx-filter-editor',
|
selector: 'pngx-filter-editor',
|
||||||
templateUrl: './filter-editor.component.html',
|
templateUrl: './filter-editor.component.html',
|
||||||
@ -199,29 +244,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
_moreLikeDoc: PaperlessDocument
|
_moreLikeDoc: PaperlessDocument
|
||||||
|
|
||||||
get textFilterTargets() {
|
get textFilterTargets() {
|
||||||
let targets = [
|
|
||||||
{ id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title` },
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_TARGET_TITLE_CONTENT,
|
|
||||||
name: $localize`Title & content`,
|
|
||||||
},
|
|
||||||
{ id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` },
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_TARGET_CUSTOM_FIELDS,
|
|
||||||
name: $localize`Custom fields`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_TARGET_FULLTEXT_QUERY,
|
|
||||||
name: $localize`Advanced search`,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
|
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
|
||||||
targets.push({
|
return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([
|
||||||
id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE,
|
TEXT_FILTER_TARGET_MORELIKE_OPTION,
|
||||||
name: $localize`More like`,
|
])
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return targets
|
return DEFAULT_TEXT_FILTER_TARGET_OPTIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT
|
textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT
|
||||||
@ -234,28 +262,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
public textFilterModifier: string
|
public textFilterModifier: string
|
||||||
|
|
||||||
get textFilterModifiers() {
|
get textFilterModifiers() {
|
||||||
return [
|
return DEFAULT_TEXT_FILTER_MODIFIER_OPTIONS
|
||||||
{
|
|
||||||
id: TEXT_FILTER_MODIFIER_EQUALS,
|
|
||||||
label: $localize`equals`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_MODIFIER_NULL,
|
|
||||||
label: $localize`is empty`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_MODIFIER_NOTNULL,
|
|
||||||
label: $localize`is not empty`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_MODIFIER_GT,
|
|
||||||
label: $localize`greater than`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TEXT_FILTER_MODIFIER_LT,
|
|
||||||
label: $localize`less than`,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get textFilterModifierIsNull(): boolean {
|
get textFilterModifierIsNull(): boolean {
|
||||||
|
@ -38,120 +38,7 @@ export interface LanguageOption {
|
|||||||
dateInputFormat?: string
|
dateInputFormat?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({
|
const LANGUAGE_OPTIONS = [
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class SettingsService {
|
|
||||||
protected baseUrl: string = environment.apiBaseUrl + 'ui_settings/'
|
|
||||||
|
|
||||||
private settings: Object = {}
|
|
||||||
currentUser: PaperlessUser
|
|
||||||
|
|
||||||
public settingsSaved: EventEmitter<any> = new EventEmitter()
|
|
||||||
|
|
||||||
private _renderer: Renderer2
|
|
||||||
public get renderer(): Renderer2 {
|
|
||||||
return this._renderer
|
|
||||||
}
|
|
||||||
|
|
||||||
public dashboardIsEmpty: boolean = false
|
|
||||||
|
|
||||||
public globalDropzoneEnabled: boolean = true
|
|
||||||
public globalDropzoneActive: boolean = false
|
|
||||||
public organizingSidebarSavedViews: boolean = false
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
rendererFactory: RendererFactory2,
|
|
||||||
@Inject(DOCUMENT) private document,
|
|
||||||
private cookieService: CookieService,
|
|
||||||
private meta: Meta,
|
|
||||||
@Inject(LOCALE_ID) private localeId: string,
|
|
||||||
protected http: HttpClient,
|
|
||||||
private toastService: ToastService,
|
|
||||||
private permissionsService: PermissionsService
|
|
||||||
) {
|
|
||||||
this._renderer = rendererFactory.createRenderer(null, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is called by the app initializer in app.module
|
|
||||||
public initializeSettings(): Observable<PaperlessUiSettings> {
|
|
||||||
return this.http.get<PaperlessUiSettings>(this.baseUrl).pipe(
|
|
||||||
first(),
|
|
||||||
tap((uisettings) => {
|
|
||||||
Object.assign(this.settings, uisettings.settings)
|
|
||||||
this.maybeMigrateSettings()
|
|
||||||
// to update lang cookie
|
|
||||||
if (this.settings['language']?.length)
|
|
||||||
this.setLanguage(this.settings['language'])
|
|
||||||
this.currentUser = uisettings.user
|
|
||||||
this.permissionsService.initialize(
|
|
||||||
uisettings.permissions,
|
|
||||||
this.currentUser
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
get displayName(): string {
|
|
||||||
return (
|
|
||||||
this.currentUser.first_name ??
|
|
||||||
this.currentUser.username ??
|
|
||||||
''
|
|
||||||
).trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateAppearanceSettings(
|
|
||||||
darkModeUseSystem = null,
|
|
||||||
darkModeEnabled = null,
|
|
||||||
themeColor = null
|
|
||||||
): void {
|
|
||||||
darkModeUseSystem ??= this.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM)
|
|
||||||
darkModeEnabled ??= this.get(SETTINGS_KEYS.DARK_MODE_ENABLED)
|
|
||||||
themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR)
|
|
||||||
|
|
||||||
if (darkModeUseSystem) {
|
|
||||||
this._renderer.setAttribute(
|
|
||||||
this.document.documentElement,
|
|
||||||
'data-bs-theme',
|
|
||||||
'auto'
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this._renderer.setAttribute(
|
|
||||||
this.document.documentElement,
|
|
||||||
'data-bs-theme',
|
|
||||||
darkModeEnabled ? 'dark' : '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')
|
|
||||||
}
|
|
||||||
document.documentElement.style.setProperty(
|
|
||||||
'--pngx-primary',
|
|
||||||
`${+hsl.h * 360},${hsl.s * 100}%`
|
|
||||||
)
|
|
||||||
document.documentElement.style.setProperty(
|
|
||||||
'--pngx-primary-lightness',
|
|
||||||
`${hsl.l * 100}%`
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this._renderer.removeClass(this.document.body, 'primary-dark')
|
|
||||||
this._renderer.removeClass(this.document.body, 'primary-light')
|
|
||||||
document.documentElement.style.removeProperty('--pngx-primary')
|
|
||||||
document.documentElement.style.removeProperty('--pngx-primary-lightness')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLanguageOptions(): LanguageOption[] {
|
|
||||||
const languages = [
|
|
||||||
{
|
{
|
||||||
code: 'en-us',
|
code: 'en-us',
|
||||||
name: $localize`English (US)`,
|
name: $localize`English (US)`,
|
||||||
@ -338,23 +225,135 @@ export class SettingsService {
|
|||||||
englishName: 'Chinese Simplified',
|
englishName: 'Chinese Simplified',
|
||||||
dateInputFormat: 'yyyy-mm-dd',
|
dateInputFormat: 'yyyy-mm-dd',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// Sort languages by localized name at runtime
|
const ISO_LANGUAGE_OPTION: LanguageOption = {
|
||||||
languages.sort((a, b) => {
|
|
||||||
return a.name < b.name ? -1 : 1
|
|
||||||
})
|
|
||||||
|
|
||||||
return languages
|
|
||||||
}
|
|
||||||
|
|
||||||
getDateLocaleOptions(): LanguageOption[] {
|
|
||||||
let isoOption: LanguageOption = {
|
|
||||||
code: 'iso-8601',
|
code: 'iso-8601',
|
||||||
name: $localize`ISO 8601`,
|
name: $localize`ISO 8601`,
|
||||||
dateInputFormat: 'yyyy-mm-dd',
|
dateInputFormat: 'yyyy-mm-dd',
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class SettingsService {
|
||||||
|
protected baseUrl: string = environment.apiBaseUrl + 'ui_settings/'
|
||||||
|
|
||||||
|
private settings: Object = {}
|
||||||
|
currentUser: PaperlessUser
|
||||||
|
|
||||||
|
public settingsSaved: EventEmitter<any> = new EventEmitter()
|
||||||
|
|
||||||
|
private _renderer: Renderer2
|
||||||
|
public get renderer(): Renderer2 {
|
||||||
|
return this._renderer
|
||||||
}
|
}
|
||||||
return [isoOption].concat(this.getLanguageOptions())
|
|
||||||
|
public dashboardIsEmpty: boolean = false
|
||||||
|
|
||||||
|
public globalDropzoneEnabled: boolean = true
|
||||||
|
public globalDropzoneActive: boolean = false
|
||||||
|
public organizingSidebarSavedViews: boolean = false
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
rendererFactory: RendererFactory2,
|
||||||
|
@Inject(DOCUMENT) private document,
|
||||||
|
private cookieService: CookieService,
|
||||||
|
private meta: Meta,
|
||||||
|
@Inject(LOCALE_ID) private localeId: string,
|
||||||
|
protected http: HttpClient,
|
||||||
|
private toastService: ToastService,
|
||||||
|
private permissionsService: PermissionsService
|
||||||
|
) {
|
||||||
|
this._renderer = rendererFactory.createRenderer(null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is called by the app initializer in app.module
|
||||||
|
public initializeSettings(): Observable<PaperlessUiSettings> {
|
||||||
|
return this.http.get<PaperlessUiSettings>(this.baseUrl).pipe(
|
||||||
|
first(),
|
||||||
|
tap((uisettings) => {
|
||||||
|
Object.assign(this.settings, uisettings.settings)
|
||||||
|
this.maybeMigrateSettings()
|
||||||
|
// to update lang cookie
|
||||||
|
if (this.settings['language']?.length)
|
||||||
|
this.setLanguage(this.settings['language'])
|
||||||
|
this.currentUser = uisettings.user
|
||||||
|
this.permissionsService.initialize(
|
||||||
|
uisettings.permissions,
|
||||||
|
this.currentUser
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get displayName(): string {
|
||||||
|
return (
|
||||||
|
this.currentUser.first_name ??
|
||||||
|
this.currentUser.username ??
|
||||||
|
''
|
||||||
|
).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateAppearanceSettings(
|
||||||
|
darkModeUseSystem = null,
|
||||||
|
darkModeEnabled = null,
|
||||||
|
themeColor = null
|
||||||
|
): void {
|
||||||
|
darkModeUseSystem ??= this.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM)
|
||||||
|
darkModeEnabled ??= this.get(SETTINGS_KEYS.DARK_MODE_ENABLED)
|
||||||
|
themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR)
|
||||||
|
|
||||||
|
if (darkModeUseSystem) {
|
||||||
|
this._renderer.setAttribute(
|
||||||
|
this.document.documentElement,
|
||||||
|
'data-bs-theme',
|
||||||
|
'auto'
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._renderer.setAttribute(
|
||||||
|
this.document.documentElement,
|
||||||
|
'data-bs-theme',
|
||||||
|
darkModeEnabled ? 'dark' : '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')
|
||||||
|
}
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
'--pngx-primary',
|
||||||
|
`${+hsl.h * 360},${hsl.s * 100}%`
|
||||||
|
)
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
'--pngx-primary-lightness',
|
||||||
|
`${hsl.l * 100}%`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._renderer.removeClass(this.document.body, 'primary-dark')
|
||||||
|
this._renderer.removeClass(this.document.body, 'primary-light')
|
||||||
|
document.documentElement.style.removeProperty('--pngx-primary')
|
||||||
|
document.documentElement.style.removeProperty('--pngx-primary-lightness')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLanguageOptions(): LanguageOption[] {
|
||||||
|
// Sort languages by localized name at runtime
|
||||||
|
return LANGUAGE_OPTIONS.sort((a, b) => {
|
||||||
|
return a.name < b.name ? -1 : 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getDateLocaleOptions(): LanguageOption[] {
|
||||||
|
return [ISO_LANGUAGE_OPTION].concat(this.getLanguageOptions())
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLanguageCookieName() {
|
private getLanguageCookieName() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user