Compare commits
No commits in common. "task-project-view-component-changes" and "develop" have entirely different histories.
task-proje
...
develop
@ -30,7 +30,6 @@
|
|||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
@ -107,7 +106,6 @@
|
|||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
@ -115,8 +113,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"cli": {
|
|
||||||
"analytics": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13696
package-lock.json
generated
13696
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -10,24 +10,22 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^20.2.0",
|
"@angular/animations": "^17.3.3",
|
||||||
"@angular/cdk": "^20.2.0",
|
"@angular/common": "^17.3.3",
|
||||||
"@angular/common": "^20.2.0",
|
"@angular/compiler": "^17.3.3",
|
||||||
"@angular/compiler": "^20.2.0",
|
"@angular/core": "^17.3.3",
|
||||||
"@angular/core": "^20.2.0",
|
"@angular/forms": "^17.3.3",
|
||||||
"@angular/forms": "^20.2.0",
|
"@angular/platform-browser": "^17.3.3",
|
||||||
"@angular/material": "^20.2.0",
|
"@angular/platform-browser-dynamic": "^17.3.3",
|
||||||
"@angular/platform-browser": "^20.2.0",
|
"@angular/router": "^17.3.3",
|
||||||
"@angular/platform-browser-dynamic": "^20.2.0",
|
|
||||||
"@angular/router": "^20.2.0",
|
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.14.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^20.2.0",
|
"@angular-devkit/build-angular": "^17.3.3",
|
||||||
"@angular/cli": "~20.2.0",
|
"@angular/cli": "~17.3.3",
|
||||||
"@angular/compiler-cli": "^20.2.0",
|
"@angular/compiler-cli": "^17.3.3",
|
||||||
"@types/jasmine": "~4.3.0",
|
"@types/jasmine": "~4.3.0",
|
||||||
"jasmine-core": "~4.6.0",
|
"jasmine-core": "~4.6.0",
|
||||||
"karma": "~6.4.0",
|
"karma": "~6.4.0",
|
||||||
@ -35,6 +33,6 @@
|
|||||||
"karma-coverage": "~2.2.0",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"typescript": "~5.8.0"
|
"typescript": "~5.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<article class="about active" data-page="about">
|
<article class="about active" data-page="about">
|
||||||
<header>
|
<header>
|
||||||
<h2 class="h2 article-title">About me</h2>
|
<h2 class="h2 article-title">About me</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { AboutComponent } from './about.component';
|
import { AboutComponent } from './about.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('AboutComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [AboutComponent, HttpClientTestingModule]
|
imports: [AboutComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
import { IAbout } from './about.model';
|
import { IAbout } from './about.model';
|
||||||
import { BaseComponent } from '../base/base.component';
|
import { BaseComponent } from '../base/base.component';
|
||||||
@ -7,9 +6,7 @@ import { BaseComponent } from '../base/base.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-about',
|
selector: 'app-about',
|
||||||
templateUrl: './about.component.html',
|
templateUrl: './about.component.html',
|
||||||
styleUrl: './about.component.scss',
|
styleUrl: './about.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class AboutComponent extends BaseComponent<IAbout> implements OnInit {
|
export class AboutComponent extends BaseComponent<IAbout> implements OnInit {
|
||||||
constructor(svc: CvService){
|
constructor(svc: CvService){
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { NgModule } from '@angular/core';
|
||||||
import { AboutComponent } from './about/about.component';
|
import { AboutComponent } from './about/about.component';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { ResumeComponent } from './resume/resume.component';
|
import { ResumeComponent } from './resume/resume.component';
|
||||||
import { ProjectsComponent } from './projects/projects.component';
|
import { ProjectsComponent } from './projects/projects.component';
|
||||||
import { BlogComponent } from './blog/blog.component';
|
import { BlogComponent } from './blog/blog.component';
|
||||||
import { ContactComponent } from './contact/contact.component';
|
import { ContactComponent } from './contact/contact.component';
|
||||||
|
|
||||||
export const appRoutes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', component: AboutComponent, title: "Bangara Raju Kottedi" },
|
{ path: '', component: AboutComponent, title: "Bangara Raju Kottedi" },
|
||||||
{ path: 'resume', component: ResumeComponent, title: "Bangara Raju Kottedi - Resume" },
|
{ path: 'resume', component: ResumeComponent, title: "Bangara Raju Kottedi - Resume" },
|
||||||
{ path: 'projects', component: ProjectsComponent, title: "Bangara Raju Kottedi - Projects" },
|
{ path: 'projects', component: ProjectsComponent, title: "Bangara Raju Kottedi - Projects" },
|
||||||
@ -13,3 +14,12 @@ export const appRoutes: Routes = [
|
|||||||
{ path: 'contact', component: ContactComponent, title: "Bangara Raju Kottedi - Contact" },
|
{ path: 'contact', component: ContactComponent, title: "Bangara Raju Kottedi - Contact" },
|
||||||
{ path: '**', redirectTo: '/'}
|
{ path: '**', redirectTo: '/'}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
RouterModule.forRoot(routes)
|
||||||
|
],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
||||||
|
|||||||
@ -1,18 +1,27 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
await TestBed.configureTestingModule({
|
declarations: [AppComponent]
|
||||||
imports: [AppComponent, HttpClientTestingModule, RouterTestingModule]
|
}));
|
||||||
}).compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create the app', () => {
|
it('should create the app', () => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.componentInstance;
|
const app = fixture.componentInstance;
|
||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'my-portfolio'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('my-portfolio');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement as HTMLElement;
|
||||||
|
expect(compiled.querySelector('.content span')?.textContent).toContain('my-portfolio app is running!');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
|
||||||
import { NavbarComponent } from './navbar/navbar.component';
|
|
||||||
import { ContactSidebarComponent } from './contact-sidebar/contact-sidebar.component';
|
|
||||||
import { SpinnerComponent } from './spinner/spinner.component';
|
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
|
||||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss'],
|
styleUrls: ['./app.component.scss']
|
||||||
standalone: true,
|
|
||||||
imports: [RouterOutlet, NavbarComponent, ContactSidebarComponent, SpinnerComponent]
|
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|||||||
40
src/app/app.module.ts
Normal file
40
src/app/app.module.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { ContactSidebarComponent } from './contact-sidebar/contact-sidebar.component';
|
||||||
|
import { NavbarComponent } from './navbar/navbar.component';
|
||||||
|
import { AboutComponent } from './about/about.component';
|
||||||
|
import { ResumeComponent } from './resume/resume.component';
|
||||||
|
import { ProjectsComponent } from './projects/projects.component';
|
||||||
|
import { BlogComponent } from './blog/blog.component';
|
||||||
|
import { ContactComponent } from './contact/contact.component';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { httpInterceptorProviders } from './http-interceptors';
|
||||||
|
import { SpinnerComponent } from './spinner/spinner.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
SpinnerComponent,
|
||||||
|
ContactSidebarComponent,
|
||||||
|
NavbarComponent,
|
||||||
|
AboutComponent,
|
||||||
|
ResumeComponent,
|
||||||
|
ProjectsComponent,
|
||||||
|
BlogComponent,
|
||||||
|
ContactComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
HttpClientModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
providers: [httpInterceptorProviders],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { BlogComponent } from './blog.component';
|
import { BlogComponent } from './blog.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('BlogComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [BlogComponent, HttpClientTestingModule]
|
imports: [BlogComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
import { BaseComponent } from '../base/base.component';
|
import { BaseComponent } from '../base/base.component';
|
||||||
import { IBlog } from './blog.model';
|
import { IBlog } from './blog.model';
|
||||||
@ -8,9 +7,7 @@ import { environment } from 'src/environments/environment';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-blog',
|
selector: 'app-blog',
|
||||||
templateUrl: './blog.component.html',
|
templateUrl: './blog.component.html',
|
||||||
styleUrl: './blog.component.scss',
|
styleUrl: './blog.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class BlogComponent extends BaseComponent<IBlog> implements OnInit{
|
export class BlogComponent extends BaseComponent<IBlog> implements OnInit{
|
||||||
blogUrl!: string;
|
blogUrl!: string;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { ContactSidebarComponent } from './contact-sidebar.component';
|
import { ContactSidebarComponent } from './contact-sidebar.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('ContactSidebarComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [ContactSidebarComponent, HttpClientTestingModule]
|
imports: [ContactSidebarComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { BaseComponent } from '../base/base.component';
|
import { BaseComponent } from '../base/base.component';
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
import { ISideBar } from './side-bar.model';
|
import { ISideBar } from './side-bar.model';
|
||||||
@ -7,9 +6,7 @@ import { ISideBar } from './side-bar.model';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-sidebar',
|
selector: 'app-contact-sidebar',
|
||||||
templateUrl: './contact-sidebar.component.html',
|
templateUrl: './contact-sidebar.component.html',
|
||||||
styleUrl: './contact-sidebar.component.scss',
|
styleUrl: './contact-sidebar.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class ContactSidebarComponent extends BaseComponent<ISideBar> implements OnInit {
|
export class ContactSidebarComponent extends BaseComponent<ISideBar> implements OnInit {
|
||||||
sideBarExpanded: boolean = false;
|
sideBarExpanded: boolean = false;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { ContactComponent } from './contact.component';
|
import { ContactComponent } from './contact.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('ContactComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [ContactComponent, HttpClientTestingModule]
|
imports: [ContactComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { FormsModule, FormBuilder, FormControl, NgForm } from '@angular/forms';
|
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
import { IContact } from './contact.model';
|
import { IContact } from './contact.model';
|
||||||
|
import { FormBuilder, FormControl, NgForm } from '@angular/forms';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact',
|
selector: 'app-contact',
|
||||||
templateUrl: './contact.component.html',
|
templateUrl: './contact.component.html',
|
||||||
styleUrl: './contact.component.scss',
|
styleUrl: './contact.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule, FormsModule]
|
|
||||||
})
|
})
|
||||||
export class ContactComponent {
|
export class ContactComponent {
|
||||||
messageModel: IContact = {name: '', email: '', content: '' };
|
messageModel: IContact = {name: '', email: '', content: '' };
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
import { HttpInterceptorFn } from "@angular/common/http";
|
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
|
||||||
import { inject } from "@angular/core";
|
import { Observable } from "rxjs";
|
||||||
import { AuthService } from "../services/auth.service";
|
import { AuthService } from "../services/auth.service";
|
||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
@Injectable()
|
||||||
const authSvc = inject(AuthService);
|
export class AuthInterceptor implements HttpInterceptor{
|
||||||
const apiKey = authSvc.getApiKey();
|
constructor(public authSvc: AuthService){}
|
||||||
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
const apiKey = this.authSvc.getApiKey();
|
||||||
|
|
||||||
const authReq = req.clone({
|
const authReq = req.clone({
|
||||||
headers: req.headers.set('XApiKey', apiKey)
|
headers: req.headers.set('XApiKey', apiKey)
|
||||||
});
|
});
|
||||||
|
|
||||||
return next(authReq);
|
return next.handle(authReq);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,9 @@
|
|||||||
import { authInterceptor } from "./auth.interceptor";
|
import { HTTP_INTERCEPTORS } from "@angular/common/http";
|
||||||
import { loadingInterceptor } from "./loading.interceptor";
|
|
||||||
|
|
||||||
export const httpInterceptors = [authInterceptor, loadingInterceptor];
|
import { AuthInterceptor } from "./auth.interceptor";
|
||||||
|
import { LoadingInterceptor } from "./loading.interceptor";
|
||||||
|
|
||||||
|
export const httpInterceptorProviders = [
|
||||||
|
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
|
||||||
|
{provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true}
|
||||||
|
]
|
||||||
@ -1,22 +1,27 @@
|
|||||||
import { HttpInterceptorFn } from "@angular/common/http";
|
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
|
||||||
import { inject } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { finalize } from "rxjs";
|
import { Observable, finalize } from "rxjs";
|
||||||
import { LoaderService } from "../services/loader.service";
|
import { LoaderService } from "../services/loader.service";
|
||||||
|
|
||||||
let totalRequests: number = 0;
|
@Injectable()
|
||||||
|
export class LoadingInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
export const loadingInterceptor: HttpInterceptorFn = (req, next) => {
|
private totalRequests: number = 0;
|
||||||
const loadingSvc = inject(LoaderService);
|
|
||||||
|
|
||||||
totalRequests++;
|
constructor(private loadingSvc: LoaderService) { }
|
||||||
loadingSvc.setLoading(true);
|
|
||||||
|
|
||||||
return next(req).pipe(
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
finalize(() => {
|
this.totalRequests++;
|
||||||
totalRequests--;
|
this.loadingSvc.setLoading(true);
|
||||||
if (totalRequests === 0) {
|
return next.handle(req).pipe(
|
||||||
loadingSvc.setLoading(false);
|
finalize(
|
||||||
}
|
() => {
|
||||||
})
|
this.totalRequests--;
|
||||||
);
|
if (this.totalRequests == 0) {
|
||||||
};
|
this.loadingSvc.setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,11 +8,4 @@ export interface IProject{
|
|||||||
responsibilities: string[];
|
responsibilities: string[];
|
||||||
technologiesUsed: string[];
|
technologiesUsed: string[];
|
||||||
imagePath: string;
|
imagePath: string;
|
||||||
challenges: string;
|
|
||||||
lessonsLearned: string;
|
|
||||||
impact: string;
|
|
||||||
startDate: string;
|
|
||||||
endDate: string;
|
|
||||||
status: string;
|
|
||||||
resumeId: number;
|
|
||||||
}
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
|
|
||||||
import { NavbarComponent } from './navbar.component';
|
import { NavbarComponent } from './navbar.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('NavbarComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [NavbarComponent, RouterTestingModule]
|
imports: [NavbarComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navbar',
|
selector: 'app-navbar',
|
||||||
templateUrl: './navbar.component.html',
|
templateUrl: './navbar.component.html',
|
||||||
styleUrl: './navbar.component.scss',
|
styleUrl: './navbar.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule, RouterModule]
|
|
||||||
})
|
})
|
||||||
export class NavbarComponent {
|
export class NavbarComponent {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
<div class="project-detail" role="dialog" aria-labelledby="project-title">
|
|
||||||
<div class="detail-header">
|
|
||||||
<h2 id="project-title">{{ project.name }}</h2>
|
|
||||||
<button class="close-btn" (click)="close()" aria-label="Close">
|
|
||||||
<i class="fa-solid fa-xmark"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (project.status) {
|
|
||||||
<span class="status-badge">{{ project.status }}</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.description) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Description</h4>
|
|
||||||
<p>{{ project.description }}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.roles.length) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Roles</h4>
|
|
||||||
<div class="tag-list">
|
|
||||||
@for (role of project.roles; track role) {
|
|
||||||
<span class="tag">{{ role }}</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.responsibilities.length) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Responsibilities</h4>
|
|
||||||
<div class="tag-list">
|
|
||||||
@for (r of project.responsibilities; track r) {
|
|
||||||
<span class="tag">{{ r }}</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.technologiesUsed.length) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Technologies</h4>
|
|
||||||
<div class="tag-list">
|
|
||||||
@for (tech of project.technologiesUsed; track tech) {
|
|
||||||
<span class="tag tech">{{ tech }}</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.startDate || project.endDate) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Duration</h4>
|
|
||||||
<p class="duration">
|
|
||||||
@if (project.startDate) {
|
|
||||||
<span>{{ project.startDate | date: 'MMM yyyy' }}</span>
|
|
||||||
}
|
|
||||||
@if (project.startDate && project.endDate) {
|
|
||||||
<span> — </span>
|
|
||||||
}
|
|
||||||
@if (project.endDate) {
|
|
||||||
<span>{{ project.endDate | date: 'MMM yyyy' }}</span>
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.challenges) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Challenges</h4>
|
|
||||||
<p>{{ project.challenges }}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.lessonsLearned) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Lessons Learned</h4>
|
|
||||||
<p>{{ project.lessonsLearned }}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.impact) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Impact</h4>
|
|
||||||
<p>{{ project.impact }}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (project.categories.length) {
|
|
||||||
<div class="detail-section">
|
|
||||||
<h4>Categories</h4>
|
|
||||||
<div class="tag-list">
|
|
||||||
@for (cat of project.categories; track cat) {
|
|
||||||
<span class="tag category">{{ cat }}</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
.project-detail {
|
|
||||||
padding: 24px;
|
|
||||||
color: var(--white-1, #fff);
|
|
||||||
max-height: 80vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
background: var(--eerie-black-2, #1e1e1e);
|
|
||||||
border: 1.2px solid hsla(45, 100%, 72%, 0.45);
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Override Material Dialog container defaults - must be global due to ViewEncapsulation.None */
|
|
||||||
.dark-popup-panel {
|
|
||||||
border-radius: 14px !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
|
|
||||||
.mat-dialog-container {
|
|
||||||
background: var(--eerie-black-2, #1e1e1e) !important;
|
|
||||||
border-radius: 14px !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
border: 2px solid rgba(227, 179, 65, 0.9) !important;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 0 0 1px rgba(255, 255, 255, 0.08),
|
|
||||||
0 8px 32px rgba(0, 0, 0, 0.5) !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
|
|
||||||
/* Ensure no white background shows */
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
border-radius: 14px;
|
|
||||||
pointer-events: none;
|
|
||||||
background: var(--eerie-black-2, #1e1e1e);
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 16px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.35rem;
|
|
||||||
color: var(--white-1, #fff);
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-btn {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
color: var(--light-gray-70, #aaa);
|
|
||||||
font-size: 1.1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 4px 6px;
|
|
||||||
border-radius: 6px;
|
|
||||||
transition: background 0.2s, color 0.2s;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
color: var(--white-1, #fff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-badge {
|
|
||||||
display: inline-block;
|
|
||||||
background: rgba(227, 179, 65, 0.15);
|
|
||||||
color: var(--orange-yellow-crayola, #e3b341);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 3px 10px;
|
|
||||||
border-radius: 12px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-section {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: 0 0 6px;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--light-gray-70, #999);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.55;
|
|
||||||
color: var(--white-2, #ddd);
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.duration {
|
|
||||||
color: var(--white-2, #ddd);
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 4px 10px;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 0.78rem;
|
|
||||||
background: rgba(255, 255, 255, 0.06);
|
|
||||||
color: var(--white-2, #ddd);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
||||||
|
|
||||||
&.tech {
|
|
||||||
background: rgba(100, 180, 255, 0.1);
|
|
||||||
color: #8cc4ff;
|
|
||||||
border-color: rgba(100, 180, 255, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.category {
|
|
||||||
background: rgba(227, 179, 65, 0.1);
|
|
||||||
color: var(--orange-yellow-crayola, #e3b341);
|
|
||||||
border-color: rgba(227, 179, 65, 0.15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
import { Component, inject, ViewEncapsulation } from '@angular/core';
|
|
||||||
import { CommonModule, DatePipe } from '@angular/common';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { IProject } from '../../models/project.model';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-project-detail-popup',
|
|
||||||
templateUrl: './project-detail-popup.html',
|
|
||||||
styleUrls: ['./project-detail-popup.scss'],
|
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule, DatePipe],
|
|
||||||
encapsulation: ViewEncapsulation.None
|
|
||||||
})
|
|
||||||
export class ProjectDetailPopupComponent {
|
|
||||||
private dialogRef = inject(MatDialogRef<ProjectDetailPopupComponent>);
|
|
||||||
project: IProject = inject(MAT_DIALOG_DATA);
|
|
||||||
|
|
||||||
close(): void {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,74 +1,70 @@
|
|||||||
<article class="projects" data-page="projects">
|
<article class="projects" data-page="projects">
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<h2 class="h2 article-title">Projects</h2>
|
<h2 class="h2 article-title">Projects</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="projects">
|
<section class="projects">
|
||||||
|
|
||||||
<ul class="filter-list">
|
<ul class="filter-list">
|
||||||
|
|
||||||
<li class="filter-item">
|
<li class="filter-item">
|
||||||
<button [ngClass]="{active: filter === 'All'}" (click)="filterProjects('All')">All</button>
|
<button [ngClass]="{active: filter === 'All'}" (click)="filterProjects('All')">All</button>
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="filter-item" *ngFor="let category of model.projectsCategories">
|
|
||||||
<button (click)="filterProjects(category)" [ngClass]="{active: filter === category}"
|
|
||||||
(click)="filter = category">{{category}}</button>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="filter-select-box" (click)="categoryClicked = !categoryClicked">
|
|
||||||
|
|
||||||
<button class="filter-select" [ngClass]="{active: categoryClicked}">
|
|
||||||
|
|
||||||
<div class="select-value">{{filter}}</div>
|
|
||||||
|
|
||||||
<div class="select-icon">
|
|
||||||
<i class="fa-regular fa-chevron-down"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul class="select-list">
|
|
||||||
|
|
||||||
<li class="select-item">
|
|
||||||
<button (click)="filterProjects('All')">All</button>
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="select-item" *ngFor="let category of model.projectsCategories">
|
<li class="filter-item" *ngFor="let category of model.projectsCategories">
|
||||||
<button (click)="filterProjects(category)">{{category}}</button>
|
<button (click)="filterProjects(category)" [ngClass]="{active: filter === category}" (click)="filter = category">{{category}}</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="project-list">
|
<div class="filter-select-box" (click)="categoryClicked = !categoryClicked">
|
||||||
|
|
||||||
<li class="project-item active" *ngFor="let project of projects">
|
<button class="filter-select" [ngClass]="{active: categoryClicked}" >
|
||||||
<a>
|
|
||||||
|
|
||||||
<figure class="project-img">
|
<div class="select-value">{{filter}}</div>
|
||||||
<button class="project-item-icon-box" (click)="openViewProject(project)"
|
|
||||||
(keyup.enter)="openViewProject(project)" title="View Project">
|
|
||||||
<i class="fa-regular fa-eye"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
|
<div class="select-icon">
|
||||||
<img src="{{imagesOrigin + project.imagePath}}" loading="lazy">
|
<i class="fa-regular fa-chevron-down"></i>
|
||||||
</figure>
|
|
||||||
|
|
||||||
<h3 class="project-title">{{project.name}}</h3>
|
|
||||||
<div class="project-category">
|
|
||||||
<span *ngFor="let responsbility of project.responsibilities; index as i" class="inline">{{i > 0 ? ', ' +
|
|
||||||
responsbility : responsbility}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
</button>
|
||||||
|
|
||||||
</section>
|
<ul class="select-list">
|
||||||
|
|
||||||
</article>
|
<li class="select-item">
|
||||||
|
<button (click)="filterProjects('All')">All</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="select-item" *ngFor="let category of model.projectsCategories">
|
||||||
|
<button (click)="filterProjects(category)">{{category}}</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="project-list">
|
||||||
|
|
||||||
|
<li class="project-item active" *ngFor="let project of projects">
|
||||||
|
<a>
|
||||||
|
|
||||||
|
<figure class="project-img">
|
||||||
|
<!-- <div class="project-item-icon-box">
|
||||||
|
<ion-icon name="eye-outline"></ion-icon>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<img src="{{imagesOrigin + project.imagePath}}" loading="lazy">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<h3 class="project-title">{{project.name}}</h3>
|
||||||
|
<div class="project-category">
|
||||||
|
<span *ngFor="let responsbility of project.responsibilities; index as i" class="inline">{{i > 0 ? ', ' + responsbility : responsbility}}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</article>
|
||||||
@ -1,19 +1,18 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { ProjectsComponent } from './projects.component';
|
import { PortfolioComponent } from './projects.component';
|
||||||
|
|
||||||
describe('ProjectsComponent', () => {
|
describe('PortfolioComponent', () => {
|
||||||
let component: ProjectsComponent;
|
let component: PortfolioComponent;
|
||||||
let fixture: ComponentFixture<ProjectsComponent>;
|
let fixture: ComponentFixture<PortfolioComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [ProjectsComponent, HttpClientTestingModule]
|
imports: [PortfolioComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ProjectsComponent);
|
fixture = TestBed.createComponent(PortfolioComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,27 +1,22 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Component, OnInit, Inject } from '@angular/core';
|
|
||||||
import { BaseComponent } from '../base/base.component';
|
import { BaseComponent } from '../base/base.component';
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
import { IProjects } from './projects.model';
|
import { IProjects } from './projects.model';
|
||||||
import { IProject } from '../models/project.model';
|
import { IProject } from '../models/project.model';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ProjectDetailPopupComponent } from './project-detail-popup/project-detail-popup';
|
|
||||||
import { MatDialog} from '@angular/material/dialog';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-projects',
|
selector: 'app-projects',
|
||||||
templateUrl: './projects.component.html',
|
templateUrl: './projects.component.html',
|
||||||
styleUrl: './projects.component.scss',
|
styleUrl: './projects.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class ProjectsComponent extends BaseComponent<IProjects> implements OnInit {
|
export class ProjectsComponent extends BaseComponent<IProjects> implements OnInit {
|
||||||
filter: string = 'All';
|
filter: string = 'All';
|
||||||
projects!: IProject[];
|
projects!: IProject[];
|
||||||
subscription: Subscription = <Subscription>{};
|
subscription: Subscription = <Subscription>{};
|
||||||
categoryClicked: boolean = false;
|
categoryClicked: boolean = false;
|
||||||
constructor(svc: CvService, public http: HttpClient, @Inject(MatDialog) private dialog: MatDialog){
|
constructor(svc: CvService, public http: HttpClient){
|
||||||
super(svc);
|
super(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,13 +41,4 @@ categoryClicked: boolean = false;
|
|||||||
return project.categories.includes(category)
|
return project.categories.includes(category)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openViewProject(project: IProject): void {
|
|
||||||
this.dialog.open(ProjectDetailPopupComponent, {
|
|
||||||
data: project,
|
|
||||||
panelClass: 'dark-popup-panel',
|
|
||||||
width: '520px',
|
|
||||||
maxHeight: '85vh'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { ResumeComponent } from './resume.component';
|
import { ResumeComponent } from './resume.component';
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ describe('ResumeComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [ResumeComponent, HttpClientTestingModule]
|
imports: [ResumeComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { BaseComponent } from '../base/base.component';
|
import { BaseComponent } from '../base/base.component';
|
||||||
import { IResume } from './resume.model';
|
import { IResume } from './resume.model';
|
||||||
import { CvService } from '../services/cv.service';
|
import { CvService } from '../services/cv.service';
|
||||||
@ -7,9 +6,7 @@ import { CvService } from '../services/cv.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-resume',
|
selector: 'app-resume',
|
||||||
templateUrl: './resume.component.html',
|
templateUrl: './resume.component.html',
|
||||||
styleUrl: './resume.component.scss',
|
styleUrl: './resume.component.scss'
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class ResumeComponent extends BaseComponent<IResume> implements OnInit {
|
export class ResumeComponent extends BaseComponent<IResume> implements OnInit {
|
||||||
constructor(svc: CvService){
|
constructor(svc: CvService){
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { CvService } from './cv.service';
|
import { ResumeService } from './cv.service';
|
||||||
|
|
||||||
describe('CvService', () => {
|
describe('ResumeService', () => {
|
||||||
let service: CvService;
|
let service: ResumeService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({});
|
||||||
imports: [HttpClientTestingModule]
|
service = TestBed.inject(ResumeService);
|
||||||
});
|
|
||||||
service = TestBed.inject(CvService);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import { Component, ViewEncapsulation } from '@angular/core';
|
import { Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { LoaderService } from '../services/loader.service';
|
import { LoaderService } from '../services/loader.service';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-spinner',
|
selector: 'app-spinner',
|
||||||
templateUrl: './spinner.component.html',
|
templateUrl: './spinner.component.html',
|
||||||
styleUrl: './spinner.component.scss',
|
styleUrl: './spinner.component.scss',
|
||||||
encapsulation: ViewEncapsulation.ShadowDom,
|
encapsulation: ViewEncapsulation.ShadowDom
|
||||||
standalone: true,
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
})
|
||||||
export class SpinnerComponent {
|
export class SpinnerComponent {
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
export const environment = {
|
|
||||||
apiUrl: 'https://localhost:7013',
|
|
||||||
apiKey: "c6eAXYcNT873TT7BfMgQyS4ii7hxa53TLEUN7pAGaaU="
|
|
||||||
};
|
|
||||||
@ -25,8 +25,6 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
|
|||||||
20
src/main.ts
20
src/main.ts
@ -1,15 +1,7 @@
|
|||||||
import { bootstrapApplication } from '@angular/platform-browser';
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
import { AppComponent } from './app/app.component';
|
|
||||||
import { provideRouter } from '@angular/router';
|
|
||||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
|
||||||
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
|
|
||||||
import { appRoutes } from './app/app-routing.module';
|
|
||||||
import { httpInterceptors } from './app/http-interceptors';
|
|
||||||
|
|
||||||
bootstrapApplication(AppComponent, {
|
import { AppModule } from './app/app.module';
|
||||||
providers: [
|
|
||||||
provideRouter(appRoutes),
|
|
||||||
provideAnimations(),
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
provideHttpClient(withInterceptors(httpInterceptors), withFetch())
|
.catch(err => console.error(err));
|
||||||
]
|
|
||||||
}).catch(err => console.error(err));
|
|
||||||
|
|||||||
@ -1,38 +1,3 @@
|
|||||||
|
|
||||||
// Include theming for Angular Material with `mat.theme()`.
|
|
||||||
// This Sass mixin will define CSS variables that are used for styling Angular Material
|
|
||||||
// components according to the Material 3 design spec.
|
|
||||||
// Learn more about theming and how to use it for your application's
|
|
||||||
// custom components at https://material.angular.dev/guide/theming
|
|
||||||
@use '@angular/material' as mat;
|
|
||||||
|
|
||||||
html {
|
|
||||||
@include mat.theme((
|
|
||||||
color: (
|
|
||||||
primary: mat.$azure-palette,
|
|
||||||
tertiary: mat.$blue-palette,
|
|
||||||
),
|
|
||||||
typography: Roboto,
|
|
||||||
density: 0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
// Default the application to a light color theme. This can be changed to
|
|
||||||
// `dark` to enable the dark color theme, or to `light dark` to defer to the
|
|
||||||
// user's system settings.
|
|
||||||
color-scheme: light;
|
|
||||||
|
|
||||||
// Set a default background, font and text colors for the application using
|
|
||||||
// Angular Material's system-level CSS variables. Learn more about these
|
|
||||||
// variables at https://material.angular.dev/guide/system-variables
|
|
||||||
background-color: var(--mat-sys-surface);
|
|
||||||
color: var(--mat-sys-on-surface);
|
|
||||||
font: var(--mat-sys-body-medium);
|
|
||||||
|
|
||||||
// Reset the user agent margin.
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
/*-----------------------------------*\
|
/*-----------------------------------*\
|
||||||
#style.css
|
#style.css
|
||||||
\*-----------------------------------*/
|
\*-----------------------------------*/
|
||||||
@ -1922,9 +1887,4 @@ body {
|
|||||||
|
|
||||||
.timeline-text { max-width: 700px; }
|
.timeline-text { max-width: 700px; }
|
||||||
|
|
||||||
}
|
}
|
||||||
html, body { height: 100%; }
|
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
|
||||||
|
|
||||||
html, body { height: 100%; }
|
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
|
||||||
Loading…
Reference in New Issue
Block a user