mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-15 22:13:02 +00:00
Merge pull request #1853 from atmire/w2p-94233_use-css-vars-in-CSSVariableService
Use CSS variables in TypeScript
This commit is contained in:
@@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|||||||
|
|
||||||
import { MenuService } from '../../../shared/menu/menu.service';
|
import { MenuService } from '../../../shared/menu/menu.service';
|
||||||
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
||||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||||
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
@@ -6,7 +6,7 @@ import { ScriptDataService } from '../../core/data/processes/script-data.service
|
|||||||
import { AdminSidebarComponent } from './admin-sidebar.component';
|
import { AdminSidebarComponent } from './admin-sidebar.component';
|
||||||
import { MenuService } from '../../shared/menu/menu.service';
|
import { MenuService } from '../../shared/menu/menu.service';
|
||||||
import { MenuServiceStub } from '../../shared/testing/menu-service.stub';
|
import { MenuServiceStub } from '../../shared/testing/menu-service.stub';
|
||||||
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../shared/sass-helper/css-variable.service';
|
||||||
import { CSSVariableServiceStub } from '../../shared/testing/css-variable-service.stub';
|
import { CSSVariableServiceStub } from '../../shared/testing/css-variable-service.stub';
|
||||||
import { AuthServiceStub } from '../../shared/testing/auth-service.stub';
|
import { AuthServiceStub } from '../../shared/testing/auth-service.stub';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
@@ -5,7 +5,7 @@ import { AuthService } from '../../core/auth/auth.service';
|
|||||||
import { slideSidebar } from '../../shared/animations/slide';
|
import { slideSidebar } from '../../shared/animations/slide';
|
||||||
import { MenuComponent } from '../../shared/menu/menu.component';
|
import { MenuComponent } from '../../shared/menu/menu.component';
|
||||||
import { MenuService } from '../../shared/menu/menu.service';
|
import { MenuService } from '../../shared/menu/menu.service';
|
||||||
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../shared/sass-helper/css-variable.service';
|
||||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { MenuID } from '../../shared/menu/menu-id.model';
|
import { MenuID } from '../../shared/menu/menu-id.model';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
@@ -69,7 +69,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.sidebarWidth = this.variableService.getVariable('sidebarItemsWidth');
|
this.sidebarWidth = this.variableService.getVariable('--ds-sidebar-items-width');
|
||||||
this.authService.isAuthenticated()
|
this.authService.isAuthenticated()
|
||||||
.subscribe((loggedIn: boolean) => {
|
.subscribe((loggedIn: boolean) => {
|
||||||
if (loggedIn) {
|
if (loggedIn) {
|
||||||
|
@@ -3,7 +3,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|||||||
import { ExpandableAdminSidebarSectionComponent } from './expandable-admin-sidebar-section.component';
|
import { ExpandableAdminSidebarSectionComponent } from './expandable-admin-sidebar-section.component';
|
||||||
import { MenuService } from '../../../shared/menu/menu.service';
|
import { MenuService } from '../../../shared/menu/menu.service';
|
||||||
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
||||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||||
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
@@ -2,7 +2,7 @@ import { Component, Inject, Injector, OnInit } from '@angular/core';
|
|||||||
import { rotate } from '../../../shared/animations/rotate';
|
import { rotate } from '../../../shared/animations/rotate';
|
||||||
import { AdminSidebarSectionComponent } from '../admin-sidebar-section/admin-sidebar-section.component';
|
import { AdminSidebarSectionComponent } from '../admin-sidebar-section/admin-sidebar-section.component';
|
||||||
import { slide } from '../../../shared/animations/slide';
|
import { slide } from '../../../shared/animations/slide';
|
||||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||||
import { bgColor } from '../../../shared/animations/bgColor';
|
import { bgColor } from '../../../shared/animations/bgColor';
|
||||||
import { MenuService } from '../../../shared/menu/menu.service';
|
import { MenuService } from '../../../shared/menu/menu.service';
|
||||||
import { combineLatest as combineLatestObservable, Observable } from 'rxjs';
|
import { combineLatest as combineLatestObservable, Observable } from 'rxjs';
|
||||||
@@ -65,7 +65,7 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC
|
|||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
|
this.sidebarActiveBg = this.variableService.getVariable('--ds-admin-sidebar-active-bg');
|
||||||
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
|
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
|
||||||
this.sidebarPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID);
|
this.sidebarPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID);
|
||||||
this.expanded = combineLatestObservable(this.active, this.sidebarCollapsed, this.sidebarPreviewCollapsed)
|
this.expanded = combineLatestObservable(this.active, this.sidebarCollapsed, this.sidebarPreviewCollapsed)
|
||||||
|
@@ -18,7 +18,7 @@ import { AngularticsProviderMock } from './shared/mocks/angulartics-provider.ser
|
|||||||
import { AuthServiceMock } from './shared/mocks/auth.service.mock';
|
import { AuthServiceMock } from './shared/mocks/auth.service.mock';
|
||||||
import { AuthService } from './core/auth/auth.service';
|
import { AuthService } from './core/auth/auth.service';
|
||||||
import { MenuService } from './shared/menu/menu.service';
|
import { MenuService } from './shared/menu/menu.service';
|
||||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from './shared/sass-helper/css-variable.service';
|
||||||
import { CSSVariableServiceStub } from './shared/testing/css-variable-service.stub';
|
import { CSSVariableServiceStub } from './shared/testing/css-variable-service.stub';
|
||||||
import { MenuServiceStub } from './shared/testing/menu-service.stub';
|
import { MenuServiceStub } from './shared/testing/menu-service.stub';
|
||||||
import { HostWindowService } from './shared/host-window.service';
|
import { HostWindowService } from './shared/host-window.service';
|
||||||
|
@@ -25,7 +25,7 @@ import { HostWindowState } from './shared/search/host-window.reducer';
|
|||||||
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
||||||
import { isAuthenticationBlocking } from './core/auth/selectors';
|
import { isAuthenticationBlocking } from './core/auth/selectors';
|
||||||
import { AuthService } from './core/auth/auth.service';
|
import { AuthService } from './core/auth/auth.service';
|
||||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from './shared/sass-helper/css-variable.service';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { models } from './core/core.module';
|
import { models } from './core/core.module';
|
||||||
import { ThemeService } from './shared/theme-support/theme.service';
|
import { ThemeService } from './shared/theme-support/theme.service';
|
||||||
@@ -110,18 +110,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private storeCSSVariables() {
|
private storeCSSVariables() {
|
||||||
this.cssService.addCSSVariable('xlMin', '1200px');
|
this.cssService.clearCSSVariables();
|
||||||
this.cssService.addCSSVariable('mdMin', '768px');
|
this.cssService.addCSSVariables(this.cssService.getCSSVariablesFromStylesheets(this.document));
|
||||||
this.cssService.addCSSVariable('lgMin', '576px');
|
|
||||||
this.cssService.addCSSVariable('smMin', '0');
|
|
||||||
this.cssService.addCSSVariable('adminSidebarActiveBg', '#0f1b28');
|
|
||||||
this.cssService.addCSSVariable('sidebarItemsWidth', '250px');
|
|
||||||
this.cssService.addCSSVariable('collapsedSidebarWidth', '53.234px');
|
|
||||||
this.cssService.addCSSVariable('totalSidebarWidth', '303.234px');
|
|
||||||
// const vars = variables.locals || {};
|
|
||||||
// Object.keys(vars).forEach((name: string) => {
|
|
||||||
// this.cssService.addCSSVariable(name, vars[name]);
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
|
@@ -35,7 +35,7 @@ import {
|
|||||||
ObjectSelectionListState,
|
ObjectSelectionListState,
|
||||||
objectSelectionReducer
|
objectSelectionReducer
|
||||||
} from './shared/object-select/object-select.reducer';
|
} from './shared/object-select/object-select.reducer';
|
||||||
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/css-variable.reducer';
|
||||||
|
|
||||||
import { hostWindowReducer, HostWindowState } from './shared/search/host-window.reducer';
|
import { hostWindowReducer, HostWindowState } from './shared/search/host-window.reducer';
|
||||||
import {
|
import {
|
||||||
|
@@ -23,7 +23,6 @@ import { NotificationsService } from '../shared/notifications/notifications.serv
|
|||||||
import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service';
|
import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service';
|
||||||
import { ObjectSelectService } from '../shared/object-select/object-select.service';
|
import { ObjectSelectService } from '../shared/object-select/object-select.service';
|
||||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
|
||||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||||
import { UploaderService } from '../shared/uploader/uploader.service';
|
import { UploaderService } from '../shared/uploader/uploader.service';
|
||||||
import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service';
|
import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service';
|
||||||
@@ -257,7 +256,6 @@ const PROVIDERS = [
|
|||||||
DefaultChangeAnalyzer,
|
DefaultChangeAnalyzer,
|
||||||
ArrayMoveChangeAnalyzer,
|
ArrayMoveChangeAnalyzer,
|
||||||
ObjectSelectService,
|
ObjectSelectService,
|
||||||
CSSVariableService,
|
|
||||||
MenuService,
|
MenuService,
|
||||||
ObjectUpdatesService,
|
ObjectUpdatesService,
|
||||||
SearchService,
|
SearchService,
|
||||||
|
@@ -17,7 +17,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { RouterMock } from '../shared/mocks/router.mock';
|
import { RouterMock } from '../shared/mocks/router.mock';
|
||||||
import { MockActivatedRoute } from '../shared/mocks/active-router.mock';
|
import { MockActivatedRoute } from '../shared/mocks/active-router.mock';
|
||||||
import { MenuService } from '../shared/menu/menu.service';
|
import { MenuService } from '../shared/menu/menu.service';
|
||||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../shared/sass-helper/css-variable.service';
|
||||||
import { CSSVariableServiceStub } from '../shared/testing/css-variable-service.stub';
|
import { CSSVariableServiceStub } from '../shared/testing/css-variable-service.stub';
|
||||||
import { HostWindowService } from '../shared/host-window.service';
|
import { HostWindowService } from '../shared/host-window.service';
|
||||||
import { HostWindowServiceStub } from '../shared/testing/host-window-service.stub';
|
import { HostWindowServiceStub } from '../shared/testing/host-window-service.stub';
|
||||||
|
@@ -10,7 +10,7 @@ import { MetadataService } from '../core/metadata/metadata.service';
|
|||||||
import { HostWindowState } from '../shared/search/host-window.reducer';
|
import { HostWindowState } from '../shared/search/host-window.reducer';
|
||||||
import { NativeWindowRef, NativeWindowService } from '../core/services/window.service';
|
import { NativeWindowRef, NativeWindowService } from '../core/services/window.service';
|
||||||
import { AuthService } from '../core/auth/auth.service';
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from '../shared/sass-helper/css-variable.service';
|
||||||
import { MenuService } from '../shared/menu/menu.service';
|
import { MenuService } from '../shared/menu/menu.service';
|
||||||
import { HostWindowService } from '../shared/host-window.service';
|
import { HostWindowService } from '../shared/host-window.service';
|
||||||
import { ThemeConfig } from '../../config/theme.model';
|
import { ThemeConfig } from '../../config/theme.model';
|
||||||
@@ -63,8 +63,8 @@ export class RootComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
|
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
|
||||||
|
|
||||||
this.collapsedSidebarWidth = this.cssService.getVariable('collapsedSidebarWidth');
|
this.collapsedSidebarWidth = this.cssService.getVariable('--ds-collapsed-sidebar-width');
|
||||||
this.totalSidebarWidth = this.cssService.getVariable('totalSidebarWidth');
|
this.totalSidebarWidth = this.cssService.getVariable('--ds-total-sidebar-width');
|
||||||
|
|
||||||
const sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN);
|
const sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN);
|
||||||
this.slideSidebarOver = combineLatestObservable([sidebarCollapsed, this.windowService.isXsOrSm()])
|
this.slideSidebarOver = combineLatestObservable([sidebarCollapsed, this.windowService.isXsOrSm()])
|
||||||
|
@@ -7,7 +7,7 @@ import { createSelector, select, Store } from '@ngrx/store';
|
|||||||
|
|
||||||
import { hasValue } from './empty.util';
|
import { hasValue } from './empty.util';
|
||||||
import { AppState } from '../app.reducer';
|
import { AppState } from '../app.reducer';
|
||||||
import { CSSVariableService } from './sass-helper/sass-helper.service';
|
import { CSSVariableService } from './sass-helper/css-variable.service';
|
||||||
|
|
||||||
export enum WidthCategory {
|
export enum WidthCategory {
|
||||||
XS,
|
XS,
|
||||||
@@ -31,10 +31,10 @@ export class HostWindowService {
|
|||||||
/* See _exposed_variables.scss */
|
/* See _exposed_variables.scss */
|
||||||
variableService.getAllVariables()
|
variableService.getAllVariables()
|
||||||
.subscribe((variables) => {
|
.subscribe((variables) => {
|
||||||
this.breakPoints.XL_MIN = parseInt(variables.xlMin, 10);
|
this.breakPoints.XL_MIN = parseInt(variables['--bs-xl-min'], 10);
|
||||||
this.breakPoints.LG_MIN = parseInt(variables.lgMin, 10);
|
this.breakPoints.LG_MIN = parseInt(variables['--bs-lg-min'], 10);
|
||||||
this.breakPoints.MD_MIN = parseInt(variables.mdMin, 10);
|
this.breakPoints.MD_MIN = parseInt(variables['--bs-md-min'], 10);
|
||||||
this.breakPoints.SM_MIN = parseInt(variables.smMin, 10);
|
this.breakPoints.SM_MIN = parseInt(variables['--bs-sm-min'], 10);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
src/app/shared/key-value-pair.model.ts
Normal file
4
src/app/shared/key-value-pair.model.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface KeyValuePair<K, V> {
|
||||||
|
key: K;
|
||||||
|
value: V;
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
|
/* eslint-disable max-classes-per-file */
|
||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
import { type } from '../ngrx/type';
|
import { type } from '../ngrx/type';
|
||||||
|
import { KeyValuePair } from '../key-value-pair.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For each action type in an action group, make a simple
|
* For each action type in an action group, make a simple
|
||||||
@@ -11,6 +13,8 @@ import { type } from '../ngrx/type';
|
|||||||
*/
|
*/
|
||||||
export const CSSVariableActionTypes = {
|
export const CSSVariableActionTypes = {
|
||||||
ADD: type('dspace/css-variables/ADD'),
|
ADD: type('dspace/css-variables/ADD'),
|
||||||
|
ADD_ALL: type('dspace/css-variables/ADD_ALL'),
|
||||||
|
CLEAR: type('dspace/css-variables/CLEAR'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export class AddCSSVariableAction implements Action {
|
export class AddCSSVariableAction implements Action {
|
||||||
@@ -24,5 +28,17 @@ export class AddCSSVariableAction implements Action {
|
|||||||
this.payload = {name, value};
|
this.payload = {name, value};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export class AddAllCSSVariablesAction implements Action {
|
||||||
|
type = CSSVariableActionTypes.ADD_ALL;
|
||||||
|
payload: KeyValuePair<string, string>[];
|
||||||
|
|
||||||
export type CSSVariableAction = AddCSSVariableAction;
|
constructor(variables: KeyValuePair<string, string>[]) {
|
||||||
|
this.payload = variables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClearCSSVariablesAction implements Action {
|
||||||
|
type = CSSVariableActionTypes.CLEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CSSVariableAction = AddCSSVariableAction | AddAllCSSVariablesAction | ClearCSSVariablesAction;
|
30
src/app/shared/sass-helper/css-variable.reducer.ts
Normal file
30
src/app/shared/sass-helper/css-variable.reducer.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { CSSVariableAction, CSSVariableActionTypes } from './css-variable.actions';
|
||||||
|
import { KeyValuePair } from '../key-value-pair.model';
|
||||||
|
|
||||||
|
export interface CSSVariablesState {
|
||||||
|
[name: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: CSSVariablesState = Object.create({});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reducer that handles the state of CSS variables in the store
|
||||||
|
* @param state The current state of the store
|
||||||
|
* @param action The action to apply onto the current state of the store
|
||||||
|
*/
|
||||||
|
export function cssVariablesReducer(state = initialState, action: CSSVariableAction): CSSVariablesState {
|
||||||
|
switch (action.type) {
|
||||||
|
case CSSVariableActionTypes.ADD: {
|
||||||
|
const variable = action.payload;
|
||||||
|
return Object.assign({}, state, { [variable.name]: variable.value });
|
||||||
|
} case CSSVariableActionTypes.ADD_ALL: {
|
||||||
|
const variables = action.payload;
|
||||||
|
return Object.assign({}, state, ...variables.map(({ key, value }: KeyValuePair<string, string>) => {return {[key]: value};}));
|
||||||
|
} case CSSVariableActionTypes.CLEAR: {
|
||||||
|
return initialState;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
src/app/shared/sass-helper/css-variable.service.spec.ts
Normal file
78
src/app/shared/sass-helper/css-variable.service.spec.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { CSSVariableService } from './css-variable.service';
|
||||||
|
import { MockStore, provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { getTestScheduler } from 'jasmine-marbles';
|
||||||
|
import { buildPaginatedList } from '../../core/data/paginated-list.model';
|
||||||
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
|
import { KeyValuePair } from '../key-value-pair.model';
|
||||||
|
|
||||||
|
describe('CSSVariableService', () => {
|
||||||
|
let store: MockStore;
|
||||||
|
|
||||||
|
let service: CSSVariableService;
|
||||||
|
let initialState;
|
||||||
|
const varKey1 = '--test-1';
|
||||||
|
const varValue1 = 'test-value-1';
|
||||||
|
const varKey2 = '--test-2';
|
||||||
|
const varValue2 = 'test-value-2';
|
||||||
|
const varKey3 = '--test-3';
|
||||||
|
const varValue3 = 'test-value-3';
|
||||||
|
const queryInAll = 'test';
|
||||||
|
const queryFor3 = '3';
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
initialState = {
|
||||||
|
['cssVariables']: {
|
||||||
|
[varKey1]: varValue1,
|
||||||
|
[varKey2]: varValue2,
|
||||||
|
[varKey3]: varValue3,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
init();
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
CSSVariableService,
|
||||||
|
provideMockStore({ initialState }),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
service = TestBed.inject(CSSVariableService as any);
|
||||||
|
store = TestBed.inject(MockStore as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('searchVariable', () => {
|
||||||
|
it('should return the right keys and variables in a paginated list for query that returns all 3 results', () => {
|
||||||
|
const currentPage = 1;
|
||||||
|
const pageSize = 5;
|
||||||
|
const pageInfo = new PageInfo({ currentPage, elementsPerPage: pageSize, totalPages: 1, totalElements: 3 });
|
||||||
|
const page: KeyValuePair<string, string>[] = [{ key: varKey1, value: varValue1 }, { key: varKey2, value: varValue2 }, { key: varKey3, value: varValue3 }];
|
||||||
|
const result = buildPaginatedList(pageInfo, page);
|
||||||
|
getTestScheduler().expectObservable(service.searchVariable(queryInAll, { currentPage, pageSize } as any)).toBe('a', { a: result });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the right keys and variables in a paginated list for query that returns only the 3rd results', () => {
|
||||||
|
const currentPage = 1;
|
||||||
|
const pageSize = 5;
|
||||||
|
const pageInfo = new PageInfo({ currentPage, elementsPerPage: pageSize, totalPages: 1, totalElements: 1 });
|
||||||
|
const page: KeyValuePair<string, string>[] = [{ key: varKey3, value: varValue3 }];
|
||||||
|
const result = buildPaginatedList(pageInfo, page);
|
||||||
|
getTestScheduler().expectObservable(service.searchVariable(queryFor3, { currentPage, pageSize } as any)).toBe('a', { a: result });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the right keys and variables in a paginated list that\'s not longer than the page size', () => {
|
||||||
|
const currentPage = 1;
|
||||||
|
const pageSize = 2;
|
||||||
|
const pageInfo = new PageInfo({ currentPage, elementsPerPage: pageSize, totalPages: 2, totalElements: 3 });
|
||||||
|
const page: KeyValuePair<string, string>[] = [{ key: varKey1, value: varValue1 }, { key: varKey2, value: varValue2 }];
|
||||||
|
const result = buildPaginatedList(pageInfo, page);
|
||||||
|
getTestScheduler().expectObservable(service.searchVariable(queryInAll, { currentPage, pageSize } as any)).toBe('a', { a: result });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
161
src/app/shared/sass-helper/css-variable.service.ts
Normal file
161
src/app/shared/sass-helper/css-variable.service.ts
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { AppState, keySelector } from '../../app.reducer';
|
||||||
|
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||||
|
import { AddAllCSSVariablesAction, AddCSSVariableAction, ClearCSSVariablesAction } from './css-variable.actions';
|
||||||
|
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
||||||
|
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { hasValue, isNotEmpty } from '../empty.util';
|
||||||
|
import { KeyValuePair } from '../key-value-pair.model';
|
||||||
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
|
import { CSSVariablesState } from './css-variable.reducer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This service deals with adding and retrieving CSS variables to and from the store
|
||||||
|
*/
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CSSVariableService {
|
||||||
|
isSameDomain = (styleSheet) => {
|
||||||
|
// Internal style blocks won't have an href value
|
||||||
|
if (!styleSheet.href) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return styleSheet.href.indexOf(window.location.origin) === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Determine if the given rule is a CSSStyleRule
|
||||||
|
See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants
|
||||||
|
*/
|
||||||
|
isStyleRule = (rule) => rule.type === 1;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected store: Store<AppState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a CSS variable to the store
|
||||||
|
* @param name The name/key of the CSS variable
|
||||||
|
* @param value The value of the CSS variable
|
||||||
|
*/
|
||||||
|
addCSSVariable(name: string, value: string) {
|
||||||
|
this.store.dispatch(new AddCSSVariableAction(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds multiples CSS variables to the store
|
||||||
|
* @param variables The key-value pairs with the CSS variables to be added
|
||||||
|
*/
|
||||||
|
addCSSVariables(variables: KeyValuePair<string, string>[]) {
|
||||||
|
this.store.dispatch(new AddAllCSSVariablesAction(variables));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all CSS variables ƒrom the store
|
||||||
|
*/
|
||||||
|
clearCSSVariables() {
|
||||||
|
this.store.dispatch(new ClearCSSVariablesAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of a specific CSS key
|
||||||
|
* @param name The name/key of the CSS value
|
||||||
|
*/
|
||||||
|
getVariable(name: string): Observable<string> {
|
||||||
|
return this.store.pipe(select(themeVariableByNameSelector(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CSSVariablesState of the store containing all variables
|
||||||
|
*/
|
||||||
|
getAllVariables(): Observable<CSSVariablesState> {
|
||||||
|
return this.store.pipe(select(themeVariablesSelector));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to find CSS variables by their partially supplying their key. Case sensitive. Returns a paginated list of KeyValuePairs with CSS variables that match the query.
|
||||||
|
* @param query The query to look for in the keys
|
||||||
|
* @param paginationOptions The pagination options for the requested page
|
||||||
|
*/
|
||||||
|
searchVariable(query: string, paginationOptions: PaginationComponentOptions): Observable<PaginatedList<KeyValuePair<string, string>>> {
|
||||||
|
return this.store.pipe(select(themePaginatedVariablesByQuery(query, paginationOptions)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all custom properties on a page
|
||||||
|
* @return array<KeyValuePair<string, string>>
|
||||||
|
* ex; [{key: "--color-accent", value: "#b9f500"}, {key: "--color-text", value: "#252525"}, ...]
|
||||||
|
*/
|
||||||
|
getCSSVariablesFromStylesheets(document: Document): KeyValuePair<string, string>[] {
|
||||||
|
if (isNotEmpty(document.styleSheets)) {
|
||||||
|
// styleSheets is array-like, so we convert it to an array.
|
||||||
|
// Filter out any stylesheets not on this domain
|
||||||
|
return [...document.styleSheets]
|
||||||
|
.filter(this.isSameDomain)
|
||||||
|
.reduce(
|
||||||
|
(finalArr, sheet) =>
|
||||||
|
finalArr.concat(
|
||||||
|
// cssRules is array-like, so we convert it to an array
|
||||||
|
[...sheet.cssRules].filter(this.isStyleRule).reduce((propValArr, rule: any) => {
|
||||||
|
const props = [...rule.style]
|
||||||
|
.map((propName) => {
|
||||||
|
return {
|
||||||
|
key: propName.trim(),
|
||||||
|
value: rule.style.getPropertyValue(propName).trim()
|
||||||
|
} as KeyValuePair<string, string>;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// Discard any props that don't start with "--". Custom props are required to.
|
||||||
|
.filter(({ key }: KeyValuePair<string, string>) => key.indexOf('--') === 0);
|
||||||
|
|
||||||
|
return [...propValArr, ...props];
|
||||||
|
}, [])
|
||||||
|
),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const themeVariablesSelector = (state: AppState) => state.cssVariables;
|
||||||
|
|
||||||
|
const themeVariableByNameSelector = (name: string): MemoizedSelector<AppState, string> => {
|
||||||
|
return keySelector<string>(name, themeVariablesSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Split this up into two memoized selectors so the query search gets cached separately from the pagination,
|
||||||
|
// since the entire list has to be retrieved every time anyway
|
||||||
|
const themePaginatedVariablesByQuery = (query: string, pagination: PaginationComponentOptions): MemoizedSelector<AppState, PaginatedList<KeyValuePair<string, string>>> => {
|
||||||
|
return createSelector(themeVariablesByQuery(query), (pairs) => {
|
||||||
|
if (hasValue(pairs)) {
|
||||||
|
const { currentPage, pageSize } = pagination;
|
||||||
|
const startIndex = (currentPage - 1) * pageSize;
|
||||||
|
const endIndex = startIndex + pageSize;
|
||||||
|
const pairsPage = pairs.slice(startIndex, endIndex);
|
||||||
|
const totalPages = Math.ceil(pairs.length / pageSize);
|
||||||
|
const pageInfo = new PageInfo({ currentPage, elementsPerPage: pageSize, totalElements: pairs.length, totalPages });
|
||||||
|
return buildPaginatedList(pageInfo, pairsPage);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const themeVariablesByQuery = (query: string): MemoizedSelector<AppState, KeyValuePair<string, string>[]> => {
|
||||||
|
return createSelector(themeVariablesSelector, (state) => {
|
||||||
|
if (hasValue(state)) {
|
||||||
|
return Object.keys(state)
|
||||||
|
.filter((key: string) => key.includes(query))
|
||||||
|
.map((key: string) => {
|
||||||
|
return { key, value: state[key] };
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@@ -1,20 +0,0 @@
|
|||||||
import { CSSVariableAction, CSSVariableActionTypes } from './sass-helper.actions';
|
|
||||||
|
|
||||||
export interface CSSVariablesState {
|
|
||||||
[name: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: CSSVariablesState = Object.create({});
|
|
||||||
|
|
||||||
export function cssVariablesReducer(state = initialState, action: CSSVariableAction): CSSVariablesState {
|
|
||||||
switch (action.type) {
|
|
||||||
case CSSVariableActionTypes.ADD: {
|
|
||||||
const variable = action.payload;
|
|
||||||
const t = Object.assign({}, state, { [variable.name]: variable.value });
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { AppState, keySelector } from '../../app.reducer';
|
|
||||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
|
||||||
import { AddCSSVariableAction } from './sass-helper.actions';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CSSVariableService {
|
|
||||||
constructor(
|
|
||||||
protected store: Store<AppState>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
addCSSVariable(name: string, value: string) {
|
|
||||||
this.store.dispatch(new AddCSSVariableAction(name, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
getVariable(name: string) {
|
|
||||||
return this.store.pipe(select(themeVariableByNameSelector(name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllVariables() {
|
|
||||||
return this.store.pipe(select(themeVariablesSelector));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const themeVariablesSelector = (state: AppState) => state.cssVariables;
|
|
||||||
|
|
||||||
const themeVariableByNameSelector = (name: string): MemoizedSelector<AppState, string> => {
|
|
||||||
return keySelector<string>(name, themeVariablesSelector);
|
|
||||||
};
|
|
@@ -1,10 +1,11 @@
|
|||||||
import { Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { KeyValuePair } from '../key-value-pair.model';
|
||||||
|
|
||||||
const variables = {
|
const variables = {
|
||||||
smMin: '576px,',
|
'--bs-sm-min': '576px,',
|
||||||
mdMin: '768px,',
|
'--bs-md-min': '768px,',
|
||||||
lgMin: '992px',
|
'--bs-lg-min': '992px',
|
||||||
xlMin: '1200px',
|
'--bs-xl-min': '1200px',
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
export class CSSVariableServiceStub {
|
export class CSSVariableServiceStub {
|
||||||
@@ -19,4 +20,16 @@ export class CSSVariableServiceStub {
|
|||||||
addCSSVariable(name: string, value: string): void {
|
addCSSVariable(name: string, value: string): void {
|
||||||
/**/
|
/**/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addCSSVariables(variablesToAdd: KeyValuePair<string, string>[]): void {
|
||||||
|
/**/
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCSSVariables(): void {
|
||||||
|
/**/
|
||||||
|
}
|
||||||
|
|
||||||
|
getCSSVariablesFromStylesheets(document: Document): void {
|
||||||
|
/**/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,6 @@ import { LocaleService } from '../../app/core/locale/locale.service';
|
|||||||
import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider';
|
import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider';
|
||||||
import { MetadataService } from '../../app/core/metadata/metadata.service';
|
import { MetadataService } from '../../app/core/metadata/metadata.service';
|
||||||
import { BreadcrumbsService } from '../../app/breadcrumbs/breadcrumbs.service';
|
import { BreadcrumbsService } from '../../app/breadcrumbs/breadcrumbs.service';
|
||||||
import { CSSVariableService } from '../../app/shared/sass-helper/sass-helper.service';
|
|
||||||
import { ThemeService } from '../../app/shared/theme-support/theme.service';
|
import { ThemeService } from '../../app/shared/theme-support/theme.service';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ export class ServerInitService extends InitService {
|
|||||||
protected angulartics2DSpace: Angulartics2DSpace,
|
protected angulartics2DSpace: Angulartics2DSpace,
|
||||||
protected metadata: MetadataService,
|
protected metadata: MetadataService,
|
||||||
protected breadcrumbsService: BreadcrumbsService,
|
protected breadcrumbsService: BreadcrumbsService,
|
||||||
protected cssService: CSSVariableService,
|
|
||||||
protected themeService: ThemeService,
|
protected themeService: ThemeService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
|
Reference in New Issue
Block a user