Compare commits

...

3 Commits

Author SHA1 Message Date
797163d1ba chore: update Angular dependencies to version 20.2.0 and refactor HTTP interceptors to use new functional API
- Updated Angular dependencies in package.json to version 20.2.0, including Angular Material and CDK.
- Refactored AuthInterceptor and LoadingInterceptor to use the new HttpInterceptorFn functional API.
- Modified the index file for interceptors to export the new functional interceptors.
- Enhanced the styling of the project detail popup with a dark theme and encapsulation settings.
- Updated main.ts to use the new interceptor setup with provideHttpClient.
- Added theming support for Angular Material in styles.scss, including light and dark themes.
2026-03-14 22:54:01 +05:30
b4c5fddf0d Merge remote-tracking branch 'origin/task/upgrade-to-angular20' into task-project-view-component-changes 2026-03-14 17:45:41 +05:30
3cb47c7c1a chore: upgrade Angular and related dependencies to version 20.0.0
feat: refactor AboutComponent to be standalone and include CommonModule
feat: refactor BlogComponent to be standalone and include CommonModule
feat: refactor ContactSidebarComponent to be standalone and include CommonModule
feat: refactor ContactComponent to be standalone and include CommonModule and FormsModule
feat: refactor NavbarComponent to be standalone and include CommonModule and RouterModule
feat: refactor ProjectsComponent to be standalone and include CommonModule
feat: refactor ResumeComponent to be standalone and include CommonModule
feat: refactor AppComponent to be standalone and include necessary components
feat: remove AppModule in favor of standalone components
fix: update tests to include HttpClientTestingModule where necessary
fix: update routing module to export appRoutes without NgModule
chore: add environment configuration for production
2026-03-14 09:38:15 +05:30
31 changed files with 8234 additions and 6295 deletions

View File

@ -115,5 +115,8 @@
} }
} }
} }
},
"cli": {
"analytics": false
} }
} }

14120
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,24 +10,24 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^17.3.3", "@angular/animations": "^20.2.0",
"@angular/cdk": "^17.3.10", "@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/material": "^17.3.10", "@angular/material": "^20.2.0",
"@angular/platform-browser": "^17.3.3", "@angular/platform-browser": "^20.2.0",
"@angular/platform-browser-dynamic": "^17.3.3", "@angular/platform-browser-dynamic": "^20.2.0",
"@angular/router": "^17.3.3", "@angular/router": "^20.2.0",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.14.4" "zone.js": "~0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^17.3.3", "@angular-devkit/build-angular": "^20.2.0",
"@angular/cli": "~17.3.3", "@angular/cli": "~20.2.0",
"@angular/compiler-cli": "^17.3.3", "@angular/compiler-cli": "^20.2.0",
"@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 +35,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.4.4" "typescript": "~5.8.0"
} }
} }

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('AboutComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [AboutComponent] imports: [AboutComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,4 +1,5 @@
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';
@ -6,7 +7,9 @@ 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){

View File

@ -1,25 +1,15 @@
import { NgModule } from '@angular/core'; import { Routes } from '@angular/router';
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';
const routes: Routes = [ export const appRoutes: Routes = [
{ path: '', component: AboutComponent, title: "About" }, { path: '', component: AboutComponent, title: "Bangara Raju Kottedi" },
{ path: 'resume', component: ResumeComponent, title: "Resume" }, { path: 'resume', component: ResumeComponent, title: "Bangara Raju Kottedi - Resume" },
{ path: 'projects', component: ProjectsComponent, title: "Projects" }, { path: 'projects', component: ProjectsComponent, title: "Bangara Raju Kottedi - Projects" },
{ path: 'weblog', component: BlogComponent, title: "Posts" }, { path: 'weblog', component: BlogComponent, title: "Bangara Raju Kottedi - Posts" },
{ path: 'contact', component: ContactComponent, title: "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 { }

View File

@ -1,27 +1,18 @@
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(() => TestBed.configureTestingModule({ beforeEach(async () => {
declarations: [AppComponent] await TestBed.configureTestingModule({
})); 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!');
});
}); });

View File

@ -1,9 +1,17 @@
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() {}

View File

@ -1,42 +0,0 @@
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';
import { MatDialogModule } from '@angular/material/dialog';
@NgModule({
declarations: [
AppComponent,
SpinnerComponent,
ContactSidebarComponent,
NavbarComponent,
AboutComponent,
ResumeComponent,
ProjectsComponent,
BlogComponent,
ContactComponent
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
FormsModule,
MatDialogModule,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [httpInterceptorProviders],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('BlogComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [BlogComponent] imports: [BlogComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,4 +1,5 @@
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';
@ -7,7 +8,9 @@ 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;

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('ContactSidebarComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [ContactSidebarComponent] imports: [ContactSidebarComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,4 +1,5 @@
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';
@ -6,7 +7,9 @@ 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;

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('ContactComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [ContactComponent] imports: [ContactComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,12 +1,15 @@
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: '' };

View File

@ -1,18 +1,14 @@
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http"; import { HttpInterceptorFn } from "@angular/common/http";
import { Observable } from "rxjs"; import { inject } from "@angular/core";
import { AuthService } from "../services/auth.service"; import { AuthService } from "../services/auth.service";
import { Injectable } from "@angular/core";
@Injectable() export const authInterceptor: HttpInterceptorFn = (req, next) => {
export class AuthInterceptor implements HttpInterceptor{ const authSvc = inject(AuthService);
constructor(public authSvc: AuthService){} const apiKey = authSvc.getApiKey();
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.handle(authReq); return next(authReq);
} };
}

View File

@ -1,9 +1,4 @@
import { HTTP_INTERCEPTORS } from "@angular/common/http"; import { authInterceptor } from "./auth.interceptor";
import { loadingInterceptor } from "./loading.interceptor";
import { AuthInterceptor } from "./auth.interceptor"; export const httpInterceptors = [authInterceptor, loadingInterceptor];
import { LoadingInterceptor } from "./loading.interceptor";
export const httpInterceptorProviders = [
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true}
]

View File

@ -1,27 +1,22 @@
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http"; import { HttpInterceptorFn } from "@angular/common/http";
import { Injectable } from "@angular/core"; import { inject } from "@angular/core";
import { Observable, finalize } from "rxjs"; import { finalize } from "rxjs";
import { LoaderService } from "../services/loader.service"; import { LoaderService } from "../services/loader.service";
@Injectable() let totalRequests: number = 0;
export class LoadingInterceptor implements HttpInterceptor {
private totalRequests: number = 0; export const loadingInterceptor: HttpInterceptorFn = (req, next) => {
const loadingSvc = inject(LoaderService);
constructor(private loadingSvc: LoaderService) { } totalRequests++;
loadingSvc.setLoading(true);
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next(req).pipe(
this.totalRequests++; finalize(() => {
this.loadingSvc.setLoading(true); totalRequests--;
return next.handle(req).pipe( if (totalRequests === 0) {
finalize( loadingSvc.setLoading(false);
() => {
this.totalRequests--;
if (this.totalRequests == 0) {
this.loadingSvc.setLoading(false);
} }
} })
)
); );
} };
}

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('NavbarComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [NavbarComponent] imports: [NavbarComponent, RouterTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,9 +1,13 @@
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 {
} }

View File

@ -8,6 +8,37 @@
border-radius: 14px; 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 { .detail-header {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;

View File

@ -1,4 +1,4 @@
import { Component, inject } from '@angular/core'; import { Component, inject, ViewEncapsulation } from '@angular/core';
import { CommonModule, DatePipe } from '@angular/common'; import { CommonModule, DatePipe } from '@angular/common';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { IProject } from '../../models/project.model'; import { IProject } from '../../models/project.model';
@ -8,7 +8,8 @@ import { IProject } from '../../models/project.model';
templateUrl: './project-detail-popup.html', templateUrl: './project-detail-popup.html',
styleUrls: ['./project-detail-popup.scss'], styleUrls: ['./project-detail-popup.scss'],
standalone: true, standalone: true,
imports: [CommonModule, DatePipe] imports: [CommonModule, DatePipe],
encapsulation: ViewEncapsulation.None
}) })
export class ProjectDetailPopupComponent { export class ProjectDetailPopupComponent {
private dialogRef = inject(MatDialogRef<ProjectDetailPopupComponent>); private dialogRef = inject(MatDialogRef<ProjectDetailPopupComponent>);

View File

@ -1,18 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { PortfolioComponent } from './projects.component'; import { ProjectsComponent } from './projects.component';
describe('PortfolioComponent', () => { describe('ProjectsComponent', () => {
let component: PortfolioComponent; let component: ProjectsComponent;
let fixture: ComponentFixture<PortfolioComponent>; let fixture: ComponentFixture<ProjectsComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [PortfolioComponent] imports: [ProjectsComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();
fixture = TestBed.createComponent(PortfolioComponent); fixture = TestBed.createComponent(ProjectsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@ -1,3 +1,4 @@
import { CommonModule } from '@angular/common';
import { Component, OnInit, Inject } 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';
@ -11,7 +12,9 @@ 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';

View File

@ -1,4 +1,5 @@
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';
@ -8,7 +9,7 @@ describe('ResumeComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [ResumeComponent] imports: [ResumeComponent, HttpClientTestingModule]
}) })
.compileComponents(); .compileComponents();

View File

@ -1,4 +1,5 @@
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';
@ -6,7 +7,9 @@ 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){

View File

@ -1,13 +1,16 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ResumeService } from './cv.service'; import { CvService } from './cv.service';
describe('ResumeService', () => { describe('CvService', () => {
let service: ResumeService; let service: CvService;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({}); TestBed.configureTestingModule({
service = TestBed.inject(ResumeService); imports: [HttpClientTestingModule]
});
service = TestBed.inject(CvService);
}); });
it('should be created', () => { it('should be created', () => {

View File

@ -1,11 +1,14 @@
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 {

View File

@ -0,0 +1,4 @@
export const environment = {
apiUrl: 'https://localhost:7013',
apiKey: "c6eAXYcNT873TT7BfMgQyS4ii7hxa53TLEUN7pAGaaU="
};

View File

@ -1,7 +1,15 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { bootstrapApplication } from '@angular/platform-browser';
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';
import { AppModule } from './app/app.module'; bootstrapApplication(AppComponent, {
providers: [
provideRouter(appRoutes),
platformBrowserDynamic().bootstrapModule(AppModule) provideAnimations(),
.catch(err => console.error(err)); provideHttpClient(withInterceptors(httpInterceptors), withFetch())
]
}).catch(err => console.error(err));

View File

@ -1,3 +1,38 @@
// 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
\*-----------------------------------*/ \*-----------------------------------*/
@ -1890,3 +1925,6 @@
} }
html, body { height: 100%; } html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }