MOBILE-3565 settings: Add space usage page
parent
a9e8213026
commit
d5e95ccd89
|
@ -0,0 +1,46 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>{{ 'core.settings.spaceusage' | translate }}</ion-title>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<!-- @todo <core-navbar-buttons></core-navbar-buttons>-->
|
||||||
|
<ion-button (click)="showInfo()" [attr.aria-label]="'core.info' | translate">
|
||||||
|
<ion-icon name="fas-info-circle" slot="icon-only"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content>
|
||||||
|
<ion-refresher [disabled]="!loaded" (ionRefresh)="refreshData($event)" slot="fixed">
|
||||||
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
|
<core-loading [hideUntil]="loaded">
|
||||||
|
<ion-item *ngFor="let site of sites" [class.core-selected-item]="site.id == currentSiteId">
|
||||||
|
<ion-label class="ion-text-wrap">
|
||||||
|
<h2>
|
||||||
|
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
||||||
|
</h2>
|
||||||
|
<p class="ion-text-wrap">{{ site.fullName }}</p>
|
||||||
|
<p>{{ site.siteUrl }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<p *ngIf="site.spaceUsage != null" slot="end">
|
||||||
|
{{ site.spaceUsage | coreBytesToSize }}
|
||||||
|
</p>
|
||||||
|
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)"
|
||||||
|
[hidden]="site.spaceUsage! + site.cacheEntries! <= 0"
|
||||||
|
[attr.aria-label]="'core.settings.deletesitefilestitle' | translate">
|
||||||
|
<ion-icon name="fas-trash" slot="icon-only"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-divider>
|
||||||
|
<ion-label>
|
||||||
|
<h2>{{ 'core.settings.total' | translate }}</h2>
|
||||||
|
</ion-label>
|
||||||
|
<p slot="end" class="ion-margin-end">
|
||||||
|
{{ totals.spaceUsage | coreBytesToSize }}
|
||||||
|
</p>
|
||||||
|
</ion-item-divider>
|
||||||
|
</core-loading>
|
||||||
|
</ion-content>
|
|
@ -0,0 +1,49 @@
|
||||||
|
// (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 { NgModule } from '@angular/core';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { IonicModule } from '@ionic/angular';
|
||||||
|
|
||||||
|
import { CoreComponentsModule } from '@components/components.module';
|
||||||
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
|
import { CorePipesModule } from '@pipes/pipes.module';
|
||||||
|
|
||||||
|
import { CoreSettingsSpaceUsagePage } from './space-usage.page';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: CoreSettingsSpaceUsagePage,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreComponentsModule,
|
||||||
|
CoreDirectivesModule,
|
||||||
|
CorePipesModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CoreSettingsSpaceUsagePage,
|
||||||
|
],
|
||||||
|
exports: [RouterModule],
|
||||||
|
})
|
||||||
|
export class CoreSettingsSpaceUsagePageModule {}
|
|
@ -0,0 +1,157 @@
|
||||||
|
// (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, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { IonRefresher } from '@ionic/angular';
|
||||||
|
|
||||||
|
import { CoreSiteBasicInfo, CoreSites } from '@services/sites';
|
||||||
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
import { Translate } from '@singletons/core.singletons';
|
||||||
|
import { CoreEventObserver, CoreEvents, CoreEventSiteUpdatedData } from '@singletons/events';
|
||||||
|
|
||||||
|
import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings.helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page that displays the space usage settings.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'page-core-app-settings-space-usage',
|
||||||
|
templateUrl: 'space-usage.html',
|
||||||
|
})
|
||||||
|
export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
loaded = false;
|
||||||
|
sites: CoreSiteBasicInfoWithUsage[] = [];
|
||||||
|
currentSiteId = '';
|
||||||
|
totals: CoreSiteSpaceUsage = {
|
||||||
|
cacheEntries: 0,
|
||||||
|
spaceUsage: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected sitesObserver: CoreEventObserver;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.currentSiteId = CoreSites.instance.getCurrentSiteId();
|
||||||
|
|
||||||
|
this.sitesObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async (data: CoreEventSiteUpdatedData) => {
|
||||||
|
const site = await CoreSites.instance.getSite(data.siteId);
|
||||||
|
|
||||||
|
const siteEntry = this.sites.find((siteEntry) => siteEntry.id == site.id);
|
||||||
|
if (siteEntry) {
|
||||||
|
const siteInfo = site.getInfo();
|
||||||
|
|
||||||
|
siteEntry.siteName = site.getSiteName();
|
||||||
|
|
||||||
|
if (siteInfo) {
|
||||||
|
siteEntry.siteUrl = siteInfo.siteurl;
|
||||||
|
siteEntry.fullName = siteInfo.fullname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View loaded.
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadSiteData().finally(() => {
|
||||||
|
this.loaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to load site data/usage and calculate the totals.
|
||||||
|
*
|
||||||
|
* @return Resolved when done.
|
||||||
|
*/
|
||||||
|
protected async loadSiteData(): Promise<void> {
|
||||||
|
// Calculate total usage.
|
||||||
|
let totalSize = 0;
|
||||||
|
let totalEntries = 0;
|
||||||
|
|
||||||
|
this.sites = await CoreSites.instance.getSortedSites();
|
||||||
|
|
||||||
|
const settingsHelper = CoreSettingsHelper.instance;
|
||||||
|
|
||||||
|
// Get space usage.
|
||||||
|
await Promise.all(this.sites.map(async (site) => {
|
||||||
|
const siteInfo = await settingsHelper.getSiteSpaceUsage(site.id);
|
||||||
|
|
||||||
|
site.cacheEntries = siteInfo.cacheEntries;
|
||||||
|
site.spaceUsage = siteInfo.spaceUsage;
|
||||||
|
|
||||||
|
totalSize += site.spaceUsage || 0;
|
||||||
|
totalEntries += site.cacheEntries || 0;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.totals.spaceUsage = totalSize;
|
||||||
|
this.totals.cacheEntries = totalEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the data.
|
||||||
|
*
|
||||||
|
* @param event Refresher event.
|
||||||
|
*/
|
||||||
|
refreshData(event?: CustomEvent<IonRefresher>): void {
|
||||||
|
this.loadSiteData().finally(() => {
|
||||||
|
event?.detail.complete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes files of a site and the tables that can be cleared.
|
||||||
|
*
|
||||||
|
* @param siteData Site object with space usage.
|
||||||
|
*/
|
||||||
|
async deleteSiteStorage(siteData: CoreSiteBasicInfoWithUsage): Promise<void> {
|
||||||
|
try {
|
||||||
|
const newInfo = await CoreSettingsHelper.instance.deleteSiteStorage(siteData.siteName || '', siteData.id);
|
||||||
|
|
||||||
|
this.totals.spaceUsage -= siteData.spaceUsage! - newInfo.spaceUsage;
|
||||||
|
this.totals.spaceUsage -= siteData.cacheEntries! - newInfo.cacheEntries;
|
||||||
|
|
||||||
|
siteData.spaceUsage = newInfo.spaceUsage;
|
||||||
|
siteData.cacheEntries = newInfo.cacheEntries;
|
||||||
|
} catch {
|
||||||
|
// Ignore cancelled confirmation modal.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show information about space usage actions.
|
||||||
|
*/
|
||||||
|
showInfo(): void {
|
||||||
|
CoreDomUtils.instance.showAlert(
|
||||||
|
Translate.instance.instant('core.help'),
|
||||||
|
Translate.instance.instant('core.settings.spaceusagehelp'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page destroyed.
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.sitesObserver?.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic site info with space usage and cache entries that can be erased.
|
||||||
|
*/
|
||||||
|
export interface CoreSiteBasicInfoWithUsage extends CoreSiteBasicInfo {
|
||||||
|
cacheEntries?: number; // Number of cached entries that can be cleared.
|
||||||
|
spaceUsage?: number; // Space used in this site.
|
||||||
|
}
|
|
@ -31,8 +31,8 @@ import { makeSingleton, Translate } from '@singletons/core.singletons';
|
||||||
* Object with space usage and cache entries that can be erased.
|
* Object with space usage and cache entries that can be erased.
|
||||||
*/
|
*/
|
||||||
export interface CoreSiteSpaceUsage {
|
export interface CoreSiteSpaceUsage {
|
||||||
cacheEntries?: number; // Number of cached entries that can be cleared.
|
cacheEntries: number; // Number of cached entries that can be cleared.
|
||||||
spaceUsage?: number; // Space used in this site (total files + estimate of cache).
|
spaceUsage: number; // Space used in this site (total files + estimate of cache).
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,6 +24,12 @@ const routes: Routes = [
|
||||||
path: 'general',
|
path: 'general',
|
||||||
loadChildren: () => import('./pages/general/general.page.module').then( m => m.CoreSettingsGeneralPageModule),
|
loadChildren: () => import('./pages/general/general.page.module').then( m => m.CoreSettingsGeneralPageModule),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'spaceusage',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('@core/settings/pages/space-usage/space-usage.page.module')
|
||||||
|
.then(m => m.CoreSettingsSpaceUsagePageModule),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
loadChildren: () => import('./pages/app/app.page.module').then( m => m.CoreSettingsAppPageModule),
|
loadChildren: () => import('./pages/app/app.page.module').then( m => m.CoreSettingsAppPageModule),
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
// (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 { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipe to turn a number in bytes to a human readable size (e.g. 5,25 MB).
|
||||||
|
*/
|
||||||
|
@Pipe({
|
||||||
|
name: 'coreBytesToSize',
|
||||||
|
})
|
||||||
|
export class CoreBytesToSizePipe implements PipeTransform {
|
||||||
|
|
||||||
|
protected logger: CoreLogger;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.logger = CoreLogger.getInstance('CoreBytesToSizePipe');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a number and turns it to a human readable size.
|
||||||
|
*
|
||||||
|
* @param value The bytes to convert.
|
||||||
|
* @return Readable bytes.
|
||||||
|
*/
|
||||||
|
transform(value: number | string): string {
|
||||||
|
if (typeof value == 'string') {
|
||||||
|
// Convert the value to a number.
|
||||||
|
const numberValue = parseInt(value, 10);
|
||||||
|
if (isNaN(numberValue)) {
|
||||||
|
this.logger.error('Invalid value received', value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
value = numberValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CoreTextUtils.instance.bytesToSize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import { CoreCreateLinksPipe } from './create-links.pipe';
|
||||||
import { CoreFormatDatePipe } from './format-date.pipe';
|
import { CoreFormatDatePipe } from './format-date.pipe';
|
||||||
import { CoreNoTagsPipe } from './no-tags.pipe';
|
import { CoreNoTagsPipe } from './no-tags.pipe';
|
||||||
import { CoreTimeAgoPipe } from './time-ago.pipe';
|
import { CoreTimeAgoPipe } from './time-ago.pipe';
|
||||||
|
import { CoreBytesToSizePipe } from './bytes-to-size.pipe';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -24,6 +25,7 @@ import { CoreTimeAgoPipe } from './time-ago.pipe';
|
||||||
CoreNoTagsPipe,
|
CoreNoTagsPipe,
|
||||||
CoreTimeAgoPipe,
|
CoreTimeAgoPipe,
|
||||||
CoreFormatDatePipe,
|
CoreFormatDatePipe,
|
||||||
|
CoreBytesToSizePipe,
|
||||||
],
|
],
|
||||||
imports: [],
|
imports: [],
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -31,6 +33,7 @@ import { CoreTimeAgoPipe } from './time-ago.pipe';
|
||||||
CoreNoTagsPipe,
|
CoreNoTagsPipe,
|
||||||
CoreTimeAgoPipe,
|
CoreTimeAgoPipe,
|
||||||
CoreFormatDatePipe,
|
CoreFormatDatePipe,
|
||||||
|
CoreBytesToSizePipe,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CorePipesModule {}
|
export class CorePipesModule {}
|
||||||
|
|
|
@ -1038,7 +1038,7 @@ export class CoreSitesProvider {
|
||||||
id: site.id,
|
id: site.id,
|
||||||
siteUrl: site.siteUrl,
|
siteUrl: site.siteUrl,
|
||||||
fullName: siteInfo?.fullname,
|
fullName: siteInfo?.fullname,
|
||||||
siteName: CoreConstants.CONFIG.sitename ?? siteInfo?.sitename,
|
siteName: CoreConstants.CONFIG.sitename == '' ? siteInfo?.sitename: CoreConstants.CONFIG.sitename,
|
||||||
avatar: siteInfo?.userpictureurl,
|
avatar: siteInfo?.userpictureurl,
|
||||||
siteHomeId: siteInfo?.siteid || 1,
|
siteHomeId: siteInfo?.siteid || 1,
|
||||||
};
|
};
|
||||||
|
@ -1055,32 +1055,32 @@ export class CoreSitesProvider {
|
||||||
* @param ids IDs of the sites to get. If not defined, return all sites.
|
* @param ids IDs of the sites to get. If not defined, return all sites.
|
||||||
* @return Promise resolved when the sites are retrieved.
|
* @return Promise resolved when the sites are retrieved.
|
||||||
*/
|
*/
|
||||||
getSortedSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
async getSortedSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||||
return this.getSites(ids).then((sites) => {
|
const sites = await this.getSites(ids);
|
||||||
// Sort sites by url and ful lname.
|
|
||||||
sites.sort((a, b) => {
|
|
||||||
// First compare by site url without the protocol.
|
|
||||||
const urlA = a.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
|
|
||||||
const urlB = b.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
|
|
||||||
const compare = urlA.localeCompare(urlB);
|
|
||||||
|
|
||||||
if (compare !== 0) {
|
// Sort sites by url and ful lname.
|
||||||
return compare;
|
sites.sort((a, b) => {
|
||||||
}
|
// First compare by site url without the protocol.
|
||||||
|
const urlA = a.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
|
||||||
|
const urlB = b.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
|
||||||
|
const compare = urlA.localeCompare(urlB);
|
||||||
|
|
||||||
// If site url is the same, use fullname instead.
|
if (compare !== 0) {
|
||||||
const fullNameA = a.fullName?.toLowerCase().trim();
|
return compare;
|
||||||
const fullNameB = b.fullName?.toLowerCase().trim();
|
}
|
||||||
|
|
||||||
if (!fullNameA || !fullNameB) {
|
// If site url is the same, use fullname instead.
|
||||||
return 0;
|
const fullNameA = a.fullName?.toLowerCase().trim();
|
||||||
}
|
const fullNameB = b.fullName?.toLowerCase().trim();
|
||||||
|
|
||||||
return fullNameA.localeCompare(fullNameB);
|
if (!fullNameA || !fullNameB) {
|
||||||
});
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return sites;
|
return fullNameA.localeCompare(fullNameB);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return sites;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Params } from '@angular/router';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { CoreSiteInfoResponse } from '@classes/site';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer instance to stop listening to an event.
|
* Observer instance to stop listening to an event.
|
||||||
|
@ -192,13 +193,24 @@ export class CoreEvents {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some events contains siteId added by the trigger function. This type is intended to be combined with others.
|
||||||
|
*/
|
||||||
|
export type CoreEventSiteData = {
|
||||||
|
siteId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data passed to SITE_UPDATED event.
|
||||||
|
*/
|
||||||
|
export type CoreEventSiteUpdatedData = CoreEventSiteData & CoreSiteInfoResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data passed to SESSION_EXPIRED event.
|
* Data passed to SESSION_EXPIRED event.
|
||||||
*/
|
*/
|
||||||
export type CoreEventSessionExpiredData = {
|
export type CoreEventSessionExpiredData = CoreEventSiteData & {
|
||||||
pageName?: string;
|
pageName?: string;
|
||||||
params?: Params;
|
params?: Params;
|
||||||
siteId?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -105,6 +105,13 @@ ion-list.list-md {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Item styles
|
||||||
|
.item.core-selected-item {
|
||||||
|
// TODO: Add safe are to border and RTL
|
||||||
|
border-inline-start: var(--selected-item-border-width) solid var(--selected-item-color);
|
||||||
|
--ion-safe-area-left: calc(-1 * var(--selected-item-border-width));
|
||||||
|
}
|
||||||
|
|
||||||
// Avatar
|
// Avatar
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// Large centered avatar
|
// Large centered avatar
|
||||||
|
|
|
@ -131,6 +131,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--selected-item-color: var(--custom-selected-item-color, var(--core-color));
|
||||||
|
--selected-item-border-width: var(--custom-selected-item-border-width, 5px);
|
||||||
|
|
||||||
--drop-shadow: var(--custom-drop-shadow, 0, 0, 0, 0.2);
|
--drop-shadow: var(--custom-drop-shadow, 0, 0, 0, 0.2);
|
||||||
|
|
||||||
--core-login-background: var(--custom-login-background, var(--white));
|
--core-login-background: var(--custom-login-background, var(--white));
|
||||||
|
|
Loading…
Reference in New Issue