From 7151354a0c7ca9665a30ccce79d30d7f232122b1 Mon Sep 17 00:00:00 2001 From: shubhamsharma9199 Date: Mon, 19 Jan 2026 12:36:03 +0530 Subject: [PATCH] WEB-552: fix(templates) fix TinyMCE editor dark mode styling fix(templates): prevent memory leaks by cleaning up subscriptions improve --- .../create-edit-template.component.html | 18 +-- .../create-edit-template.component.ts | 117 ++++++++++------- src/main.scss | 118 +++++++++++++++--- 3 files changed, 182 insertions(+), 71 deletions(-) diff --git a/src/app/templates/create-edit-template/create-edit-template.component.html b/src/app/templates/create-edit-template/create-edit-template.component.html index 7c14399e6..85d31cbcb 100644 --- a/src/app/templates/create-edit-template/create-edit-template.component.html +++ b/src/app/templates/create-edit-template/create-edit-template.component.html @@ -99,14 +99,16 @@ - + @if (editorVisible) { + + } diff --git a/src/app/templates/create-edit-template/create-edit-template.component.ts b/src/app/templates/create-edit-template/create-edit-template.component.ts index 78312b621..bec4c8830 100644 --- a/src/app/templates/create-edit-template/create-edit-template.component.ts +++ b/src/app/templates/create-edit-template/create-edit-template.component.ts @@ -7,7 +7,8 @@ */ /** Angular Imports */ -import { Component, OnInit, ViewChild, inject } from '@angular/core'; +import { Component, OnInit, ViewChild, inject, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { UntypedFormGroup, UntypedFormBuilder, @@ -23,6 +24,7 @@ import { clientParameterLabels, loanParameterLabels, repaymentParameterLabels } /** Custom Services */ import { TemplatesService } from '../templates.service'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { ThemingService } from 'app/shared/theme-toggle/theming.service'; import { EditorComponent, EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; import { MatAccordion, @@ -60,22 +62,34 @@ export class CreateEditComponent implements OnInit { private route = inject(ActivatedRoute); private router = inject(Router); private templateService = inject(TemplatesService); + private themingService = inject(ThemingService); + private destroyRef = inject(DestroyRef); - /** TinyMCE instance configuration */ - tinymceConfig = { - base_url: 'assets/tinymce', - suffix: '.min', - menubar: false, - branding: false, - height: 320, - forced_root_block: false, - statusbar: false, - elementpath: false, - resize: false, - plugins: 'lists link table media codesample', - toolbar: - 'undo redo | blocks | bold italic underline | link | numlist bullist outdent indent | alignleft aligncenter alignright alignjustify | table media | removeformat' - }; + themeKey = 'light'; + + editorVisible = true; + + get tinymceConfig() { + const isDark = this.themeKey === 'dark-theme'; + return { + base_url: 'assets/tinymce', + suffix: '.min', + menubar: false, + branding: false, + height: 320, + forced_root_block: false, + statusbar: false, + elementpath: false, + resize: false, + skin: isDark ? 'oxide-dark' : 'oxide', + content_css: isDark ? 'dark' : 'default', + content_style: isDark ? 'body { background-color: transparent !important; }' : '', + body_class: isDark ? 'dark-theme' : '', + plugins: 'lists link table media codesample', + toolbar: + 'undo redo | blocks | bold italic underline | link | numlist bullist outdent indent | alignleft aligncenter alignright alignjustify | table media | removeformat' + }; + } /** TinyMCE component reference */ @ViewChild('tinymceEditor', { static: false }) tinymceEditor: EditorComponent; @@ -105,16 +119,24 @@ export class CreateEditComponent implements OnInit { * @param {TemplateService} templateService Templates Service */ constructor() { - this.route.data.subscribe((data: { templateData: any; mode: 'create' | 'edit' }) => { - this.templateData = data.templateData; - this.mode = data.mode; - if (this.mode === 'edit') { - this.mappers = this.templateData.template.mappers.map((mapper: any) => ({ - mappersorder: mapper.mapperorder, - mapperskey: new UntypedFormControl(mapper.mapperkey), - mappersvalue: new UntypedFormControl(mapper.mappervalue) - })); - } + this.route.data + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((data: { templateData: any; mode: 'create' | 'edit' }) => { + this.templateData = data.templateData; + this.mode = data.mode; + if (this.mode === 'edit') { + this.mappers = this.templateData.template.mappers.map((mapper: any) => ({ + mappersorder: mapper.mapperorder, + mapperskey: new UntypedFormControl(mapper.mapperkey), + mappersvalue: new UntypedFormControl(mapper.mappervalue) + })); + } + }); + + this.themingService.theme.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((theme) => { + this.themeKey = theme; + this.editorVisible = false; + setTimeout(() => (this.editorVisible = true)); }); } @@ -173,25 +195,30 @@ export class CreateEditComponent implements OnInit { */ buildDependencies() { const tenantIdentifier = 'default'; // update once global settings are setup. - this.templateForm.get('entity').valueChanges.subscribe((value: any) => { - if (value === 0) { - // client - this.mappers.splice(0, 1, { - mappersorder: 0, - mapperskey: new UntypedFormControl('client'), - mappersvalue: new UntypedFormControl('clients/{{clientId}}?tenantIdentifier=' + tenantIdentifier) - }); - } else { - // loan - this.mappers.splice(0, 1, { - mappersorder: 0, - mapperskey: new UntypedFormControl('loan'), - mappersvalue: new UntypedFormControl('loans/{{loanId}}?associations=all&tenantIdentifier=' + tenantIdentifier) - }); - } - this.setEditorContent(''); - this.templateForm.get('text').setValue(''); - }); + this.templateForm + .get('entity') + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((value: any) => { + if (value === 0) { + // client + this.mappers.splice(0, 1, { + mappersorder: 0, + mapperskey: new UntypedFormControl('client'), + mappersvalue: new UntypedFormControl('clients/{{clientId}}?tenantIdentifier=' + tenantIdentifier) + }); + } else { + // loan + this.mappers.splice(0, 1, { + mappersorder: 0, + mapperskey: new UntypedFormControl('loan'), + mappersvalue: new UntypedFormControl( + 'loans/{{loanId}}?associations=all&tenantIdentifier=' + tenantIdentifier + ) + }); + } + this.setEditorContent(''); + this.templateForm.get('text').setValue(''); + }); if (this.mode === 'create') { this.templateForm.get('entity').patchValue(0); } diff --git a/src/main.scss b/src/main.scss index b86c32818..98f8d19cf 100644 --- a/src/main.scss +++ b/src/main.scss @@ -147,7 +147,7 @@ } .responsive-column { - @media (width <= 768px) { + @media (width <=768px) { flex-direction: column; } } @@ -235,13 +235,13 @@ } .layout-gt-sm-row { - @media (width >= 600px) { + @media (width >=600px) { flex-direction: row; } } .align-gt-sm-start-center { - @media (width >= 600px) { + @media (width >=600px) { justify-content: flex-start; align-items: center; } @@ -369,7 +369,7 @@ flex: 0 0 48%; } -@media (width <= 768px) { +@media (width <=768px) { .hide-lt-md { display: none !important; } @@ -442,21 +442,21 @@ flex: 0 0 96%; } -@media screen and (width <= 599px) { +@media screen and (width <=599px) { .flex-xs-15 { flex: 0 0 15%; max-width: 15%; } } -@media screen and (width >= 600px) and (width <= 959px) { +@media screen and (width >=600px) and (width <=959px) { .flex-sm-10 { flex: 0 0 10%; max-width: 10%; } } -@media screen and (width >= 960px) and (width <= 1279px) { +@media screen and (width >=960px) and (width <=1279px) { .flex-md-5 { flex: 0 0 5%; max-width: 5%; @@ -464,7 +464,7 @@ } .hide-lt-sm { - @media (width <= 599px) { + @media (width <=599px) { display: none !important; } } @@ -548,24 +548,24 @@ } .flex-gt-sm-30 { - @media (width >= 600px) { + @media (width >=600px) { flex: 1 0 30%; } } -@media (width <= 1199px) { +@media (width <=1199px) { .hide-lt-lg { display: none !important; } } -@media (width <= 768px) { +@media (width <=768px) { .flex-25 { flex: 0 0 50%; } } -@media (width <= 599px) { +@media (width <=599px) { .layout-xs-column { flex-direction: column; } @@ -584,19 +584,19 @@ } .layout-lt-md-column { - @media (width <= 768px) { + @media (width <=768px) { flex-direction: column; } } .layout-column.lt-md { - @media (width <= 599px) { + @media (width <=599px) { flex-direction: column !important; } } .responsive-flex-full { - @media (width <= 768px) { + @media (width <=768px) { flex: 0 0 100% !important; } } @@ -617,19 +617,19 @@ } } -@media (width <= 768px) { +@media (width <=768px) { .flex-lt-md-50 { flex: 0 0 50%; } } -@media (width <= 768px) { +@media (width <=768px) { .flex-50-lt-md { flex: 0 0 50%; } } -@media (width <= 599px) { +@media (width <=599px) { .layout-column-xs { flex-direction: column !important; } @@ -719,3 +719,85 @@ mat-card { overflow: hidden; } } + +.dark-theme { + .tox.tox-tinymce { + border-color: #444 !important; + } + + .tox .tox-editor-header, + .tox .tox-toolbar-overlord, + .tox .tox-toolbar, + .tox .tox-toolbar__overflow, + .tox .tox-toolbar__primary { + background-color: #303135 !important; + } + + .tox .tox-tbtn { + background-color: transparent !important; + color: rgb(255 255 255 / 87%) !important; + + svg { + fill: rgb(255 255 255 / 87%) !important; + } + + &:hover { + background-color: rgb(255 255 255 / 12%) !important; + } + + &:focus { + background-color: rgb(255 255 255 / 8%) !important; + } + } + + .tox .tox-tbtn--bevel { + background: transparent !important; + } + + .tox .tox-tbtn--select { + background-color: transparent !important; + } + + .tox .tox-split-button { + background-color: transparent !important; + + &:hover { + box-shadow: none !important; + } + } + + .tox .tox-edit-area { + background-color: #303135 !important; + + iframe { + background-color: transparent !important; + } + } + + .tox .tox-sidebar-wrap { + background-color: #303135 !important; + } + + .tox .tox-menubar { + background-color: #303135 !important; + } + + .tox .tox-menu { + background-color: #303135 !important; + border-color: #444 !important; + } + + .tox .tox-collection__item { + color: rgb(255 255 255 / 87%) !important; + + &:hover { + background-color: rgb(255 255 255 / 8%) !important; + } + } + + .tox .tox-statusbar { + background-color: #303135 !important; + border-color: #444 !important; + color: rgb(255 255 255 / 60%) !important; + } +}