forked from EVOgeek/Vmeda.Online
		
	Merge pull request #4252 from crazyserver/MOBILE-4653
MOBILE-4653 core: Add site logo component
This commit is contained in:
		
						commit
						d9a64ff99b
					
				@ -98,6 +98,7 @@
 | 
			
		||||
    "enableonboarding": true,
 | 
			
		||||
    "forceColorScheme": "",
 | 
			
		||||
    "forceLoginLogo": false,
 | 
			
		||||
    "showTopLogo": "hidden",
 | 
			
		||||
    "ioswebviewscheme": "moodleappfs",
 | 
			
		||||
    "appstores": {
 | 
			
		||||
        "android": "com.moodle.moodlemobile",
 | 
			
		||||
 | 
			
		||||
@ -163,7 +163,7 @@ export class CoreUnauthenticatedSite {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether the app should use the local logo instead of the remote one.
 | 
			
		||||
     * Check whether the app should use the local logo instead or the remote one.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Whether local logo is forced.
 | 
			
		||||
     */
 | 
			
		||||
@ -180,10 +180,34 @@ export class CoreUnauthenticatedSite {
 | 
			
		||||
    getLogoUrl(config?: CoreSitePublicConfigResponse): string | undefined {
 | 
			
		||||
        config = config ?? this.publicConfig;
 | 
			
		||||
        if (!config || this.forcesLocalLogo()) {
 | 
			
		||||
            return 'assets/img/login_logo.png';
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return config.logourl || config.compactlogourl || 'assets/img/login_logo.png';
 | 
			
		||||
        return config.logourl || config.compactlogourl || undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check show top logo mode.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns The top logo mode.
 | 
			
		||||
     */
 | 
			
		||||
    getShowTopLogo(): 'online' | 'offline' | 'hidden' {
 | 
			
		||||
        return this.isDemoModeSite() ? 'hidden' : CoreConstants.CONFIG.showTopLogo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get logo URL from a site public config.
 | 
			
		||||
     *
 | 
			
		||||
     * @param config Site public config.
 | 
			
		||||
     * @returns Logo URL.
 | 
			
		||||
     */
 | 
			
		||||
    getTopLogoUrl(config?: CoreSitePublicConfigResponse): string | undefined {
 | 
			
		||||
        config = config ?? this.publicConfig;
 | 
			
		||||
        if (!config || this.getShowTopLogo() !== 'online') {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return config.logourl || config.compactlogourl || undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/core/components/site-logo/site-logo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/components/site-logo/site-logo.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
<div class="core-logo-container" *ngIf="showLogo && logoLoaded">
 | 
			
		||||
    <img *ngIf="siteLogo" [src]="siteLogo" class="core-logo" [alt]="siteName" core-external-content [siteId]="siteId"
 | 
			
		||||
        (error)="imageError()">
 | 
			
		||||
    <img *ngIf="!siteLogo" [src]="fallbackLogo" class="core-logo" [alt]="siteName">
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<p *ngIf="showSiteName && siteNameMode === 'p' && siteName" class="ion-no-margin ion-no-padding core-logo-sitename">
 | 
			
		||||
    <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [siteId]="siteId" />
 | 
			
		||||
</p>
 | 
			
		||||
<core-format-text *ngIf="showSiteName && siteNameMode === '' && siteName" [text]="siteName" contextLevel="system" [contextInstanceId]="0"
 | 
			
		||||
    class="core-logo-sitename" [siteId]="siteId" />
 | 
			
		||||
<h2 *ngIf="showSiteName && siteNameMode === 'h2' && siteName" class="ion-margin-top ion-no-padding core-logo-sitename">
 | 
			
		||||
    <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [siteId]="siteId" />
 | 
			
		||||
</h2>
 | 
			
		||||
							
								
								
									
										22
									
								
								src/core/components/site-logo/site-logo.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/core/components/site-logo/site-logo.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
:host {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.core-logo-container {
 | 
			
		||||
    margin-bottom: var(--core-site-logo-margin-bottom, 0px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img.core-logo {
 | 
			
		||||
    max-height: var(--core-site-logo-max-height);
 | 
			
		||||
    max-width: var(--core-site-logo-max-width, 100%);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    width: var(--core-site-logo-width, auto);
 | 
			
		||||
    margin: var(--core-site-logo-margin, 0px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.core-logo-sitename {
 | 
			
		||||
    display: var(--core-site-logo-sitename-display, block);
 | 
			
		||||
    font: var(--core-site-logo-sitename-font);
 | 
			
		||||
    margin-bottom: var(--core-site-logo-sitename-margin-bottom, 0px);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										131
									
								
								src/core/components/site-logo/site-logo.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/core/components/site-logo/site-logo.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,131 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreSite } from '@classes/sites/site';
 | 
			
		||||
import { toBoolean } from '@/core/transforms/boolean';
 | 
			
		||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
			
		||||
import { CoreUnauthenticatedSite } from '@classes/sites/unauthenticated-site';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to render the current site logo.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'core-site-logo',
 | 
			
		||||
    templateUrl: 'site-logo.html',
 | 
			
		||||
    styleUrl: 'site-logo.scss',
 | 
			
		||||
    standalone: true,
 | 
			
		||||
    imports: [CoreSharedModule],
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
export class CoreSiteLogoComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @Input({ transform: toBoolean }) hideOnError = false;
 | 
			
		||||
    @Input() siteNameMode: CoreSiteLogoSiteNameMode = CoreSiteLogoSiteNameMode.NOTAG;
 | 
			
		||||
    @Input({ transform: toBoolean }) showLogo = true;
 | 
			
		||||
    @Input() site?: CoreSite | CoreUnauthenticatedSite;
 | 
			
		||||
    @Input() logoType: 'top' | 'login' = 'login';
 | 
			
		||||
 | 
			
		||||
    siteName?: string;
 | 
			
		||||
    siteId?: string;
 | 
			
		||||
    siteLogo?: string;
 | 
			
		||||
    logoLoaded = false;
 | 
			
		||||
    fallbackLogo = '';
 | 
			
		||||
    showSiteName = true;
 | 
			
		||||
 | 
			
		||||
    protected updateSiteObserver?: CoreEventObserver;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        this.loadSite();
 | 
			
		||||
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async () => {
 | 
			
		||||
            await this.loadInfo();
 | 
			
		||||
        }, this.siteId);
 | 
			
		||||
 | 
			
		||||
        this.fallbackLogo = this.logoType === 'top' ? 'assets/img/top_logo.png' : 'assets/img/login_logo.png';
 | 
			
		||||
        this.showSiteName = this.logoType !== 'top';
 | 
			
		||||
 | 
			
		||||
        await this.loadInfo();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function to handle the image error.
 | 
			
		||||
     */
 | 
			
		||||
    imageError(): void {
 | 
			
		||||
        if (this.hideOnError) {
 | 
			
		||||
            this.showLogo = false;
 | 
			
		||||
        }
 | 
			
		||||
        this.siteLogo = undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the site and siteId.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Site.
 | 
			
		||||
     */
 | 
			
		||||
    protected loadSite(): CoreSite | CoreUnauthenticatedSite {
 | 
			
		||||
        this.site = this.site ?? CoreSites.getRequiredCurrentSite();
 | 
			
		||||
 | 
			
		||||
        // During login, the siteId could be not defined yet.
 | 
			
		||||
        if (!this.siteId && this.site instanceof CoreSite) {
 | 
			
		||||
            this.siteId = this.site.getId();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.site;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the site name and logo.
 | 
			
		||||
     */
 | 
			
		||||
    protected async loadInfo(): Promise<void> {
 | 
			
		||||
        const site = this.loadSite();
 | 
			
		||||
 | 
			
		||||
        this.siteName = await site.getSiteName() || '';
 | 
			
		||||
 | 
			
		||||
        this.showSiteName = this.logoType !== 'top' || site.getShowTopLogo() === 'hidden';
 | 
			
		||||
 | 
			
		||||
        if (this.logoType === 'top' && site.getShowTopLogo() === 'hidden') {
 | 
			
		||||
            this.showLogo = false;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Get the public config to avoid race conditions when retrieving the logo.
 | 
			
		||||
            const siteConfig = await CorePromiseUtils.ignoreErrors(site.getPublicConfig());
 | 
			
		||||
 | 
			
		||||
            this.siteLogo = this.logoType === 'top'
 | 
			
		||||
                ? site.getTopLogoUrl(siteConfig)
 | 
			
		||||
                : site.getLogoUrl(siteConfig);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.logoLoaded = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.updateSiteObserver?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const enum CoreSiteLogoSiteNameMode {
 | 
			
		||||
    HEADING2 = 'h2',
 | 
			
		||||
    PARAGRAPH = 'p',
 | 
			
		||||
    NOTAG = '',
 | 
			
		||||
}
 | 
			
		||||
@ -92,20 +92,25 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
 | 
			
		||||
    @Input({ transform: toBoolean }) wsNotFiltered = false; // If true it means the WS didn't filter the text for some reason.
 | 
			
		||||
    @Input({ transform: toBoolean }) captureLinks = true; // Whether links should tried to be opened inside the app.
 | 
			
		||||
    @Input({ transform: toBoolean }) openLinksInApp = false; // Whether links should be opened in InAppBrowser.
 | 
			
		||||
    @Input({ transform: toBoolean }) hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
 | 
			
		||||
    @Input({ transform: toBoolean }) disabled = false; // If disabled, autoplay elements will be disabled.
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @deprecated since 5.0. Not used anymore.
 | 
			
		||||
     */
 | 
			
		||||
    @Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
 | 
			
		||||
 | 
			
		||||
    @Output() afterRender = new EventEmitter<void>(); // Called when the data is rendered.
 | 
			
		||||
    @Output() filterContentRenderingComplete = new EventEmitter<void>(); // Called when the filters have finished rendering content.
 | 
			
		||||
    @Output() onClick: EventEmitter<void> = new EventEmitter(); // Called when clicked.
 | 
			
		||||
 | 
			
		||||
    protected element: HTMLElement;
 | 
			
		||||
    protected elementControllers: ElementController[] = [];
 | 
			
		||||
    protected emptyText = '';
 | 
			
		||||
    protected domPromises: CoreCancellablePromise<void>[] = [];
 | 
			
		||||
    protected domElementPromise?: CoreCancellablePromise<void>;
 | 
			
		||||
    protected externalContentInstances: CoreExternalContentDirective[] = [];
 | 
			
		||||
 | 
			
		||||
    protected static readonly EMPTY_TEXT = ' ';
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        element: ElementRef,
 | 
			
		||||
        protected viewContainerRef: ViewContainerRef,
 | 
			
		||||
@ -116,18 +121,17 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
 | 
			
		||||
        this.element = element.nativeElement;
 | 
			
		||||
        this.element.classList.add('core-loading'); // Hide contents until they're treated.
 | 
			
		||||
 | 
			
		||||
        this.emptyText = this.hideIfEmpty ? '' : ' ';
 | 
			
		||||
        this.element.innerHTML = this.emptyText;
 | 
			
		||||
        this.element.innerHTML = CoreFormatTextDirective.EMPTY_TEXT;
 | 
			
		||||
 | 
			
		||||
        this.element.addEventListener('click', (event) => this.elementClicked(event));
 | 
			
		||||
 | 
			
		||||
        this.siteId = this.siteId || CoreSites.getCurrentSiteId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnChanges(changes: { [name: string]: SimpleChange }): void {
 | 
			
		||||
        this.siteId = this.siteId || CoreSites.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        if (changes.text || changes.filter || changes.contextLevel || changes.contextInstanceId) {
 | 
			
		||||
            this.formatAndRenderContents();
 | 
			
		||||
 | 
			
		||||
@ -365,7 +369,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
 | 
			
		||||
        this.externalContentInstances = [];
 | 
			
		||||
 | 
			
		||||
        if (!this.text) {
 | 
			
		||||
            this.element.innerHTML = this.emptyText; // Remove current contents.
 | 
			
		||||
            this.element.innerHTML = CoreFormatTextDirective.EMPTY_TEXT; // Remove current contents.
 | 
			
		||||
 | 
			
		||||
            await this.finishRender();
 | 
			
		||||
 | 
			
		||||
@ -450,7 +454,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
 | 
			
		||||
        let formatted: string;
 | 
			
		||||
        let filters: CoreFilterFilter[] = [];
 | 
			
		||||
 | 
			
		||||
        if (filter) {
 | 
			
		||||
        if (filter && siteId) {
 | 
			
		||||
            const filterResult = await CoreFilterHelper.getFiltersAndFormatText(
 | 
			
		||||
                this.text || '',
 | 
			
		||||
                this.contextLevel || ContextLevel.SYSTEM,
 | 
			
		||||
 | 
			
		||||
@ -96,6 +96,17 @@ describe('CoreFormatTextDirective', () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should get filters from server and format text', async () => {
 | 
			
		||||
        // Arrange
 | 
			
		||||
        const site = mock(new CoreSite('25', 'https://mysite.com', 'token'), {
 | 
			
		||||
            getId: () => site.id,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        mockSingleton(CoreSites, {
 | 
			
		||||
            getSite: () => Promise.resolve(site),
 | 
			
		||||
            getCurrentSite: () => site,
 | 
			
		||||
            getCurrentSiteId: () => site.id,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Arrange
 | 
			
		||||
        mockSingleton(CoreFilterHelper, {
 | 
			
		||||
            getFiltersAndFormatText: () => Promise.resolve({
 | 
			
		||||
@ -124,7 +135,7 @@ describe('CoreFormatTextDirective', () => {
 | 
			
		||||
            ContextLevel.COURSE,
 | 
			
		||||
            42,
 | 
			
		||||
            expect.anything(),
 | 
			
		||||
            undefined,
 | 
			
		||||
            '25',
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ import { CoreBlockComponentsModule } from '@features/block/components/components
 | 
			
		||||
 | 
			
		||||
import { CoreMainMenuComponentsModule } from '@features/mainmenu/components/components.module';
 | 
			
		||||
import { CoreCoursesMyPage } from '@features/courses/pages/my/my';
 | 
			
		||||
import { CoreSiteLogoComponent } from '@/core/components/site-logo/site-logo';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
@ -34,6 +35,7 @@ const routes: Routes = [
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreBlockComponentsModule,
 | 
			
		||||
        CoreMainMenuComponentsModule,
 | 
			
		||||
        CoreSiteLogoComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreCoursesMyPage,
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,7 @@
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>
 | 
			
		||||
            <h1>
 | 
			
		||||
                <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" class="core-header-sitename" />
 | 
			
		||||
                <img src="assets/img/top_logo.png" class="core-header-logo" [alt]="siteName">
 | 
			
		||||
                <core-site-logo logoType="top" />
 | 
			
		||||
            </h1>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,6 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(CoreBlockComponent) block!: CoreBlockComponent;
 | 
			
		||||
 | 
			
		||||
    siteName = '';
 | 
			
		||||
    downloadCoursesEnabled = false;
 | 
			
		||||
    userId: number;
 | 
			
		||||
    loadedBlock?: Partial<CoreCourseBlock>;
 | 
			
		||||
@ -66,8 +65,6 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async () => {
 | 
			
		||||
            this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
 | 
			
		||||
            await this.loadSiteName();
 | 
			
		||||
 | 
			
		||||
        }, CoreSites.getCurrentSiteId());
 | 
			
		||||
 | 
			
		||||
        this.userId = CoreSites.getCurrentSiteUserId();
 | 
			
		||||
@ -98,8 +95,6 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
 | 
			
		||||
        CoreSites.loginNavigationFinished();
 | 
			
		||||
 | 
			
		||||
        await this.loadSiteName();
 | 
			
		||||
 | 
			
		||||
        this.loadContent(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -156,14 +151,6 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
        this.logView();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the site name.
 | 
			
		||||
     */
 | 
			
		||||
    protected async loadSiteName(): Promise<void> {
 | 
			
		||||
        const site = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
        this.siteName = await site.getSiteName() || '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load fallback blocks.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreLoginComponentsModule } from '@features/login/components/components.module';
 | 
			
		||||
import { CoreLoginCredentialsPage } from '@features/login/pages/credentials/credentials';
 | 
			
		||||
import { CoreSiteLogoComponent } from '@/core/components/site-logo/site-logo';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
@ -31,6 +32,7 @@ const routes: Routes = [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreLoginComponentsModule,
 | 
			
		||||
        CoreSiteLogoComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreLoginCredentialsPage,
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreLoginComponentsModule } from '@features/login/components/components.module';
 | 
			
		||||
import { CoreLoginReconnectPage } from '@features/login/pages/reconnect/reconnect';
 | 
			
		||||
import { CoreSiteLogoComponent } from '@/core/components/site-logo/site-logo';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
@ -31,6 +32,7 @@ const routes: Routes = [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreLoginComponentsModule,
 | 
			
		||||
        CoreSiteLogoComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreLoginReconnectPage,
 | 
			
		||||
 | 
			
		||||
@ -29,20 +29,14 @@
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
        .core-login-site {
 | 
			
		||||
            .core-login-site-logo {
 | 
			
		||||
                width: 90%;
 | 
			
		||||
                max-width: 300px;
 | 
			
		||||
                margin: 0px auto;
 | 
			
		||||
            core-site-logo {
 | 
			
		||||
                --core-site-logo-max-height: 104px;
 | 
			
		||||
                --core-site-logo-sitename-margin-bottom: 8px;
 | 
			
		||||
                --core-site-logo-sitename-font: var(--mdl-typography-subtitle-font-lg);
 | 
			
		||||
 | 
			
		||||
                img {
 | 
			
		||||
                    max-width: 100%;
 | 
			
		||||
                    max-height: 104px;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .core-sitename {
 | 
			
		||||
                font-size: 1.2rem;
 | 
			
		||||
                margin-bottom: 8px;
 | 
			
		||||
                --core-site-logo-max-width: 300px;
 | 
			
		||||
                --core-site-logo-width: 90%;
 | 
			
		||||
                --core-site-logo-margin: 0 auto;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .core-siteurl {
 | 
			
		||||
@ -89,9 +83,12 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @if ($core-fixed-url) {
 | 
			
		||||
        .core-sitename, .core-siteurl {
 | 
			
		||||
        .core-siteurl {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
        core-site-logo {
 | 
			
		||||
            --core-site-logo-sitename-display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @if ($core-login-button-outline) {
 | 
			
		||||
 | 
			
		||||
@ -23,16 +23,7 @@
 | 
			
		||||
        <ng-container *ngIf="!siteCheckError && site && credForm">
 | 
			
		||||
            <div class="ion-text-wrap ion-text-center core-login-info-box">
 | 
			
		||||
                <div class="core-login-site">
 | 
			
		||||
                    <div class="core-login-site-logo">
 | 
			
		||||
                        <!-- Show site logo or a default image. -->
 | 
			
		||||
                        <img *ngIf="logoUrl" [src]="logoUrl" role="presentation" alt="" core-external-content
 | 
			
		||||
                            onError="this.src='assets/img/login_logo.png'">
 | 
			
		||||
                        <img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation" alt="">
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <h2 *ngIf="siteName" class="ion-margin-top ion-no-padding core-sitename">
 | 
			
		||||
                        <core-format-text [text]="siteName" [filter]="false" />
 | 
			
		||||
                    </h2>
 | 
			
		||||
                    <core-site-logo siteNameMode="h2" [site]="site" />
 | 
			
		||||
                    <p class="core-siteurl" *ngIf="displaySiteUrl">{{site.siteUrl}}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -57,8 +57,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    credForm!: FormGroup;
 | 
			
		||||
    site!: CoreUnauthenticatedSite;
 | 
			
		||||
    siteName?: string;
 | 
			
		||||
    logoUrl?: string;
 | 
			
		||||
    authInstructions?: string;
 | 
			
		||||
    canSignup?: boolean;
 | 
			
		||||
    pageLoaded = false;
 | 
			
		||||
@ -104,11 +102,9 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.site = CoreSitesFactory.makeUnauthenticatedSite(siteUrl, this.siteConfig);
 | 
			
		||||
            this.logoUrl = this.site.getLogoUrl(this.siteConfig);
 | 
			
		||||
            this.urlToOpen = CoreNavigator.getRouteParam('urlToOpen');
 | 
			
		||||
            this.supportConfig = this.siteConfig && new CoreUserGuestSupportConfig(this.site, this.siteConfig);
 | 
			
		||||
            this.displaySiteUrl = this.site.shouldDisplayInformativeLinks();
 | 
			
		||||
            this.siteName = await this.site.getSiteName();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
 | 
			
		||||
@ -220,8 +216,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
        if (this.site.isDemoModeSite()) {
 | 
			
		||||
            this.showScanQR = false;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.siteName = this.siteConfig.sitename;
 | 
			
		||||
            this.logoUrl = this.site.getLogoUrl(this.siteConfig);
 | 
			
		||||
            this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,16 +31,8 @@
 | 
			
		||||
 | 
			
		||||
            <div class="ion-text-wrap ion-text-center core-login-info-box">
 | 
			
		||||
                <div class="core-login-site">
 | 
			
		||||
                    <div class="core-login-site-logo" *ngIf="!showUserAvatar">
 | 
			
		||||
                        <!-- Show site logo or a default image. -->
 | 
			
		||||
                        <img *ngIf="logoUrl" [src]="logoUrl" role="presentation" onError="this.src='assets/img/login_logo.png'" alt=""
 | 
			
		||||
                            core-external-content [siteId]="siteId">
 | 
			
		||||
                        <img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation" alt="">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <core-site-logo siteNameMode="p" [showLogo]="!showUserAvatar" [site]="site" />
 | 
			
		||||
 | 
			
		||||
                    <p *ngIf="siteInfo?.siteName" class="ion-no-margin ion-no-padding core-sitename">
 | 
			
		||||
                        <core-format-text [text]="siteInfo?.siteName" [filter]="false" />
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="core-siteurl" *ngIf="displaySiteUrl">{{site.siteUrl}}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,6 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    credForm: FormGroup;
 | 
			
		||||
    site!: CoreSite;
 | 
			
		||||
    logoUrl?: string;
 | 
			
		||||
    displaySiteUrl = false;
 | 
			
		||||
    showForgottenPassword = true;
 | 
			
		||||
    showUserAvatar = false;
 | 
			
		||||
@ -202,7 +201,6 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isBrowserSSO = CoreLoginHelper.isSSOLoginNeeded(this.siteConfig.typeoflogin);
 | 
			
		||||
        this.logoUrl = this.site.getLogoUrl();
 | 
			
		||||
 | 
			
		||||
        await CoreSites.checkApplication(this.siteConfig);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,6 @@
 | 
			
		||||
.core-login-site-logo,
 | 
			
		||||
.core-login-site-list,
 | 
			
		||||
.core-login-site-list-found {
 | 
			
		||||
    transition-delay: 0s;
 | 
			
		||||
    visibility: visible;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    transition: all 0.7s ease-in-out;
 | 
			
		||||
@ -61,6 +60,7 @@
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        max-height: 0;
 | 
			
		||||
        display: block !important; /** Avoid breaking the animation */
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB  | 
@ -13,18 +13,14 @@
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-loading [hideUntil]="siteLogoLoaded && handlersLoaded">
 | 
			
		||||
    <core-loading [hideUntil]="handlersLoaded">
 | 
			
		||||
        <ion-list>
 | 
			
		||||
            <!-- Site info with URL and clickable. -->
 | 
			
		||||
            <ion-item button class="core-usermenu-siteinfo ion-text-wrap" *ngIf="siteInfo && displaySiteUrl" lines="full" [detail]="false"
 | 
			
		||||
                [href]="siteUrl" core-link>
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <!-- Show site logo. -->
 | 
			
		||||
                    <img class="core-usermenu-site-logo" *ngIf="siteLogo && siteLogoLoaded" [src]="siteLogo" role="presentation" alt=""
 | 
			
		||||
                        core-external-content onError="this.class='image-not-found'">
 | 
			
		||||
                    <p class="core-usermenu-sitename">
 | 
			
		||||
                        <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [wsNotFiltered]="true" />
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <core-site-logo [hideOnError]="true" siteNameMode="p" />
 | 
			
		||||
                    <a [href]="siteUrl" core-link class="core-usermenu-siteurl">{{ siteUrl }}</a>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
@ -32,11 +28,7 @@
 | 
			
		||||
            <ion-item class="core-usermenu-siteinfo ion-text-wrap" *ngIf="siteInfo && !displaySiteUrl" lines="full" detail="false">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <!-- Show site logo. -->
 | 
			
		||||
                    <img class="core-usermenu-site-logo" *ngIf="siteLogo && siteLogoLoaded" [src]="siteLogo" role="presentation" alt=""
 | 
			
		||||
                        onError="this.class='image-not-found'">
 | 
			
		||||
                    <p class="core-usermenu-sitename">
 | 
			
		||||
                        <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [wsNotFiltered]="true" />
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <core-site-logo [hideOnError]="true" siteNameMode="p" />
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,23 +22,17 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.core-usermenu-sitename {
 | 
			
		||||
    font: var(--mdl-typography-subtitle-font-lg);
 | 
			
		||||
}
 | 
			
		||||
core-site-logo {
 | 
			
		||||
    --core-site-logo-margin-bottom: 8px;
 | 
			
		||||
    --core-site-logo-max-height: var(--core-user-menu-site-logo-max-height);
 | 
			
		||||
 | 
			
		||||
img.core-usermenu-site-logo {
 | 
			
		||||
    margin-bottom: 8px;
 | 
			
		||||
    max-height: var(--core-user-menu-site-logo-max-height);
 | 
			
		||||
    --core-site-logo-sitename-font: var(--mdl-typography-subtitle-font-lg);
 | 
			
		||||
    --core-site-logo-sitename-margin-bottom: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img.image-not-found {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@if ($core-user-hide-sitename) {
 | 
			
		||||
    .core-usermenu-sitename {
 | 
			
		||||
        display: none;
 | 
			
		||||
    core-site-logo {
 | 
			
		||||
        --core-site-logo-sitename-display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,6 @@
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { CoreSite } from '@classes/sites/site';
 | 
			
		||||
import { CoreSiteInfo } from '@classes/sites/unauthenticated-site';
 | 
			
		||||
import { CoreFilter } from '@features/filter/services/filter';
 | 
			
		||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
 | 
			
		||||
@ -31,10 +30,10 @@ import { CoreModals } from '@services/modals';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
			
		||||
import { ModalController } from '@singletons';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
import { CoreSiteLogoComponent } from '@/core/components/site-logo/site-logo';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to display a user menu.
 | 
			
		||||
@ -46,6 +45,7 @@ import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
    standalone: true,
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreSiteLogoComponent,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
@ -53,8 +53,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
    siteId?: string;
 | 
			
		||||
    siteInfo?: CoreSiteInfo;
 | 
			
		||||
    siteName?: string;
 | 
			
		||||
    siteLogo?: string;
 | 
			
		||||
    siteLogoLoaded = false;
 | 
			
		||||
    siteUrl?: string;
 | 
			
		||||
    displaySiteUrl = false;
 | 
			
		||||
    handlers: CoreUserProfileHandlerData[] = [];
 | 
			
		||||
@ -81,8 +79,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
        this.removeAccountOnLogout = !!CoreConstants.CONFIG.removeaccountonlogout;
 | 
			
		||||
        this.displaySiteUrl = currentSite.shouldDisplayInformativeLinks();
 | 
			
		||||
 | 
			
		||||
        this.loadSiteLogo(currentSite);
 | 
			
		||||
 | 
			
		||||
        if (!this.siteInfo) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@ -127,25 +123,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load site logo from current site public config.
 | 
			
		||||
     *
 | 
			
		||||
     * @param currentSite Current site object.
 | 
			
		||||
     * @returns Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async loadSiteLogo(currentSite: CoreSite): Promise<void> {
 | 
			
		||||
        if (currentSite.forcesLocalLogo()) {
 | 
			
		||||
            this.siteLogo = currentSite.getLogoUrl();
 | 
			
		||||
            this.siteLogoLoaded = true;
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const siteConfig = await CorePromiseUtils.ignoreErrors(currentSite.getPublicConfig());
 | 
			
		||||
        this.siteLogo = currentSite.getLogoUrl(siteConfig);
 | 
			
		||||
        this.siteLogoLoaded = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens User profile page.
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@ import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/hand
 | 
			
		||||
import { CoreMainMenuComponentsModule } from '@features/mainmenu/components/components.module';
 | 
			
		||||
import { resolveHomeRoutes } from '@features/mainmenu/mainmenu-home-routing.module';
 | 
			
		||||
import { CoreMainMenuHomePage } from '@features/mainmenu/pages/home/home';
 | 
			
		||||
import { CoreSiteLogoComponent } from '@/core/components/site-logo/site-logo';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Build module routes.
 | 
			
		||||
@ -49,6 +50,7 @@ function buildRoutes(injector: Injector): Routes {
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreMainMenuComponentsModule,
 | 
			
		||||
        CoreSiteLogoComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        { provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] },
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,7 @@
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>
 | 
			
		||||
            <h1>
 | 
			
		||||
                <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" class="core-header-sitename" />
 | 
			
		||||
                <img src="assets/img/top_logo.png" class="core-header-logo" [alt]="siteName">
 | 
			
		||||
                <core-site-logo logoType="top" />
 | 
			
		||||
            </h1>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
 | 
			
		||||
@ -69,15 +69,8 @@ ion-header.header-md {
 | 
			
		||||
            display: inline !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        h1 {
 | 
			
		||||
            .core-header-logo {
 | 
			
		||||
                max-height: var(--core-mainpage-headerlogo-maxheight);
 | 
			
		||||
                display: var( --core-mainpage-headerlogo-display);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .core-header-sitename {
 | 
			
		||||
                display: var(--core-mainpage-sitename-display);
 | 
			
		||||
            }
 | 
			
		||||
        h1 core-site-logo {
 | 
			
		||||
            --core-site-logo-max-height: var(--core-mainpage-headerlogo-maxheight);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        h1, h2, .subheading {
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,6 @@ $core-dd-question-colors: #FFFFFF, #B0C4DE, #DCDCDC, #D8BFD8, #87CEFA, #DAA520,
 | 
			
		||||
$core-text-hightlight-background-color: lighten($blue, 40%) !default;
 | 
			
		||||
 | 
			
		||||
$core-fixed-url: false !default;
 | 
			
		||||
$core-dashboard-logo: false !default;
 | 
			
		||||
$core-always-show-main-menu: false !default;
 | 
			
		||||
$core-format-text-never-shorten: false !default;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -231,15 +231,7 @@
 | 
			
		||||
 | 
			
		||||
    --rotate-expandable: rotate(90deg);
 | 
			
		||||
 | 
			
		||||
    --core-mainpage-sitename-display: none;
 | 
			
		||||
    --core-mainpage-headerlogo-display: none;
 | 
			
		||||
    --core-mainpage-headerlogo-maxheight: calc(var(--core-header-toolbar-height) - 16px);
 | 
			
		||||
 | 
			
		||||
    @if ($core-dashboard-logo) {
 | 
			
		||||
        --core-mainpage-headerlogo-display: inline;
 | 
			
		||||
    } @else {
 | 
			
		||||
        --core-mainpage-sitename-display: inline;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @deprecated since 4.3 **/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								src/types/config.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/types/config.d.ts
									
									
									
									
										vendored
									
									
								
							@ -53,6 +53,7 @@ export interface EnvironmentConfig {
 | 
			
		||||
    enableonboarding: boolean;
 | 
			
		||||
    forceColorScheme: CoreColorScheme;
 | 
			
		||||
    forceLoginLogo: boolean;
 | 
			
		||||
    showTopLogo: 'online' | 'offline' | 'hidden';
 | 
			
		||||
    ioswebviewscheme: string;
 | 
			
		||||
    appstores: Record<string, string>;
 | 
			
		||||
    displayqroncredentialscreen?: boolean;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user