Added routing for nav links and SPA mounting of components using Angular router

This commit is contained in:
AdamBtech
2025-05-22 11:56:39 +02:00
parent a9dedcb1f6
commit 11fd702957
37 changed files with 269 additions and 147 deletions

View File

@@ -0,0 +1,4 @@
.route-container {
min-height: 100vh;
background: inherit;
}

View File

@@ -6,8 +6,14 @@
<title>{{title}}</title>
</head>
<body>
<app-main-layout/>
<app-header />
<main class="bg-nier-bg checkered-background">
<div class="route-container">
<router-outlet />
</div>
</main>
<app-footer />
</body>
</html>
<router-outlet />

View File

@@ -1,12 +1,13 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {MainLayoutComponent} from './layout/components/main-layout/main-layout.component';
import { FooterComponent } from './layout/components/footer/footer.component';
import { HeaderComponent } from './layout/components/header/header.component';
@Component({
selector: 'app-root',
imports: [RouterOutlet, MainLayoutComponent],
imports: [RouterOutlet, FooterComponent, HeaderComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'Adam Benyekkou Portfolio';

View File

@@ -1,3 +1,14 @@
import { Routes } from '@angular/router';
import { AboutComponent } from './layout/components/about/about.component';
import { ContactComponent } from './layout/components/contact/contact.component';
import { HeroComponent } from './layout/components/hero/hero.component';
import { ProjectsListComponent } from './features/project-display/components/projects-list/projects-list.component';
import { ExperienceComponent } from './layout/components/experience/experience.component';
export const routes: Routes = [];
export const routes: Routes = [
{ path: '', component: HeroComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: 'projects', component: ProjectsListComponent },
{ path: 'experience', component: ExperienceComponent },
];

View File

@@ -1,3 +1,3 @@
<section class="border-b-1 h-100 flex items-top justify-top checkered-bg p-6 relative">
<section class="border-b-1 h-screen flex items-top justify-top checkered-bg p-6 relative">
<app-section-title title="NEURAL PROFILE" />
</section>

View File

@@ -1,3 +1,3 @@
<section class="border-b-1 h-100 flex items-top justify-top checkered-bg p-6 relative">
<section class="border-b-1 h-screen flex items-top justify-top checkered-bg p-6 relative">
<app-section-title title="TRANSMISSION LINKS" />
</section>

View File

@@ -0,0 +1,3 @@
<section class="border-b-1 h-screen flex items-top justify-top checkered-bg p-6 relative">
<app-section-title title=" OPERATIVE HISTORY" />
</section>

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import {SectionTitleComponent} from '../../shared/ui/section-title/section-title.component';
@Component({
selector: 'app-experience-display',
imports: [SectionTitleComponent],
templateUrl: './experience-display.component.html',
styleUrl: './experience-display.component.css',
})
export class ExperienceDisplayComponent {}

View File

@@ -30,15 +30,15 @@
</div>
</article>
<!-- Rest of your layout remains unchanged -->
<article class="border-r-0 md:border-r-1 grid grid-rows-2 w-full h-full my-4 md:my-0">
<article class="border-r-0 md:border-r-1 grid grid-rows-2 w-full h-full my-4 md:my-0 mb-6 md:mb-0">
<div class="border-b-1 w-full h-full">
<p class="flex items-center justify-center h-full w-full text-sm sm:text-lg md:text-lg lg:text-lg xl:text-lg text-center px-2">
Based in unknown french-hideout
</p>
</div>
<div class="w-full h-full">
<p class="flex items-center justify-center h-full w-full text-sm sm:text-lg md:text-lg lg:text-lg xl:text-lg text-center px-2 flex-wrap">
<p class="flex items-center justify-center h-full w-full text-sm sm:text-lg md:text-lg lg:text-lg xl:text-lg text-center px-2 flex-wrap ">
<span class="whitespace-nowrap mb-1 sm:mb-0">Tech operative ready /</span>
<a href="https://www.linkedin.com/in/adambnk/" target="_blank" class="text-nier-mid ml-1 sm:ml-2 whitespace-nowrap" data-label="Deploy my skills">
<span class="relative z-10">Deploy my skills</span>
@@ -48,7 +48,7 @@
</div>
</article>
<article class="flex items-center justify-center w-full h-full">
<article class="flex items-center justify-center w-full h-full mt-2">
<a href="mailto:your.email@example.com?subject=Initialize%20Connection%20-&body=System%20message%3A%20Your%20connection%20request%20has%20been%20received.%20Please%20provide%20your%20message%20to%20establish%20communication.">
<div class="icon-email"></div>
</a>

View File

@@ -1,4 +1,4 @@
<!-- header-switch-theme-button.component.html -->
<!-- header-switch-theme-nav-button.html -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-10 h-10 svg-icon">
<!-- Outer ring -->
<circle cx="12" cy="12" r="11" fill="none" stroke="currentColor" stroke-width="0.8" />

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,4 +1,4 @@
// header-switch-theme-button.component.ts
// header-switch-theme-nav-button.component.ts
import { Component, OnInit } from '@angular/core';
@Component({

View File

@@ -1,5 +1,6 @@
<div class="nier-logo-container">
<div class="nier-logo-container"><a [routerLink]="routerLink()">
<p class="font-terminal-nier text-8xl nier-logo nier-dark" data-text="AB">AB</p>
<div class="nier-scan-line nier-dark"></div>
<div class="nier-blocks nier-dark"></div>
</a>
</div>

View File

@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderLogoComponent } from './header-logo.component';
describe('HeaderLogoComponent', () => {
let component: HeaderLogoComponent;
let fixture: ComponentFixture<HeaderLogoComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HeaderLogoComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HeaderLogoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,9 +1,12 @@
import { Component } from '@angular/core';
import { Component, input } from '@angular/core';
import { RouterLink } from '@angular/router';
@Component({
selector: 'app-header-logo',
imports: [],
imports: [RouterLink],
templateUrl: './header-logo.component.html',
styleUrl: './header-logo.component.css',
})
export class HeaderLogoComponent {}
export class HeaderLogoComponent {
routerLink = input<string>('');
}

View File

@@ -1,8 +1,8 @@
<nav class="flex items-center justify-center">
<section class="grid grid-cols-2 gap-x-4 gap-y-5 my-4">
<app-button class="flex items-center h-10" label="Neural Profile" (click)="onClick()"/>
<app-button class="flex items-center h-10" label="Execute//Directory" (click)="onClick()"/>
<app-button class="flex items-center h-10" label="Operative History" (click)="onClick()"/>
<app-button class="flex items-center h-10" label="Transmission Link" (click)="onClick()"/>
<app-nav-button class="flex items-center h-10" label="Neural Profile" (click)="onClick()" routerLink="about"/>
<app-nav-button class="flex items-center h-10" label="Execute//Directory" (click)="onClick()" routerLink="projects"/>
<app-nav-button class="flex items-center h-10" label="Operative History" (click)="onClick()" routerLink="experience"/>
<app-nav-button class="flex items-center h-10" label="Transmission Link" (click)="onClick()" routerLink="contact"/>
</section>
</nav>

View File

@@ -1,10 +1,9 @@
import { Component } from '@angular/core';
import { ButtonComponent } from '../../../shared/ui/button/button.component';
import { NavButtonComponent } from '../../../shared/ui/button/nav-button.component';
@Component({
selector: 'app-header-nav-links',
imports: [ButtonComponent],
imports: [NavButtonComponent],
templateUrl: './header-nav-links.component.html',
styleUrl: './header-nav-links.component.css',
})

View File

@@ -1,4 +1,4 @@
<section class="border-b-1 h-100 flex items-top justify-top checkered-bg p-6 relative">
<section class="border-b-1 h-screen flex items-top justify-top checkered-bg p-6 relative">
<app-section-title title="EXECUTE // DIRECTORY" />
</section>

View File

@@ -1,2 +0,0 @@
<p class="font-terminal-retro">SIDEBAR</p>

View File

@@ -1,11 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-sidebar-display',
imports: [],
templateUrl: './sidebar-display.component.html',
styleUrl: './sidebar-display.component.css'
})
export class SidebarDisplayComponent {
}

View File

@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContactComponent } from './contact.component';
describe('ContactComponent', () => {
let component: ContactComponent;
let fixture: ComponentFixture<ContactComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ContactComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1 @@
<app-experience-display />

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { ExperienceDisplayComponent } from '../../../features/experience-display/experience-display.component';
@Component({
selector: 'app-experience',
imports: [ExperienceDisplayComponent],
templateUrl: './experience.component.html',
styleUrl: './experience.component.css',
})
export class ExperienceComponent {}

View File

@@ -0,0 +1,15 @@
/* QR Code size control for mobile */
@media (max-width: 767px) {
/* Target QR code image inside contact links - assumes proper structure */
app-header-contact-links img {
max-width: 80px;
height: auto;
}
}
/* Additional styles for better typography and spacing */
@media (min-width: 1024px) {
app-header-text-animate-section {
width: 100%;
}
}

View File

@@ -4,7 +4,7 @@
class="md:hidden grid grid-cols-1 bg-nier-bg font-terminal text-nier-dark border border-nier-accent overflow-hidden"
>
<div class="flex justify-center py-3 border-b border-nier-accent/30">
<app-header-logo />
<app-header-logo routerLink="" />
</div>
<div class="py-3 border-b border-nier-accent/30 min-h-[100px]">
<app-header-text-animate-section
@@ -137,20 +137,3 @@
</section>
</header>
<style>
/* QR Code size control for mobile */
@media (max-width: 767px) {
/* Target QR code image inside contact links - assumes proper structure */
app-header-contact-links img {
max-width: 80px;
height: auto;
}
}
/* Additional styles for better typography and spacing */
@media (min-width: 1024px) {
app-header-text-animate-section {
width: 100%;
}
}
</style>

View File

@@ -1,9 +0,0 @@
<app-header />
<main class="bg-nier-bg checkered-background">
<app-hero />
<app-projects />
<app-about />
<app-contact />
</main>
<app-footer />
<app-sidebar />

View File

@@ -1,24 +0,0 @@
import { Component } from '@angular/core';
import { FooterComponent } from '../footer/footer.component';
import { SidebarComponent } from '../sidebar/sidebar.component';
import { HeaderComponent } from '../header/header.component';
import { HeroComponent } from '../hero/hero.component';
import { AboutComponent } from '../about/about.component';
import { ProjectsComponent } from '../projects/projects.component';
import { ContactComponent } from '../contact/contact.component';
@Component({
selector: 'app-main-layout',
imports: [
FooterComponent,
SidebarComponent,
HeaderComponent,
HeroComponent,
AboutComponent,
ProjectsComponent,
ContactComponent,
],
templateUrl: './main-layout.component.html',
styleUrl: './main-layout.component.css',
})
export class MainLayoutComponent {}

View File

@@ -1 +0,0 @@
<app-sidebar-display />

View File

@@ -1,10 +0,0 @@
import { Component } from '@angular/core';
import {SidebarDisplayComponent} from '../../../features/sidebar-display/sidebar-display.component';
@Component({
selector: 'app-sidebar',
imports: [SidebarDisplayComponent],
templateUrl: './sidebar.component.html',
styleUrl: './sidebar.component.css',
})
export class SidebarComponent {}

View File

@@ -0,0 +1,19 @@
import { Component, input, output } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';
@Component({
selector: 'app-nav-button',
standalone: true, // Move this to the top
imports: [RouterLink, RouterLinkActive],
templateUrl: './nav-button.html',
styleUrl: './nav-button.css',
})
export class NavButtonComponent {
label = input<string>('label');
routerLink = input<string>('');
onClick = output<void>();
handleClick() {
this.onClick.emit();
}
}

View File

@@ -0,0 +1,10 @@
<a
[routerLink]="routerLink()"
routerLinkActive="active"
class="w-full sm:w-40 md:w-48 text-left font-noto-jp text-sm sm:text-sm md:text-base uppercase transition-all duration-300 rounded-none p-3 sm:p-1.5 button-custom"
(click)="handleClick()"
[attr.data-label]="label()"
>
<span class="relative z-10">{{ label() }}</span>
<span class="scan-line"></span>
</a>

View File

@@ -0,0 +1,149 @@
.button-custom {
cursor: pointer;
background-color: var(--color-nier-mid);
color: var(--color-nier-dark);
position: relative;
border: 1px solid transparent;
border-left: none;
border-right: none;
overflow: hidden;
transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.button-custom::before {
content: "";
position: absolute;
left: 0;
top: 3px; /* Space from top border */
bottom: 3px; /* Space from bottom border */
width: 0;
height: auto; /* This makes it respect top and bottom values */
background-color: var(--color-nier-dark);
transition: width 0.2s ease;
z-index: 0;
}
/* Normal hover/focus state - keep your original behavior */
.button-custom:hover,
.button-custom:focus {
color: var(--color-nier-text-light);
background-color: transparent;
border-color: var(--color-nier-dark);
}
.button-custom:hover::before,
.button-custom:focus::before {
width: 100%;
}
/* Add NieR-style glitch effects on hover */
.button-custom::after {
content: attr(data-label); /* Use the button's text from data-label attribute */
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-nier-text-light);
opacity: 0;
z-index: 2;
pointer-events: none;
}
.button-custom:hover::after {
animation: nier-button-glitch 0.6s ease forwards;
}
/* Add subtle scan line on hover */
.button-custom .scan-line {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 1px;
background-color: var(--color-nier-text-light);
opacity: 0;
z-index: 3;
pointer-events: none;
}
.button-custom:hover .scan-line {
animation: nier-button-scan 0.3s ease forwards;
}
/* The glitch effect animation */
@keyframes nier-button-glitch {
0%, 100% {
opacity: 0;
transform: translateX(0);
clip-path: inset(0 0 0 0);
}
10% {
opacity: 0.2;
transform: translateX(-2px);
clip-path: inset(10% 0 80% 0);
}
12% {
opacity: 0;
transform: translateX(0);
}
20% {
opacity: 0.2;
transform: translateX(2px);
clip-path: inset(30% 0 50% 0);
}
22% {
opacity: 0;
transform: translateX(0);
}
30% {
opacity: 0.1;
transform: translateX(-1px);
clip-path: inset(50% 0 20% 0);
}
32% {
opacity: 0;
transform: translateX(0);
}
}
/* The scan line animation */
@keyframes nier-button-scan {
0% {
opacity: 0.5;
left: -100%;
}
100% {
opacity: 0;
left: 100%;
}
}
/* Add a brief effect on button click */
.button-custom:active {
transform: scale(0.98);
}
.button-custom:active::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.1);
opacity: 0;
animation: nier-button-flash 0.2s ease;
}
@keyframes nier-button-flash {
0% {
opacity: 0.2;
}
100% {
opacity: 0;
}
}