mirror of
https://github.com/adam-benyekkou/my_portfolio.git
synced 2026-01-15 20:20:09 +00:00
Added routing for nav links and SPA mounting of components using Angular router
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
.route-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,14 @@
|
|||||||
<title>{{title}}</title>
|
<title>{{title}}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-main-layout/>
|
<app-header />
|
||||||
|
<main class="bg-nier-bg checkered-background">
|
||||||
|
<div class="route-container">
|
||||||
|
<router-outlet />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<app-footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<router-outlet />
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
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({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [RouterOutlet, MainLayoutComponent],
|
imports: [RouterOutlet, FooterComponent, HeaderComponent],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.css'
|
styleUrl: './app.component.css',
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'Adam Benyekkou Portfolio';
|
title = 'Adam Benyekkou Portfolio';
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
import { Routes } from '@angular/router';
|
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 },
|
||||||
|
];
|
||||||
|
|||||||
@@ -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" />
|
<app-section-title title="NEURAL PROFILE" />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -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" />
|
<app-section-title title="TRANSMISSION LINKS" />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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 {}
|
||||||
@@ -30,15 +30,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</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">
|
<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">
|
<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
|
Based in unknown french-hideout
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full h-full">
|
<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>
|
<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">
|
<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>
|
<span class="relative z-10">Deploy my skills</span>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</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.">
|
<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>
|
<div class="icon-email"></div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -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">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-10 h-10 svg-icon">
|
||||||
<!-- Outer ring -->
|
<!-- Outer ring -->
|
||||||
<circle cx="12" cy="12" r="11" fill="none" stroke="currentColor" stroke-width="0.8" />
|
<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 |
@@ -1,4 +1,4 @@
|
|||||||
// header-switch-theme-button.component.ts
|
// header-switch-theme-nav-button.component.ts
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -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>
|
<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-scan-line nier-dark"></div>
|
||||||
<div class="nier-blocks nier-dark"></div>
|
<div class="nier-blocks nier-dark"></div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, input } from '@angular/core';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header-logo',
|
selector: 'app-header-logo',
|
||||||
imports: [],
|
imports: [RouterLink],
|
||||||
templateUrl: './header-logo.component.html',
|
templateUrl: './header-logo.component.html',
|
||||||
styleUrl: './header-logo.component.css',
|
styleUrl: './header-logo.component.css',
|
||||||
})
|
})
|
||||||
export class HeaderLogoComponent {}
|
export class HeaderLogoComponent {
|
||||||
|
routerLink = input<string>('');
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<nav class="flex items-center justify-center">
|
<nav class="flex items-center justify-center">
|
||||||
<section class="grid grid-cols-2 gap-x-4 gap-y-5 my-4">
|
<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-nav-button class="flex items-center h-10" label="Neural Profile" (click)="onClick()" routerLink="about"/>
|
||||||
<app-button class="flex items-center h-10" label="Execute//Directory" (click)="onClick()"/>
|
<app-nav-button class="flex items-center h-10" label="Execute//Directory" (click)="onClick()" routerLink="projects"/>
|
||||||
<app-button class="flex items-center h-10" label="Operative History" (click)="onClick()"/>
|
<app-nav-button class="flex items-center h-10" label="Operative History" (click)="onClick()" routerLink="experience"/>
|
||||||
<app-button class="flex items-center h-10" label="Transmission Link" (click)="onClick()"/>
|
<app-nav-button class="flex items-center h-10" label="Transmission Link" (click)="onClick()" routerLink="contact"/>
|
||||||
</section>
|
</section>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { NavButtonComponent } from '../../../shared/ui/button/nav-button.component';
|
||||||
import { ButtonComponent } from '../../../shared/ui/button/button.component';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header-nav-links',
|
selector: 'app-header-nav-links',
|
||||||
imports: [ButtonComponent],
|
imports: [NavButtonComponent],
|
||||||
templateUrl: './header-nav-links.component.html',
|
templateUrl: './header-nav-links.component.html',
|
||||||
styleUrl: './header-nav-links.component.css',
|
styleUrl: './header-nav-links.component.css',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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" />
|
<app-section-title title="EXECUTE // DIRECTORY" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
<p class="font-terminal-retro">SIDEBAR</p>
|
|
||||||
@@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<app-experience-display />
|
||||||
10
src/app/layout/components/experience/experience.component.ts
Normal file
10
src/app/layout/components/experience/experience.component.ts
Normal 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 {}
|
||||||
@@ -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%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
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">
|
<div class="flex justify-center py-3 border-b border-nier-accent/30">
|
||||||
<app-header-logo />
|
<app-header-logo routerLink="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="py-3 border-b border-nier-accent/30 min-h-[100px]">
|
<div class="py-3 border-b border-nier-accent/30 min-h-[100px]">
|
||||||
<app-header-text-animate-section
|
<app-header-text-animate-section
|
||||||
@@ -137,20 +137,3 @@
|
|||||||
</section>
|
</section>
|
||||||
</header>
|
</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>
|
|
||||||
|
|||||||
@@ -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 />
|
|
||||||
@@ -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 {}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<app-sidebar-display />
|
|
||||||
@@ -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 {}
|
|
||||||
19
src/app/shared/ui/button/nav-button.component.ts
Normal file
19
src/app/shared/ui/button/nav-button.component.ts
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/app/shared/ui/button/nav-button.html
Normal file
10
src/app/shared/ui/button/nav-button.html
Normal 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>
|
||||||
149
src/app/shared/ui/nav-button/button.component.css
Normal file
149
src/app/shared/ui/nav-button/button.component.css
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user