refactor(project): Renamed all instances of dafa to msfa or mina-sidor-fa. (TV-379)
Squashed commit of the following: commit d3f52ff6876f6e246c7d3c188e56cc2370289341 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Aug 17 14:10:38 2021 +0200 Renamed all dafa instances to msfa
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<a class="back-link" [routerLink]="route">
|
||||
<msfa-icon [icon]="iconType.ARROW_LEFT"></msfa-icon>
|
||||
<ng-content></ng-content>
|
||||
</a>
|
||||
@@ -0,0 +1,11 @@
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
font-weight: var(--digi--typography--font-weight--semibold);
|
||||
gap: var(--digi--layout--gutter--xs);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BackLinkComponent } from './back-link.component';
|
||||
|
||||
describe('BackLinkComponent', () => {
|
||||
let component: BackLinkComponent;
|
||||
let fixture: ComponentFixture<BackLinkComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [BackLinkComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BackLinkComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-back-link',
|
||||
templateUrl: './back-link.component.html',
|
||||
styleUrls: ['./back-link.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BackLinkComponent {
|
||||
@Input() route: string[];
|
||||
iconType = IconType;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '../icon/icon.module';
|
||||
import { BackLinkComponent } from './back-link.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [BackLinkComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [BackLinkComponent],
|
||||
})
|
||||
export class BackLinkModule {}
|
||||
@@ -0,0 +1,8 @@
|
||||
<span class="hide-text">
|
||||
{{ transformedText }}
|
||||
<button class="hide-text__button" type="button" [attr.aria-label]="ariaLabel" (click)="toggleText()">
|
||||
<msfa-icon *ngIf="!hideText" [icon]="iconType.EYESLASH" size="l"></msfa-icon>
|
||||
<msfa-icon *ngIf="hideText" [icon]="iconType.EYE" size="l"></msfa-icon>
|
||||
<span class="hide-text__button-text">{{ hideText ? 'Visa' : 'Dölj'}}</span>
|
||||
</button>
|
||||
</span>
|
||||
@@ -0,0 +1,22 @@
|
||||
.hide-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--digi--layout--gutter);
|
||||
|
||||
&__button {
|
||||
background-color: transparent;
|
||||
color: var(--digi--typography--color--link);
|
||||
font-size: var(--digi--typography--font-size--desktop);
|
||||
border-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
color: var(--digi--typography--color--link--active);
|
||||
}
|
||||
}
|
||||
|
||||
&__button-text {
|
||||
margin-left: var(--digi--layout--gutter--s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { HideTextComponent } from './hide-text.component';
|
||||
|
||||
describe('HideTextComponent', () => {
|
||||
let component: HideTextComponent;
|
||||
let fixture: ComponentFixture<HideTextComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [HideTextComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HideTextComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-hide-text',
|
||||
templateUrl: './hide-text.component.html',
|
||||
styleUrls: ['./hide-text.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class HideTextComponent {
|
||||
@Input() changingText: string;
|
||||
@Input() symbols: string;
|
||||
@Input() ariaLabelType = 'text';
|
||||
|
||||
hideText = true;
|
||||
iconType = IconType;
|
||||
|
||||
get transformedText(): string {
|
||||
return this.hideText ? this.symbols : this.changingText;
|
||||
}
|
||||
|
||||
toggleText(): void {
|
||||
this.hideText = !this.hideText;
|
||||
}
|
||||
|
||||
get ariaLabel(): string {
|
||||
const buttonText = this.hideText ? 'Visa' : 'Dölj';
|
||||
return `${buttonText} ${this.ariaLabelType}`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { HideTextComponent } from './hide-text.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [HideTextComponent],
|
||||
imports: [CommonModule, IconModule],
|
||||
exports: [HideTextComponent],
|
||||
})
|
||||
export class HideTextModule {}
|
||||
@@ -0,0 +1,63 @@
|
||||
<digi-ng-icon-custom *ngIf="isCustomIcon; else DigiNgIcon" aria-hidden="true" class="icon" [ngClass]="[iconClass]">
|
||||
<svg *ngIf="icon === iconType.HOME" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" width="25" height="25">
|
||||
<path
|
||||
d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
<svg
|
||||
*ngIf="icon === iconType.SETTINGS"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
width="25"
|
||||
height="25"
|
||||
>
|
||||
<path
|
||||
d="M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<svg *ngIf="icon === iconType.PLUS" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="25" height="25">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<svg
|
||||
*ngIf="icon === iconType.CLIPBOARD"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
width="25"
|
||||
height="25"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M384 112v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h80c0-35.29 28.71-64 64-64s64 28.71 64 64h80c26.51 0 48 21.49 48 48zM192 40c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24m96 114v-20a6 6 0 0 0-6-6H102a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h180a6 6 0 0 0 6-6z"
|
||||
></path>
|
||||
</svg>
|
||||
</digi-ng-icon-custom>
|
||||
|
||||
<ng-template #DigiNgIcon>
|
||||
<ng-container [ngSwitch]="icon">
|
||||
<digi-icon-user-alt *ngSwitchCase="iconType.USER" [ngClass]="iconClass"></digi-icon-user-alt>
|
||||
<digi-icon-users-solid *ngSwitchCase="iconType.USERS" [ngClass]="iconClass"></digi-icon-users-solid>
|
||||
<digi-icon-bell *ngSwitchCase="iconType.BELL" [ngClass]="iconClass"></digi-icon-bell>
|
||||
<digi-icon-calendar-alt *ngSwitchCase="iconType.CALENDAR" [ngClass]="iconClass"></digi-icon-calendar-alt>
|
||||
<digi-icon-envelope-filled *ngSwitchCase="iconType.ENVELOPE" [ngClass]="iconClass"></digi-icon-envelope-filled>
|
||||
<digi-icon-sokkandidat *ngSwitchCase="iconType.SOK_KANDIDAT" [ngClass]="iconClass"></digi-icon-sokkandidat>
|
||||
<digi-icon-edit *ngSwitchCase="iconType.EDIT" [ngClass]="iconClass"></digi-icon-edit>
|
||||
<digi-icon-exclamation-circle *ngSwitchCase="iconType.INFO" [ngClass]="iconClass"></digi-icon-exclamation-circle>
|
||||
<digi-icon-exclamation-triangle
|
||||
*ngSwitchCase="iconType.WARNING"
|
||||
[ngClass]="iconClass"
|
||||
></digi-icon-exclamation-triangle>
|
||||
<digi-icon-check-circle-reg *ngSwitchCase="iconType.APPROVED" [ngClass]="iconClass"></digi-icon-check-circle-reg>
|
||||
<digi-icon-x *ngSwitchCase="iconType.X" [ngClass]="iconClass"></digi-icon-x>
|
||||
<digi-icon-arrow-left *ngSwitchCase="iconType.ARROW_LEFT" [ngClass]="iconClass"></digi-icon-arrow-left>
|
||||
<digi-icon-arrow-right *ngSwitchCase="iconType.ARROW_RIGHT" [ngClass]="iconClass"></digi-icon-arrow-right>
|
||||
<digi-icon-eye *ngSwitchCase="iconType.EYE" [ngClass]="iconClass"></digi-icon-eye>
|
||||
<digi-icon-eye-slash *ngSwitchCase="iconType.EYESLASH" [ngClass]="iconClass"></digi-icon-eye-slash>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,23 @@
|
||||
@import 'mixins/icon';
|
||||
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
&--s {
|
||||
@include msfa__digi-ng-icon(0.875em);
|
||||
}
|
||||
&--m {
|
||||
@include msfa__digi-ng-icon(1em);
|
||||
}
|
||||
&--l {
|
||||
@include msfa__digi-ng-icon(1.25em);
|
||||
}
|
||||
&--xl {
|
||||
@include msfa__digi-ng-icon(1.5em);
|
||||
}
|
||||
&--xxl {
|
||||
@include msfa__digi-ng-icon(2em);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { IconComponent } from './icon.component';
|
||||
|
||||
describe('IconComponent', () => {
|
||||
let component: IconComponent;
|
||||
let fixture: ComponentFixture<IconComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [IconComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(IconComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
|
||||
import { IconSize } from '@msfa-enums/icon-size.enum';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
const CUSTOM_ICONS: IconType[] = [IconType.HOME, IconType.SETTINGS, IconType.PLUS, IconType.CLIPBOARD];
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-icon',
|
||||
templateUrl: './icon.component.html',
|
||||
styleUrls: ['./icon.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class IconComponent implements OnChanges {
|
||||
@Input() icon: IconType;
|
||||
@Input() size: IconSize = IconSize.M;
|
||||
|
||||
iconClass: string;
|
||||
iconType = IconType;
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.iconClass = `icon--${this.size}`;
|
||||
}
|
||||
|
||||
get isCustomIcon(): boolean {
|
||||
return CUSTOM_ICONS.includes(this.icon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { IconComponent } from './icon.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [IconComponent],
|
||||
imports: [CommonModule],
|
||||
exports: [IconComponent],
|
||||
})
|
||||
export class IconModule {}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<footer class="footer">
|
||||
<div class="footer__logo-wrapper">
|
||||
<a class="footer__logo-link" href="/">
|
||||
<img class="footer__logo" src="/assets/logo/arbetsformedlingen-light.svg" alt="Arbetsförmedlingen" />
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
.footer {
|
||||
background-color: var(--digi--ui--color--background--profile);
|
||||
padding: var(--digi--layout--gutter);
|
||||
|
||||
&__logo-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
height: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
describe('FooterComponent', () => {
|
||||
let component: FooterComponent;
|
||||
let fixture: ComponentFixture<FooterComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FooterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-footer',
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FooterComponent {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [CommonModule, RouterModule],
|
||||
exports: [FooterComponent],
|
||||
})
|
||||
export class FooterModule {}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
@media print {
|
||||
.footer {
|
||||
border-bottom-width: 0;
|
||||
padding: var(--digi--layout--gutter) 0;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<div class="navigation">
|
||||
<div class="navigation__logo-wrapper">
|
||||
<a [routerLink]="['/']" aria-label="Till startsidan för FA Mina sidor">
|
||||
<digi-logo af-system-name="Mina sidor för fristående aktörer" af-color="secondary"></digi-logo>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="navigation__list msfa__hide-on-print">
|
||||
<li *ngIf="user" class="navigation__item">
|
||||
<div class="navigation__user">
|
||||
<msfa-icon [icon]="iconType.USER" size="l"></msfa-icon>
|
||||
<span class="navigation__text">{{ user.fullName }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="navigation__item">
|
||||
<a routerLink="/" class="navigation__link">
|
||||
<msfa-icon [icon]="iconType.BELL" size="l"></msfa-icon>
|
||||
<span class="navigation__text">Notiser</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
@import 'mixins/list';
|
||||
@import 'variables/breakpoints';
|
||||
@import 'variables/colors';
|
||||
@import 'variables/gutters';
|
||||
@import 'variables/navigation';
|
||||
|
||||
.navigation {
|
||||
background-color: var(--digi--ui--color--background--profile);
|
||||
border-bottom: 1px solid var(--digi--ui--color--background--off);
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 var(--digi--layout--gutter);
|
||||
height: $msfa__navigation-height;
|
||||
|
||||
@media (min-width: $digi--layout--breakpoint--m) {
|
||||
height: $msfa__navigation-height-large;
|
||||
}
|
||||
|
||||
&__logo-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
height: $msfa__navigation-height / 2.5;
|
||||
vertical-align: middle;
|
||||
|
||||
@media (min-width: $digi--layout--breakpoint--m) {
|
||||
height: $msfa__navigation-height-large / 2.5;
|
||||
}
|
||||
}
|
||||
|
||||
&__list {
|
||||
@include msfa__reset-list;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: $digi--layout--gutter--l;
|
||||
color: var(--digi--typography--color--text--light);
|
||||
margin-right: var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__user,
|
||||
&__link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: var(--digi--layout--gutter--s) var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: none;
|
||||
color: var(--digi--typography--color--text--light);
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 0.75rem;
|
||||
margin-top: var(--digi--layout--gutter--s);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { NavigationComponent } from './navigation.component';
|
||||
|
||||
describe('NavigationComponent', () => {
|
||||
let component: NavigationComponent;
|
||||
let fixture: ComponentFixture<NavigationComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [NavigationComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NavigationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
import { User } from '@msfa-models/user.model';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-navigation',
|
||||
templateUrl: './navigation.component.html',
|
||||
styleUrls: ['./navigation.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NavigationComponent {
|
||||
@Input() user: User;
|
||||
iconType = IconType;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { NavigationComponent } from './navigation.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [NavigationComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [NavigationComponent],
|
||||
})
|
||||
export class NavigationModule {}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
@media print {
|
||||
.navigation {
|
||||
border-bottom-width: 0;
|
||||
padding: var(--digi--layout--gutter) 0;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<nav class="sidebar" aria-label="Sidofält">
|
||||
<ul class="sidebar__list">
|
||||
<li class="sidebar__item">
|
||||
<a
|
||||
[routerLink]="['/']"
|
||||
[routerLinkActive]="['sidebar__link--active']"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
class="sidebar__link"
|
||||
>
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.HOME" size="xl"></msfa-icon>
|
||||
Hem
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/avrop']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.CLIPBOARD" size="xl"></msfa-icon>
|
||||
Avrop
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/deltagare']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.SOK_KANDIDAT" size="xl"></msfa-icon>
|
||||
Mina deltagare
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/planera-aktiviteter']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.USERS" size="xxl"></msfa-icon>
|
||||
Planera aktiviteter
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/rapportera']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.EDIT" size="xl"></msfa-icon>
|
||||
Rapportera
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/administration']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.SETTINGS" size="xl"></msfa-icon>
|
||||
Administration
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
@import 'variables/colors';
|
||||
@import 'variables/gutters';
|
||||
@import 'variables/navigation';
|
||||
@import 'mixins/list';
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: sticky;
|
||||
top: $msfa__navigation-height-large;
|
||||
|
||||
&__list {
|
||||
@include msfa__reset-list;
|
||||
}
|
||||
|
||||
&__link {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--digi--layout--gutter--xs);
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: $digi--layout--gutter--m var(--digi--layout--gutter);
|
||||
border-bottom: 1px solid var(--digi--ui--color--background--off);
|
||||
color: var(--digi--typography--color--text) !important;
|
||||
text-decoration: none;
|
||||
font-weight: var(--digi--typography--font-weight);
|
||||
font-size: var(--digi--typography--font-size--s);
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--digi--ui--color--background--tertiary);
|
||||
}
|
||||
|
||||
&--active {
|
||||
background-color: var(--digi--ui--color--background--tertiary);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 5px;
|
||||
background-color: var(--digi--ui--color--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: var(--digi--typography--color--link);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { SidebarComponent } from './sidebar.component';
|
||||
|
||||
describe('SidebarComponent', () => {
|
||||
let component: SidebarComponent;
|
||||
let fixture: ComponentFixture<SidebarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SidebarComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SidebarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-sidebar',
|
||||
templateUrl: './sidebar.component.html',
|
||||
styleUrls: ['./sidebar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SidebarComponent {
|
||||
iconType = IconType;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { SidebarComponent } from './sidebar.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SidebarComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [SidebarComponent],
|
||||
})
|
||||
export class SidebarModule {}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<a [attr.href]="skipLinkPath" class="skip-to-content">Gå till sidans innehåll</a>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
@import 'variables/colors';
|
||||
|
||||
.skip-to-content {
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
text-align: center;
|
||||
padding: var(--digi--layout--gutter--xs) var(--digi--layout--gutter);
|
||||
display: block;
|
||||
background-color: var(--digi--ui--color--complementary-alt);
|
||||
color: var(--digi--typography--color--text--light);
|
||||
|
||||
&:focus {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { SkipToContentComponent } from './skip-to-content.component';
|
||||
|
||||
describe('SkipToContentComponent', () => {
|
||||
let component: SkipToContentComponent;
|
||||
let fixture: ComponentFixture<SkipToContentComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [SkipToContentComponent],
|
||||
imports: [RouterTestingModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SkipToContentComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-skip-to-content',
|
||||
templateUrl: './skip-to-content.component.html',
|
||||
styleUrls: ['./skip-to-content.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SkipToContentComponent extends UnsubscribeDirective {
|
||||
@Input() mainContentId: string;
|
||||
skipLinkPath: string;
|
||||
|
||||
constructor(private router: Router, private changeDetectorRef: ChangeDetectorRef) {
|
||||
super();
|
||||
super.unsubscribeOnDestroy(
|
||||
this.router.events.pipe(filter((event: NavigationEnd) => event instanceof NavigationEnd)).subscribe(({ url }) => {
|
||||
const mainContentId = `#${this.mainContentId}`;
|
||||
// Check if the current URL already includes the mainContentId.
|
||||
const existsInUrl: boolean = url.substring(url.length - mainContentId.length, url.length) === mainContentId;
|
||||
|
||||
this.skipLinkPath = existsInUrl ? url : `${url}${mainContentId}`;
|
||||
this.changeDetectorRef.markForCheck();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SkipToContentComponent } from './skip-to-content.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SkipToContentComponent],
|
||||
imports: [CommonModule],
|
||||
exports: [SkipToContentComponent],
|
||||
})
|
||||
export class SkipToContentModule {}
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="msfa" *ngIf="isLoggedIn$ | async">
|
||||
<msfa-skip-to-content mainContentId="msfa-main-content"></msfa-skip-to-content>
|
||||
|
||||
<header class="msfa__header">
|
||||
<msfa-navigation [user]="user$ | async"></msfa-navigation>
|
||||
</header>
|
||||
|
||||
<msfa-sidebar class="msfa__sidebar"></msfa-sidebar>
|
||||
<main id="msfa-main-content" class="msfa__content">
|
||||
<digi-ng-navigation-breadcrumbs
|
||||
class="msfa__breadcrumbs"
|
||||
[afItems]="breadcrumbsItems"
|
||||
></digi-ng-navigation-breadcrumbs>
|
||||
|
||||
<ng-content></ng-content>
|
||||
</main>
|
||||
|
||||
<msfa-footer class="msfa__footer"></msfa-footer>
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
@import 'variables/navigation';
|
||||
@import 'variables/breakpoints';
|
||||
@import 'variables/gutters';
|
||||
|
||||
.msfa {
|
||||
display: grid;
|
||||
height: 100vh;
|
||||
grid-template-columns: 12rem 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-areas:
|
||||
'header header'
|
||||
'sidebar content'
|
||||
'footer footer';
|
||||
|
||||
// @media (min-width: $digi--layout--breakpoint--m) {
|
||||
// grid-template-rows: $msfa__navigation-height-large 1fr auto;
|
||||
// }
|
||||
|
||||
&__header {
|
||||
grid-area: header;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
grid-area: sidebar;
|
||||
background-color: var(--digi--ui--color--background--secondary);
|
||||
border-right: 1px solid var(--digi--ui--color--background--off);
|
||||
}
|
||||
|
||||
&__content {
|
||||
grid-area: content;
|
||||
max-width: $digi--layout--breakpoint--l;
|
||||
padding: var(--digi--layout--gutter) $digi--layout--gutter--l $digi--layout--gutter--xxl;
|
||||
}
|
||||
|
||||
&__breadcrumbs {
|
||||
display: block;
|
||||
margin-bottom: var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-area: footer;
|
||||
background-color: var(--digi--ui--color--primary);
|
||||
min-height: 10rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { LayoutComponent } from './Layout.component';
|
||||
|
||||
describe('LayoutComponent', () => {
|
||||
let component: LayoutComponent;
|
||||
let fixture: ComponentFixture<LayoutComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [LayoutComponent],
|
||||
imports: [RouterTestingModule, HttpClientTestingModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LayoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
|
||||
import { User } from '@msfa-models/user.model';
|
||||
import { AuthenticationService } from '@msfa-services/api/authentication.service';
|
||||
import { UserService } from '@msfa-services/api/user.service';
|
||||
import { mapPathsToBreadcrumbs } from '@msfa-utils/map-paths-to-breadcrumbs.util';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { filter, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
styleUrls: ['./layout.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class LayoutComponent extends UnsubscribeDirective {
|
||||
private startBreadcrumb: NavigationBreadcrumbsItem = {
|
||||
text: 'Start',
|
||||
routerLink: '/',
|
||||
};
|
||||
private _breadcrumbsItems$ = new BehaviorSubject<NavigationBreadcrumbsItem[]>([this.startBreadcrumb]);
|
||||
isLoggedIn$: Observable<boolean> = this.authService.isLoggedIn$;
|
||||
user$: Observable<User> = this.isLoggedIn$.pipe(
|
||||
filter(loggedIn => !!loggedIn),
|
||||
switchMap(() => this.userService.user$)
|
||||
);
|
||||
|
||||
get breadcrumbsItems(): NavigationBreadcrumbsItem[] {
|
||||
return this._breadcrumbsItems$.getValue();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private authService: AuthenticationService,
|
||||
private userService: UserService
|
||||
) {
|
||||
super();
|
||||
super.unsubscribeOnDestroy(
|
||||
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
|
||||
const urlTree = this.router.parseUrl(this.router.url);
|
||||
if (urlTree.queryParams.code) {
|
||||
void this.router.navigate([], {
|
||||
relativeTo: this.activatedRoute,
|
||||
queryParams: { code: null },
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
}
|
||||
urlTree.queryParams = {};
|
||||
const paths = urlTree
|
||||
.toString()
|
||||
.split('/')
|
||||
.filter(path => !!path);
|
||||
this._breadcrumbsItems$.next(mapPathsToBreadcrumbs(paths, this.startBreadcrumb));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { DigiNgNavigationBreadcrumbsModule } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import { FooterModule } from './components/footer/footer.module';
|
||||
import { NavigationModule } from './components/navigation/navigation.module';
|
||||
import { SidebarModule } from './components/sidebar/sidebar.module';
|
||||
import { SkipToContentModule } from './components/skip-to-content/skip-to-content.module';
|
||||
import { LayoutComponent } from './layout.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LayoutComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
SkipToContentModule,
|
||||
NavigationModule,
|
||||
SidebarModule,
|
||||
FooterModule,
|
||||
MarkdownModule.forRoot({ loader: HttpClient }),
|
||||
DigiNgNavigationBreadcrumbsModule,
|
||||
],
|
||||
exports: [LayoutComponent],
|
||||
})
|
||||
export class LayoutModule {}
|
||||
Reference in New Issue
Block a user