Merge pull request #4110 from jsaalfeld/logo_component
adding and implementing logo component
This commit is contained in:
commit
85a2597b27
@ -0,0 +1,3 @@
|
|||||||
|
<div *ngIf="getImage() != ''" class="logo-container">
|
||||||
|
<img [src]="getImage()">
|
||||||
|
</div>
|
10
client/src/app/shared/components/logo/logo.component.scss
Normal file
10
client/src/app/shared/components/logo/logo.component.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-container {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
25
client/src/app/shared/components/logo/logo.component.spec.ts
Normal file
25
client/src/app/shared/components/logo/logo.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
|
import { LogoComponent } from './logo.component';
|
||||||
|
|
||||||
|
describe('LogoComponent', () => {
|
||||||
|
let component: LogoComponent;
|
||||||
|
let fixture: ComponentFixture<LogoComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LogoComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
155
client/src/app/shared/components/logo/logo.component.ts
Normal file
155
client/src/app/shared/components/logo/logo.component.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { MediaManageService } from '../../../site/mediafiles/services/media-manage.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reusable Logo component for Apps.
|
||||||
|
*
|
||||||
|
* Following actions are possible:
|
||||||
|
* * "logo_projector_main"
|
||||||
|
* * "logo_projector_header"
|
||||||
|
* * "logo_web_header"
|
||||||
|
* * "logo_pdf_header_L"
|
||||||
|
* * "logo_pdf_header_R"
|
||||||
|
* * "logo_pdf_footer_L"
|
||||||
|
* * "logo_pdf_footer_R"
|
||||||
|
* * "logo_pdf_ballot_paper"
|
||||||
|
*
|
||||||
|
* ## Examples:
|
||||||
|
*
|
||||||
|
* ### Usage of the selector:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <os-logo
|
||||||
|
* inputAction="logo_projector_main"
|
||||||
|
* [footer]="false"
|
||||||
|
* [alignment]="right">
|
||||||
|
* </os-logo>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Sidenote: The footer variable is optional. Only if you want
|
||||||
|
* alternating logos, i.E. in the sidenav. the Alignment is also
|
||||||
|
* optional.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'os-logo',
|
||||||
|
templateUrl: './logo.component.html',
|
||||||
|
styleUrls: ['./logo.component.scss']
|
||||||
|
})
|
||||||
|
export class LogoComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* Constant path of the dark logo
|
||||||
|
*/
|
||||||
|
public static STANDARD_LOGO = '/assets/img/openslides-logo-h.svg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the actions for logos. Updated via an observable
|
||||||
|
*/
|
||||||
|
public logoActions: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decides based on the actionString how to display the logo
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public inputAction: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines if the current picture is displayed in the footer.
|
||||||
|
* Optional.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public footer = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* influences text-alignment in the .logo-container css class
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public alignment = 'center';
|
||||||
|
/**
|
||||||
|
* The consotructor
|
||||||
|
*
|
||||||
|
* @param mmservice The Media Manage Service
|
||||||
|
*/
|
||||||
|
public constructor(private mmservice: MediaManageService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization function
|
||||||
|
*/
|
||||||
|
public ngOnInit(): void {
|
||||||
|
this.mmservice.getLogoActions().subscribe(action => {
|
||||||
|
this.logoActions = action;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the image based on the inputAction and location.
|
||||||
|
* Possible inputActions are in the class description.
|
||||||
|
*
|
||||||
|
* @returns path to image
|
||||||
|
*/
|
||||||
|
public getImage(): string {
|
||||||
|
if (this.footer) {
|
||||||
|
const path = this.getFooterImage(this.inputAction);
|
||||||
|
return path;
|
||||||
|
} else {
|
||||||
|
const path = this.getHeaderImage(this.inputAction, this.alignment);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the header image based on logo action
|
||||||
|
*
|
||||||
|
* @param logoAction the logo action to be used
|
||||||
|
* @param alignment the alignment of the logo (optional)
|
||||||
|
* @returns path to image
|
||||||
|
*/
|
||||||
|
protected getHeaderImage(logoAction: string, alignment: string = 'center'): string {
|
||||||
|
if (alignment !== 'center') {
|
||||||
|
this.setAlignment(alignment);
|
||||||
|
}
|
||||||
|
let path = '';
|
||||||
|
/* check if datastore is loaded and custom logo can be read */
|
||||||
|
if (this.logoActions === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (this.mmservice !== undefined) {
|
||||||
|
if (this.mmservice.isImageConfigObject(this.mmservice.getMediaConfig(logoAction))) {
|
||||||
|
const imageConfig = this.mmservice.getMediaConfig(logoAction);
|
||||||
|
path = imageConfig.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path === '') {
|
||||||
|
path = LogoComponent.STANDARD_LOGO;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the alignment from center to either 'left' or 'right'
|
||||||
|
*
|
||||||
|
* @param alignment either 'right' or 'left'
|
||||||
|
*/
|
||||||
|
private setAlignment(alignment: string): void {
|
||||||
|
if (alignment === 'left' || alignment === 'right') {
|
||||||
|
const cssLogoContainer = document.getElementsByClassName('logo-container') as HTMLCollectionOf<HTMLElement>;
|
||||||
|
if (cssLogoContainer.length !== 0) {
|
||||||
|
cssLogoContainer[0].style.textAlign = alignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the image-path for the footer
|
||||||
|
*
|
||||||
|
* @param logoAction the logo action to be used
|
||||||
|
* @returns '' if no logo is set and path to standard logo if a custom
|
||||||
|
* logo was set
|
||||||
|
*/
|
||||||
|
protected getFooterImage(logoAction: string): string {
|
||||||
|
if (this.getHeaderImage(logoAction) === LogoComponent.STANDARD_LOGO || this.getHeaderImage(logoAction) === '') {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return LogoComponent.STANDARD_LOGO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -70,6 +70,7 @@ import { ChoiceDialogComponent } from './components/choice-dialog/choice-dialog.
|
|||||||
import { OsSortFilterBarComponent } from './components/os-sort-filter-bar/os-sort-filter-bar.component';
|
import { OsSortFilterBarComponent } from './components/os-sort-filter-bar/os-sort-filter-bar.component';
|
||||||
import { OsSortBottomSheetComponent } from './components/os-sort-filter-bar/os-sort-bottom-sheet/os-sort-bottom-sheet.component';
|
import { OsSortBottomSheetComponent } from './components/os-sort-filter-bar/os-sort-bottom-sheet/os-sort-bottom-sheet.component';
|
||||||
import { FilterMenuComponent } from './components/os-sort-filter-bar/filter-menu/filter-menu.component';
|
import { FilterMenuComponent } from './components/os-sort-filter-bar/filter-menu/filter-menu.component';
|
||||||
|
import { LogoComponent } from './components/logo/logo.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share Module for all "dumb" components and pipes.
|
* Share Module for all "dumb" components and pipes.
|
||||||
@ -171,7 +172,8 @@ import { FilterMenuComponent } from './components/os-sort-filter-bar/filter-menu
|
|||||||
EditorModule,
|
EditorModule,
|
||||||
SortingTreeComponent,
|
SortingTreeComponent,
|
||||||
TreeModule,
|
TreeModule,
|
||||||
OsSortFilterBarComponent
|
OsSortFilterBarComponent,
|
||||||
|
LogoComponent
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
PermsDirective,
|
PermsDirective,
|
||||||
@ -188,7 +190,8 @@ import { FilterMenuComponent } from './components/os-sort-filter-bar/filter-menu
|
|||||||
ChoiceDialogComponent,
|
ChoiceDialogComponent,
|
||||||
OsSortFilterBarComponent,
|
OsSortFilterBarComponent,
|
||||||
OsSortBottomSheetComponent,
|
OsSortBottomSheetComponent,
|
||||||
FilterMenuComponent
|
FilterMenuComponent,
|
||||||
|
LogoComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DateAdapter, useClass: OpenSlidesDateAdapter },
|
{ provide: DateAdapter, useClass: OpenSlidesDateAdapter },
|
||||||
|
@ -79,6 +79,18 @@ export class MediaManageService {
|
|||||||
return this.httpService.put<void>(restPath, payload);
|
return this.httpService.put<void>(restPath, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an image is an imageConfig Object
|
||||||
|
*
|
||||||
|
* @param object instance of something to check
|
||||||
|
* @returns boolean if an object is a ImageConfigObject
|
||||||
|
*/
|
||||||
|
public isImageConfigObject(object: any): object is ImageConfigObject {
|
||||||
|
if (object !== undefined) {
|
||||||
|
return (<ImageConfigObject>object).path !== undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all actions that can be executed on images
|
* Get all actions that can be executed on images
|
||||||
*
|
*
|
||||||
|
@ -10,10 +10,14 @@
|
|||||||
disableClose="!vp.isMobile"
|
disableClose="!vp.isMobile"
|
||||||
class="side-panel"
|
class="side-panel"
|
||||||
>
|
>
|
||||||
<mat-toolbar class="nav-toolbar">
|
<div class="nav-toolbar">
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<mat-toolbar-row class="os-logo-container" routerLink="/" (click)="toggleSideNav()"></mat-toolbar-row>
|
<a routerLink="/" (click)="toggleSideNav()">
|
||||||
</mat-toolbar>
|
<os-logo class="os-logo-container"
|
||||||
|
inputAction="logo_web_header"
|
||||||
|
[footer]="false"></os-logo>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- User Menu -->
|
<!-- User Menu -->
|
||||||
<mat-expansion-panel class="user-menu mat-elevation-z0">
|
<mat-expansion-panel class="user-menu mat-elevation-z0">
|
||||||
@ -118,6 +122,11 @@
|
|||||||
>
|
>
|
||||||
<span><small>© Copyright by OpenSlides</small></span>
|
<span><small>© Copyright by OpenSlides</small></span>
|
||||||
</a>
|
</a>
|
||||||
|
<div class="os-footer-logo-container">
|
||||||
|
<os-logo inputAction="logo_web_header"
|
||||||
|
footer="true">
|
||||||
|
</os-logo>
|
||||||
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</mat-sidenav>
|
</mat-sidenav>
|
||||||
<mat-sidenav-content>
|
<mat-sidenav-content>
|
||||||
|
@ -32,19 +32,35 @@ mat-sidenav-container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Logo container */
|
.nav-toolbar {
|
||||||
.os-logo-container {
|
display: flex;
|
||||||
width: 200px;
|
margin: auto;
|
||||||
margin-left: 10px;
|
width: 250px;
|
||||||
background-image: url(/assets/img/openslides-logo-h.svg);
|
height: 80px;
|
||||||
background-size: contain;
|
align-items: center;
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
/* The top logo container can contain any logo with any size.
|
||||||
|
It needs to always fit.*/
|
||||||
|
.os-logo-container {
|
||||||
|
margin: auto;
|
||||||
|
width: 250px !important;
|
||||||
|
max-height: 80px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The footer container only appears when custom logo is
|
||||||
|
specified. It can only contain the standard logo */
|
||||||
|
.os-footer-logo-container {
|
||||||
|
width: 150px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.os-logo-container:focus,
|
.os-logo-container:focus,
|
||||||
.os-logo-container:active,
|
.os-logo-container:active,
|
||||||
.os-logo-container:hover {
|
.os-logo-container:hover,
|
||||||
|
.os-footer-logo-container:focus,
|
||||||
|
.os-footer-logo-container:active,
|
||||||
|
.os-footer-logo-container:hover {
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user