diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html index 33773a73d890456af91f0b9d5d8ed73fcba2c751..2843f20cc1ecb6e0fbd6e7c0821530ff3e0e56f3 100644 --- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html +++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html @@ -11,7 +11,7 @@ {{'spacy-dialog.' + (languagetoolService.mapLanguageToSpacyModel(grammarChecker.selectedLang)) | translate}} </span> <span *ngIf="(grammarChecker.selectedLang === 'auto')" - id="langSelect"> + #langSelect> auto </span> <mat-select class="select-list" diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.scss b/src/app/components/shared/_dialogs/create-comment/create-comment.component.scss index b86942584f208f46452b703fbc915294dc352e9e..49db67e66622737f4548f9083baed326d50c9fe4 100644 --- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.scss +++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.scss @@ -27,7 +27,8 @@ app-comment-list { outline: none; } } -.spell-button{ + +.spell-button { background-color: var(--primary); color: var(--on-primary); margin-top: 1rem; @@ -37,21 +38,24 @@ app-comment-list { color: var(--on-primary); background-color: var(--primary); } -::ng-deep .mat-select-value{ - width: auto!important; + +::ng-deep .mat-select-value { + width: auto !important; } -.material-icons{ +.material-icons { margin-right: 18px; } -.select-list{ +.select-list { width: calc(100% - 24px); } + .lang-selection { vertical-align: middle; margin-right: 0; } + mat-hint { color: var(--on-surface) !important; } @@ -65,43 +69,43 @@ mat-hint { color: var(--on-surface); } -.tag-form-field{ - @media screen and (max-width:500px) { - width:70px; +.tag-form-field { + @media screen and (max-width: 500px) { + width: 70px; } - z-index:10000; + z-index: 10000; } -.anchor-right{ - @media screen and (max-width:500px) { - width:70px; - left:calc( 100% - 70px ); +.anchor-right { + @media screen and (max-width: 500px) { + width: 70px; + left: calc(100% - 70px); } - width:200px; - height:50px; - position:relative; - left:calc( 100% - 200px ); - top:0; + width: 200px; + height: 50px; + position: relative; + left: calc(100% - 200px); + top: 0; } -.anchor-wrp{ - width:100%; - height:0; - position:relative; - left:0; - top:0; +.anchor-wrp { + width: 100%; + height: 0; + position: relative; + left: 0; + top: 0; } ::ng-deep .mat-form-field-label { - color: var(--on-surface)!important; + color: var(--on-surface) !important; } ::ng-deep .mat-form-field-underline { - background-color: var(--on-surface)!important; + background-color: var(--on-surface) !important; } ::ng-deep .mat-form-field-ripple { - background-color: var(--on-surface)!important; + background-color: var(--on-surface) !important; } ::ng-deep .mat-select-arrow-wrapper .mat-select-arrow { @@ -142,21 +146,43 @@ mat-hint { } @keyframes shake { - 0% { transform: translate(1px, 1px) rotate(0deg); } - 10% { transform: translate(0px, 0) rotate(-1deg); } - 20% { transform: translate(0px, 0px) rotate(1deg); } - 30% { transform: translate(3px, 2px) rotate(0deg); } - 40% { transform: translate(1px, 0) rotate(1deg); } - 50% { transform: translate(-1px, 2px) rotate(-1deg); } - 60% { transform: translate(-1px, 1px) rotate(0deg); } - 70% { transform: translate(3px, 1px) rotate(-1deg); } - 80% { transform: translate(-1px, 0) rotate(1deg); } - 90% { transform: translate(1px, 2px) rotate(0deg); } - 100% { transform: translate(1px, -0) rotate(-1deg); } + 0% { + transform: translate(1px, 1px) rotate(0deg); + } + 10% { + transform: translate(0px, 0) rotate(-1deg); + } + 20% { + transform: translate(0px, 0px) rotate(1deg); + } + 30% { + transform: translate(3px, 2px) rotate(0deg); + } + 40% { + transform: translate(1px, 0) rotate(1deg); + } + 50% { + transform: translate(-1px, 2px) rotate(-1deg); + } + 60% { + transform: translate(-1px, 1px) rotate(0deg); + } + 70% { + transform: translate(3px, 1px) rotate(-1deg); + } + 80% { + transform: translate(-1px, 0) rotate(1deg); + } + 90% { + transform: translate(1px, 2px) rotate(0deg); + } + 100% { + transform: translate(1px, -0) rotate(-1deg); + } } .spellcheck { - @media screen and (max-width:500px) { + @media screen and (max-width: 500px) { overflow: auto; display: flex; justify-content: space-between; @@ -173,3 +199,46 @@ mat-hint { .mat-flat-button.mat-primary.mat-button-disabled, .mat-flat-button.mat-accent.mat-button-disabled, .mat-flat-button.mat-warn.mat-button-disabled, .mat-flat-button.mat-button-disabled.mat-button-disabled, .mat-raised-button.mat-primary.mat-button-disabled, .mat-raised-button.mat-accent.mat-button-disabled, .mat-raised-button.mat-warn.mat-button-disabled, .mat-raised-button.mat-button-disabled.mat-button-disabled, .mat-fab.mat-primary.mat-button-disabled, .mat-fab.mat-accent.mat-button-disabled, .mat-fab.mat-warn.mat-button-disabled, .mat-fab.mat-button-disabled.mat-button-disabled, .mat-mini-fab.mat-primary.mat-button-disabled, .mat-mini-fab.mat-accent.mat-button-disabled, .mat-mini-fab.mat-warn.mat-button-disabled, .mat-mini-fab.mat-button-disabled.mat-button-disabled { display: none; } + +/* +Suggestion classes from Languagetool + */ + +::ng-deep .markUp { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; + + > span { + text-decoration: underline wavy red; + cursor: pointer; + } + + > .dropdownBlock { + display: none; + width: 160px; + background-color: white; + border-style: solid; + border-color: var(--primary); + color: #fff; + text-align: center; + border-radius: 6px; + padding: 5px 0; + position: absolute; + z-index: 1000; + bottom: 100%; + + > .suggestions { + color: black; + display: block; + text-align: center; + cursor: pointer; + } + + > .error-message { + color: black; + display: block; + text-align: center; + } + } +} diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts index b282c5bef015098eae6c0afbd0c495dc958234a6..9f6e1e905f81cd6c5cf903008627727ccd52c3d6 100644 --- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts +++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; import { Comment, Language as CommentLanguage } from '../../../../models/comment'; import { NotificationService } from '../../../../services/util/notification.service'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; @@ -16,7 +16,10 @@ import { GrammarChecker } from '../../../../utils/grammar-checker'; templateUrl: './create-comment.component.html', styleUrls: ['./create-comment.component.scss'] }) -export class CreateCommentComponent implements OnInit { +export class CreateCommentComponent implements OnInit, AfterViewInit { + + @ViewChild('langSelect') langSelect: ElementRef<HTMLDivElement>; + @ViewChild('commentBody') commentBody: ElementRef<HTMLDivElement>; comment: Comment; user: User; @@ -36,13 +39,17 @@ export class CreateCommentComponent implements OnInit { public languagetoolService: LanguagetoolService, public eventService: EventService, @Inject(MAT_DIALOG_DATA) public data: any) { - this.grammarChecker = new GrammarChecker(languagetoolService); + this.grammarChecker = new GrammarChecker(this.languagetoolService); } ngOnInit() { this.translateService.use(localStorage.getItem('currentLang')); } + ngAfterViewInit() { + this.grammarChecker.initBehavior(() => this.commentBody.nativeElement, () => this.langSelect.nativeElement); + } + onNoClick(): void { this.dialogRef.close(); } diff --git a/src/app/components/shared/comment-answer/comment-answer.component.html b/src/app/components/shared/comment-answer/comment-answer.component.html index edae65f082f0f55c345302ce3e0615ea2da0c612..3bd13050ea0a82d1a0d290f1d5f6f025c1f90768 100644 --- a/src/app/components/shared/comment-answer/comment-answer.component.html +++ b/src/app/components/shared/comment-answer/comment-answer.component.html @@ -33,7 +33,7 @@ <span *ngIf="!(grammarChecker.selectedLang === 'auto')"> {{'spacy-dialog.' + (languagetoolService.mapLanguageToSpacyModel(grammarChecker.selectedLang)) | translate}} </span> - <span *ngIf="(grammarChecker.selectedLang === 'auto')" id="langSelect"> + <span *ngIf="(grammarChecker.selectedLang === 'auto')" #langSelect> auto </span> <mat-select class="select-list" #select [(ngModel)]="grammarChecker.selectedLang"> diff --git a/src/app/components/shared/comment-answer/comment-answer.component.scss b/src/app/components/shared/comment-answer/comment-answer.component.scss index f31022bbb39c606d4c89c3c11b99f696f7e525ca..9229ee94d2f9bf98c52a871549bb5a191b098232 100644 --- a/src/app/components/shared/comment-answer/comment-answer.component.scss +++ b/src/app/components/shared/comment-answer/comment-answer.component.scss @@ -114,3 +114,46 @@ mat-icon { .mat-flat-button.mat-primary.mat-button-disabled, .mat-flat-button.mat-accent.mat-button-disabled, .mat-flat-button.mat-warn.mat-button-disabled, .mat-flat-button.mat-button-disabled.mat-button-disabled, .mat-raised-button.mat-primary.mat-button-disabled, .mat-raised-button.mat-accent.mat-button-disabled, .mat-raised-button.mat-warn.mat-button-disabled, .mat-raised-button.mat-button-disabled.mat-button-disabled, .mat-fab.mat-primary.mat-button-disabled, .mat-fab.mat-accent.mat-button-disabled, .mat-fab.mat-warn.mat-button-disabled, .mat-fab.mat-button-disabled.mat-button-disabled, .mat-mini-fab.mat-primary.mat-button-disabled, .mat-mini-fab.mat-accent.mat-button-disabled, .mat-mini-fab.mat-warn.mat-button-disabled, .mat-mini-fab.mat-button-disabled.mat-button-disabled { display: none; } + +/* +Suggestion classes from Languagetool + */ + +::ng-deep .markUp { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; + + > span { + text-decoration: underline wavy red; + cursor: pointer; + } + + > .dropdownBlock { + display: none; + width: 160px; + background-color: white; + border-style: solid; + border-color: var(--primary); + color: #fff; + text-align: center; + border-radius: 6px; + padding: 5px 0; + position: absolute; + z-index: 1000; + bottom: 100%; + + > .suggestions { + color: black; + display: block; + text-align: center; + cursor: pointer; + } + + > .error-message { + color: black; + display: block; + text-align: center; + } + } +} diff --git a/src/app/components/shared/comment-answer/comment-answer.component.ts b/src/app/components/shared/comment-answer/comment-answer.component.ts index 14c8144cc208f67ac064627505e84decd4685388..22539f734bc37be9c10a65d269002678f82195a0 100644 --- a/src/app/components/shared/comment-answer/comment-answer.component.ts +++ b/src/app/components/shared/comment-answer/comment-answer.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { LanguageService } from '../../../services/util/language.service'; @@ -20,7 +20,10 @@ import { EventService } from '../../../services/util/event.service'; templateUrl: './comment-answer.component.html', styleUrls: ['./comment-answer.component.scss'] }) -export class CommentAnswerComponent implements OnInit { +export class CommentAnswerComponent implements OnInit, AfterViewInit { + + @ViewChild('langSelect') langSelect: ElementRef<HTMLSpanElement>; + @ViewChild('commentBody') commentBody: ElementRef<HTMLDivElement>; comment: Comment; answer: string; @@ -32,8 +35,6 @@ export class CommentAnswerComponent implements OnInit { grammarChecker: GrammarChecker; tempEditView: string; - @ViewChild('commentBody') commentBody: ElementRef<HTMLDivElement>; - constructor(protected route: ActivatedRoute, private notificationService: NotificationService, private translateService: TranslateService, @@ -62,6 +63,10 @@ export class CommentAnswerComponent implements OnInit { }); } + ngAfterViewInit() { + this.grammarChecker.initBehavior(() => this.commentBody.nativeElement, () => this.langSelect.nativeElement); + } + saveAnswer() { this.edit = !this.answer; this.commentService.answer(this.comment, this.answer).subscribe(); diff --git a/src/app/components/shared/footer/footer.component.ts b/src/app/components/shared/footer/footer.component.ts index 6cba039d5c54209b096782eb9ae1d556d9de4149..ce858113a5af58684f945f48a91034c12ab2a8fb 100644 --- a/src/app/components/shared/footer/footer.component.ts +++ b/src/app/components/shared/footer/footer.component.ts @@ -71,17 +71,6 @@ export class FooterComponent implements OnInit { }); }); this.deviceType = localStorage.getItem('deviceType'); - if (!this.themeService.getThemeByKey(this.themeClass) || !this.themeService.getTheme()['source']['_value']) { - if (this.deviceType === 'mobile') { - this.themeService.activate('dark'); - this.themeClass = 'dark'; - } else { - // this.themeService.activate('arsnova'); - // this.themeClass = 'arsnova'; - this.themeService.activate('dark'); - this.themeClass = 'dark'; - } - } this.styleService.setColor(this.themeService.getThemeByKey(this.themeClass).isDark); this.translateService.use(localStorage.getItem('currentLang')); this.translateService.get('footer.open').subscribe(message => { diff --git a/src/app/utils/grammar-checker.ts b/src/app/utils/grammar-checker.ts index 598d1835794831629e6556eb1cb62193cd33e2ec..50ea034c5d84ef2d6f182aaec894517baef635b8 100644 --- a/src/app/utils/grammar-checker.ts +++ b/src/app/utils/grammar-checker.ts @@ -1,4 +1,4 @@ -import { Language, LanguagetoolService } from '../services/http/languagetool.service'; +import { Language, LanguagetoolResult, LanguagetoolService } from '../services/http/languagetool.service'; import { CreateCommentKeywords } from './create-comment-keywords'; export class GrammarChecker { @@ -9,9 +9,17 @@ export class GrammarChecker { hasSpellcheckConfidence = true; newLang = 'auto'; + private commentBody: () => HTMLDivElement; + private langSelect: () => HTMLSpanElement; + constructor(private languagetoolService: LanguagetoolService) { } + initBehavior(commentBody: () => HTMLDivElement, langSelect: () => HTMLSpanElement) { + this.commentBody = commentBody; + this.langSelect = langSelect; + } + onDocumentClick(e) { const container = document.getElementsByClassName('dropdownBlock'); Array.prototype.forEach.call(container, (elem) => { @@ -35,17 +43,18 @@ export class GrammarChecker { onPaste(e) { e.preventDefault(); - const elem = document.getElementById('answer-input'); const text = e.clipboardData.getData('text'); - elem.innerText += text.replace(/<[^>]*>?/gm, ''); - + const selection = window.getSelection(); + const min = Math.min(selection.anchorOffset, selection.focusOffset); + const max = Math.max(selection.anchorOffset, selection.focusOffset); + const content = selection.anchorNode.textContent; + selection.anchorNode.textContent = content.substring(0, min) + text + content.substr(max); const range = document.createRange(); - range.setStart(elem.lastChild, elem.lastChild.textContent.length); + const elem = selection.anchorNode instanceof HTMLElement ? selection.anchorNode.lastChild : selection.anchorNode; + range.setStart(elem, min + text.length); range.collapse(true); - - const sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); + selection.removeAllRanges(); + selection.addRange(range); } grammarCheck(commentBody: HTMLDivElement): void { @@ -62,8 +71,8 @@ export class GrammarChecker { this.hasSpellcheckConfidence = false; return; } - if (this.selectedLang === 'auto' && (document.getElementById('langSelect').innerText.includes(this.newLang) - || document.getElementById('langSelect').innerText.includes('auto'))) { + if (this.selectedLang === 'auto' && (this.langSelect().innerText.includes(this.newLang) + || this.langSelect().innerText.includes('auto'))) { if (wordsCheck.language.name.includes('German')) { this.selectedLang = 'de-DE'; } else if (wordsCheck.language.name.includes('English')) { @@ -73,7 +82,7 @@ export class GrammarChecker { } else { this.newLang = wordsCheck.language.name; } - document.getElementById('langSelect').innerHTML = this.newLang; + this.langSelect().innerHTML = this.newLang; } if (wordsCheck.matches.length <= 0) { return; @@ -83,9 +92,9 @@ export class GrammarChecker { wrongWords.push(wrongWord); }); - let html = ''; let lastFound = unfilteredText.length; this.checkSpellings(unfilteredText).subscribe((res) => { + commentBody.innerHTML = ''; for (let i = res.matches.length - 1; i >= 0; i--) { const end = res.matches[i].offset + res.matches[i].length; const start = res.matches[i].offset; @@ -95,67 +104,15 @@ export class GrammarChecker { continue; } - const suggestions: any[] = res.matches[i].replacements; - let displayOptions = 3; - let suggestionsHTML = ''; - - if (!suggestions.length) { - suggestionsHTML = '<span style="color: black; display: block; text-align: center;">' + res.matches[i].message + '</span>'; - } - - if (suggestions.length < displayOptions) { - displayOptions = suggestions.length; - } - - for (let j = 0; j < displayOptions; j++) { - // eslint-disable-next-line max-len - suggestionsHTML += '<span class="suggestions"' + ' style="color: black; display: block; text-align: center; cursor: pointer;">' + suggestions[j].value + '</span>'; + if (lastFound > end) { + commentBody.prepend(unfilteredText.slice(end, lastFound)); } - - const replacement = - '<div class="markUp" data-id="' + i + '" style="position: relative; display: inline-block; border-bottom: 1px dotted black">' + - '<span data-id="' + i + '" style="text-decoration: underline wavy red; cursor: pointer;">' + - wrongWord + - '</span>' + - // eslint-disable-next-line max-len - '<div class="dropdownBlock" style="display: none; width: 160px; background-color: white; border-style: solid; border-color: var(--primary); color: #fff; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1000; bottom: 100%;">' + - suggestionsHTML + - '</div>' + - '</div>'; - - html = replacement + unfilteredText.slice(end, lastFound) + html; + commentBody.prepend(this.createSuggestionHTML(res, i, wrongWord)); lastFound = res.matches[i].offset; } - commentBody.innerHTML = unfilteredText.slice(0, lastFound) + html; - - setTimeout(() => { - Array.from(document.getElementsByClassName('markUp')).forEach((markup: HTMLElement) => { - markup.addEventListener('click', () => { - const lastChild = markup.lastChild as HTMLElement; - lastChild.style.display = 'block'; - const rectdiv = (document.getElementById('answer-input')).getBoundingClientRect(); - const rectmarkup = markup.getBoundingClientRect(); - let offset; - if (rectmarkup.x + rectmarkup.width / 2 > rectdiv.right - 80) { - offset = rectdiv.right - rectmarkup.x - rectmarkup.width; - lastChild.style.right = -offset + 'px'; - } else if (rectmarkup.x + rectmarkup.width / 2 < rectdiv.left + 80) { - offset = rectmarkup.x - rectdiv.left; - lastChild.style.left = -offset + 'px'; - } else { - lastChild.style.left = '50%'; - lastChild.style.marginLeft = '-80px'; - } - setTimeout(() => { - Array.from(document.getElementsByClassName('suggestions')).forEach(suggestion => { - suggestion.addEventListener('click', () => { - suggestion.parentElement.parentElement.outerHTML = suggestion.innerHTML; - }); - }); - }, 500); - }); - }); - }, 500); + if (lastFound > 0) { + commentBody.prepend(unfilteredText.slice(0, lastFound)); + } }); }, () => '', () => { this.isSpellchecking = false; @@ -169,4 +126,52 @@ export class GrammarChecker { checkSpellings(text: string, language: Language = this.selectedLang) { return this.languagetoolService.checkSpellings(text, language); } + + private createSuggestionHTML(result: LanguagetoolResult, index: number, wrongWord: string) { + const markUpDiv = document.createElement('div'); + markUpDiv.classList.add('markUp'); + markUpDiv.dataset.id = String(index); + const wordMarker = document.createElement('span'); + wordMarker.dataset.id = String(index); + wordMarker.append(wrongWord); + markUpDiv.append(wordMarker); + const dropDownDiv = document.createElement('div'); + dropDownDiv.classList.add('dropdownBlock'); + markUpDiv.append(dropDownDiv); + markUpDiv.addEventListener('click', () => { + dropDownDiv.style.display = 'block'; + const rectdiv = this.commentBody().getBoundingClientRect(); + const rectmarkup = markUpDiv.getBoundingClientRect(); + let offset; + if (rectmarkup.x + rectmarkup.width / 2 > rectdiv.right - 80) { + offset = rectdiv.right - rectmarkup.x - rectmarkup.width; + dropDownDiv.style.right = -offset + 'px'; + } else if (rectmarkup.x + rectmarkup.width / 2 < rectdiv.left + 80) { + offset = rectmarkup.x - rectdiv.left; + dropDownDiv.style.left = -offset + 'px'; + } else { + dropDownDiv.style.left = '50%'; + dropDownDiv.style.marginLeft = '-80px'; + } + }); + const suggestions = result.matches[index].replacements; + if (!suggestions.length) { + const elem = document.createElement('span'); + elem.classList.add('error-message'); + elem.append(result.matches[index].message); + dropDownDiv.append(elem); + } else { + const length = suggestions.length > 3 ? 3 : suggestions.length; + for (let j = 0; j < length; j++) { + const elem = document.createElement('span'); + elem.classList.add('suggestions'); + elem.append(suggestions[j].value); + elem.addEventListener('click', () => { + elem.parentElement.parentElement.outerHTML = suggestions[j].value; + }); + dropDownDiv.append(elem); + } + } + return markUpDiv; + } } diff --git a/src/theme/blue-theme/blueTheme.const.ts b/src/theme/blue-theme/blueTheme.const.ts index c6f81ec8f2604fcdd8eb2c0ec904b4d1e29e68cf..0a931c7373de92c158462b32792489814ef04b86 100644 --- a/src/theme/blue-theme/blueTheme.const.ts +++ b/src/theme/blue-theme/blueTheme.const.ts @@ -41,6 +41,7 @@ export const blue_meta = { }, }, isDark: false, + availableOnMobile: true, order: 4, scale_desktop: 1, scale_mobile: 1, diff --git a/src/theme/dark-theme/darkTheme.const.ts b/src/theme/dark-theme/darkTheme.const.ts index 71803ea98a88c933dcd45ca36c88a51d2c77f8ee..27b5bc5a7f7035d20fdcf1cbe994cdc283b98169 100644 --- a/src/theme/dark-theme/darkTheme.const.ts +++ b/src/theme/dark-theme/darkTheme.const.ts @@ -44,6 +44,7 @@ export const dark_meta = { }, }, isDark: true, + availableOnMobile: true, order: 2, scale_desktop: 1.2, scale_mobile: 1, diff --git a/src/theme/high-contrast-theme/highContrastTheme.const.ts b/src/theme/high-contrast-theme/highContrastTheme.const.ts index 0dc384b6c82c462cffb4a2e997f46b5402dff437..8ff2bcbdaa6db08740262815ca3b85ed8190a4a2 100644 --- a/src/theme/high-contrast-theme/highContrastTheme.const.ts +++ b/src/theme/high-contrast-theme/highContrastTheme.const.ts @@ -44,6 +44,7 @@ export const highcontrast_meta = { }, }, isDark: true, + availableOnMobile: true, order: 0, scale_desktop: 1.2, scale_mobile: 1, diff --git a/src/theme/light-theme/light-theme.ts b/src/theme/light-theme/light-theme.ts index e46686886251ee7eb3b4c50bf001384c25a97971..5eb62956c9147c02b5077f162d111a1a8a0d1f62 100644 --- a/src/theme/light-theme/light-theme.ts +++ b/src/theme/light-theme/light-theme.ts @@ -1,6 +1,6 @@ export const arsnova = { - '--primary' : 'green', + '--primary': 'green', '--primary-variant': 'LightGoldenrodYellow', '--secondary': 'maroon', @@ -44,6 +44,7 @@ export const arsnova_meta = { }, }, isDark: false, + availableOnMobile: true, order: 3, scale_desktop: 1.2, scale_mobile: 1, diff --git a/src/theme/purple-theme/purpleTheme.const.ts b/src/theme/purple-theme/purpleTheme.const.ts index 5039483b7fa00e5d8b3610648eda23b00eb8c1d5..1e60f396d0406d473e98301c3bce58c749055614 100644 --- a/src/theme/purple-theme/purpleTheme.const.ts +++ b/src/theme/purple-theme/purpleTheme.const.ts @@ -44,6 +44,7 @@ export const purple_meta = { }, }, isDark: false, + availableOnMobile: false, order: 1, scale_desktop: 1.5, scale_mobile: 1, diff --git a/src/theme/theme.directive.ts b/src/theme/theme.directive.ts index 40d08c6e9faecb15ffb2e396a8e1cf3b9813e3ca..b175ba97362385e711c0f461622713c96c5fff1b 100644 --- a/src/theme/theme.directive.ts +++ b/src/theme/theme.directive.ts @@ -10,7 +10,7 @@ import { Subscription } from 'rxjs'; export class ThemeDirective implements OnInit, OnDestroy { - private themeName = 'dark'; + private themeName; private themServiceSubscription: Subscription; constructor(private elementRef: ElementRef, @@ -20,7 +20,6 @@ export class ThemeDirective implements OnInit, OnDestroy { } ngOnInit() { - this.updateTheme(this.themeName); this.themService.getTheme() .subscribe(themeName => { this.themeName = themeName; @@ -29,7 +28,7 @@ export class ThemeDirective implements OnInit, OnDestroy { } updateTheme(themeName: string) { - const them = themes[ themeName ]; + const them = themes[themeName]; for (const key in them) { if (them.hasOwnProperty(key)) { this.renderer.setProperty(this.elementRef.nativeElement, key, them[key]); diff --git a/src/theme/theme.service.ts b/src/theme/theme.service.ts index e541a0f282f194b5129b9c42dada89494981c173..6dc7382533b73cf0ec0e25e83563515fef323257 100644 --- a/src/theme/theme.service.ts +++ b/src/theme/theme.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { themes, themes_meta } from './arsnova-theme.const'; -import { Theme, ThemeTranslationList } from './Theme'; +import { Theme } from './Theme'; @Injectable({ providedIn: 'root' @@ -12,8 +12,12 @@ export class ThemeService { private themes: Theme[] = []; constructor() { + const isMobile = window.matchMedia && window.matchMedia('(max-width: 499px)').matches; // eslint-disable-next-line guard-for-in for (const k in themes) { + if (!themes_meta[k].availableOnMobile && isMobile) { + continue; + } this.themes.push(new Theme( k, themes[k], @@ -28,6 +32,17 @@ export class ThemeService { } return 0; }); + if (!this.themeName) { + const isDark = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)').matches : true; + for (let i = this.themes.length - 1; i > 0; i--) { + const theme = this.themes[i]; + if (theme.isDark === isDark) { + this.themeName = theme.key; + break; + } + } + this.activate(this.themeName); + } } public getTheme() {