Refactoring contact page in smaller components

This commit is contained in:
AdamBtech
2025-05-28 14:25:19 +02:00
parent 469cd039d3
commit 98dedb0b22
9 changed files with 323 additions and 177 deletions

View File

@@ -39,12 +39,6 @@
to { opacity: 1; } to { opacity: 1; }
} }
@keyframes scanLine {
from { transform: translate3d(-100%, 0, 0); opacity: 0; }
50% { opacity: 1; }
to { transform: translate3d(100%, 0, 0); opacity: 0; }
}
/* ===================== CONTACT ELEMENTS ===================== */ /* ===================== CONTACT ELEMENTS ===================== */
/* Content container */ /* Content container */
@@ -71,59 +65,6 @@
animation: slideInUp 0.8s ease-out 0.8s forwards; animation: slideInUp 0.8s ease-out 0.8s forwards;
} }
/* Contact items */
.contact-item {
opacity: 0;
animation: scaleIn 0.8s ease-out forwards;
position: relative;
}
.contact-item:nth-child(1) { animation-delay: 1.0s; }
.contact-item:nth-child(2) { animation-delay: 1.1s; }
.contact-item:nth-child(3) { animation-delay: 1.2s; }
/* Scan line effect */
.contact-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 2px;
background: linear-gradient(90deg, transparent, var(--color-nier-accent), transparent);
animation: scanLine 1.5s ease-out forwards;
z-index: 20;
}
.contact-item:nth-child(1)::before { animation-delay: 1.2s; }
.contact-item:nth-child(2)::before { animation-delay: 1.3s; }
.contact-item:nth-child(3)::before { animation-delay: 1.4s; }
/* Contact icons */
.contact-icon {
opacity: 0;
animation: scaleIn 0.5s ease-out forwards;
}
.contact-item:nth-child(1) .contact-icon { animation-delay: 1.3s; }
.contact-item:nth-child(2) .contact-icon { animation-delay: 1.4s; }
.contact-item:nth-child(3) .contact-icon { animation-delay: 1.5s; }
/* Contact labels and values */
.contact-label,
.contact-value {
opacity: 0;
animation: slideInLeft 0.4s ease-out forwards;
}
.contact-item:nth-child(1) .contact-label { animation-delay: 1.4s; }
.contact-item:nth-child(2) .contact-label { animation-delay: 1.5s; }
.contact-item:nth-child(3) .contact-label { animation-delay: 1.6s; }
.contact-item:nth-child(1) .contact-value { animation-delay: 1.5s; }
.contact-item:nth-child(2) .contact-value { animation-delay: 1.6s; }
.contact-item:nth-child(3) .contact-value { animation-delay: 1.7s; }
/* Info panels container */ /* Info panels container */
.info-panels-container { .info-panels-container {
opacity: 0; opacity: 0;
@@ -156,22 +97,6 @@
.info-panel:nth-child(1) .info-panel-content { animation-delay: 1.9s; } .info-panel:nth-child(1) .info-panel-content { animation-delay: 1.9s; }
.info-panel:nth-child(2) .info-panel-content { animation-delay: 2.0s; } .info-panel:nth-child(2) .info-panel-content { animation-delay: 2.0s; }
/* ===================== HOVER EFFECTS ===================== */
.contact-item:hover {
transform: translateY(-3px);
box-shadow:
0 8px 25px rgba(0, 0, 0, 0.2),
0 0 20px rgba(90, 90, 80, 0.1);
transition: all 0.3s ease;
}
.contact-item:hover .contact-icon {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(90, 90, 80, 0.3);
transition: all 0.3s ease;
}
/* ===================== BACKGROUND PATTERN ===================== */ /* ===================== BACKGROUND PATTERN ===================== */
.contact-content-container::before { .contact-content-container::before {
@@ -196,11 +121,6 @@
.contact-content-container { animation-delay: 0.3s; } .contact-content-container { animation-delay: 0.3s; }
.availability-status { animation-delay: 0.4s; } .availability-status { animation-delay: 0.4s; }
.contact-grid { animation-delay: 0.6s; } .contact-grid { animation-delay: 0.6s; }
.contact-item:nth-child(1) { animation-delay: 0.8s; }
.contact-item:nth-child(2) { animation-delay: 0.9s; }
\contact-item:nth-child(3) { animation-delay: 1.0s; }
.info-panels-container { animation-delay: 1.2s; } .info-panels-container { animation-delay: 1.2s; }
.info-panel:nth-child(1) { animation-delay: 1.3s; } .info-panel:nth-child(1) { animation-delay: 1.3s; }
.info-panel:nth-child(2) { animation-delay: 1.4s; } .info-panel:nth-child(2) { animation-delay: 1.4s; }
@@ -209,16 +129,12 @@
.contact-content-container, .contact-content-container,
.availability-status, .availability-status,
.contact-grid, .contact-grid,
.contact-item,
.info-panels-container, .info-panels-container,
.info-panel { .info-panel {
animation-duration: 0.6s; animation-duration: 0.6s;
} }
.status-dot, .status-dot,
.contact-icon,
.contact-label,
.contact-value,
.info-panel-title, .info-panel-title,
.info-panel-content { .info-panel-content {
animation-duration: 0.3s; animation-duration: 0.3s;
@@ -237,12 +153,7 @@
transform: none !important; transform: none !important;
} }
.contact-item::before,
.contact-content-container::before { .contact-content-container::before {
display: none !important; display: none !important;
} }
.contact-item:hover {
transform: none;
}
} }

View File

@@ -1,97 +1,56 @@
<!-- Contact content with proper container structure --> <!-- Contact content with proper container structure -->
<div class="max-w-6xl mx-auto contact-content-container"> <div class="max-w-6xl mx-auto contact-content-container">
<!-- Availability Status --> <!-- Availability Status -->
<div class="inline-flex items-center gap-2 bg-nier-dark text-nier-light px-5 py-3 border border-nier-border mb-12 font-terminal text-xs uppercase tracking-wide availability-status mx-6"> <div
<div class="w-2 h-2 bg-green-500 rounded-full animate-pulse status-dot"></div> class="inline-flex items-center gap-2 bg-nier-dark text-nier-light px-5 py-3 border border-nier-border mb-12 font-terminal text-xs uppercase tracking-wide availability-status mx-6"
>
<div
class="w-2 h-2 bg-green-500 rounded-full animate-pulse status-dot"
></div>
AVAILABLE FOR OPPORTUNITIES AVAILABLE FOR OPPORTUNITIES
</div> </div>
<!-- Contact Grid --> <!-- Contact Grid -->
<div class="grid grid-cols-1 gap-6 w-full max-w-md mx-auto md:max-w-none contact-grid px-6"> <div
<!-- Primary Communication Channel --> class="grid grid-cols-1 gap-6 w-full max-w-md mx-auto md:max-w-none contact-grid px-6"
<a >
href="mailto:adam.benyekkou.pro@hotmail.com" <app-link-card
class="bg-nier-bg border border-nier-border p-8 flex items-center gap-6 text-nier-dark no-underline transition-all duration-200 hover:bg-nier-highlight hover:text-nier-light hover:border-nier-accent group contact-item relative" title="EMAIL COMMUNICATION CHANNEL"
> contact_link="mailto:adam.benyekkou.pro@hotmail.com"
<div class="w-14 h-14 bg-nier-mid border border-nier-border flex items-center justify-center text-xl text-nier-dark flex-shrink-0 transition-all duration-200 group-hover:bg-nier-light group-hover:text-nier-dark contact-icon"> description="Secure encrypted transmission protocol"
<i class="fas fa-envelope"></i> />
</div> <app-link-card
<div class="flex-1"> title="PROFESSIONAL NETWORK ACCESS"
<div class="font-terminal font-medium text-base text-nier-dark uppercase tracking-wide mb-2 group-hover:text-nier-light contact-label"> contact_link="https://linkedin.com/in/adambnk"
PRIMARY COMMUNICATION CHANNEL description="LinkedIn professional interface<br>
</div> Connect for career opportunities and networking"
<div class="font-noto-jp text-base text-nier-mid leading-relaxed group-hover:text-nier-light contact-value"> />
Email Access Granted<br> <app-link-card
Secure encrypted transmission protocol enabled title="SOURCE CODE REPOSITORY"
</div> contact_link="https://github.com/adam-benyekkou"
</div> description="GitHub development archives<br />
</a> Access project source files and contribution history"
/>
<!-- Professional Network Access -->
<a
href="https://linkedin.com/in/adambnk"
target="_blank"
class="bg-nier-bg border border-nier-border p-8 flex items-center gap-6 text-nier-dark no-underline transition-all duration-200 hover:bg-nier-highlight hover:text-nier-light hover:border-nier-accent group contact-item relative"
>
<div class="w-14 h-14 bg-nier-mid border border-nier-border flex items-center justify-center text-xl text-nier-dark flex-shrink-0 transition-all duration-200 group-hover:bg-nier-light group-hover:text-nier-dark contact-icon">
<i class="fab fa-linkedin-in"></i>
</div>
<div class="flex-1">
<div class="font-terminal font-medium text-base text-nier-dark uppercase tracking-wide mb-2 group-hover:text-nier-light contact-label">
PROFESSIONAL NETWORK ACCESS
</div>
<div class="font-noto-jp text-base text-nier-mid leading-relaxed group-hover:text-nier-light contact-value">
LinkedIn professional interface<br>
Connect for career opportunities and networking
</div>
</div>
</a>
<!-- Source Code Repository -->
<a
href="https://github.com/adam-benyekkou"
target="_blank"
class="bg-nier-bg border border-nier-border p-8 flex items-center gap-6 text-nier-dark no-underline transition-all duration-200 hover:bg-nier-highlight hover:text-nier-light hover:border-nier-accent group contact-item relative"
>
<div class="w-14 h-14 bg-nier-mid border border-nier-border flex items-center justify-center text-xl text-nier-dark flex-shrink-0 transition-all duration-200 group-hover:bg-nier-light group-hover:text-nier-dark contact-icon">
<i class="fab fa-github"></i>
</div>
<div class="flex-1">
<div class="font-terminal font-medium text-base text-nier-dark uppercase tracking-wide mb-2 group-hover:text-nier-light contact-label">
SOURCE CODE REPOSITORY
</div>
<div class="font-noto-jp text-base text-nier-mid leading-relaxed group-hover:text-nier-light contact-value">
GitHub development archives<br>
Access project source files and contribution history
</div>
</div>
</a>
</div> </div>
<!-- Info Panels --> <!-- Info Panels -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-12 w-full info-panels-container px-6"> <div
class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-12 w-full info-panels-container px-6"
>
<!-- Response Protocol --> <!-- Response Protocol -->
<div class="bg-nier-mid border border-nier-border p-6 info-panel"> <app-info-panel
<div class="font-terminal text-base font-medium text-nier-dark mb-3 uppercase tracking-wide info-panel-title"> title="RESPONSE PROTOCOL"
RESPONSE PROTOCOL description="Standard response time: 24-48 hour cycle<br />
</div> Emergency contact: Email protocol recommended<br />
<div class="font-noto-jp text-base text-nier-dark leading-relaxed info-panel-content"> Priority inquiries: LinkedIn messaging for urgent requests"
Standard response time: 24-48 hour cycle<br> />
Emergency contact: Email protocol recommended<br>
Priority inquiries: LinkedIn messaging for urgent requests
</div>
</div>
<!-- Collaboration Status --> <app-info-panel
<div class="bg-nier-mid border border-nier-border p-6 info-panel mb-8"> class="mb-8"
<div class="font-terminal text-base font-medium text-nier-dark mb-3 uppercase tracking-wide info-panel-title"> title="COLLABORATION STATUS"
COLLABORATION STATUS description="Currently seeking: Full-time opportunities, internships<br />
</div> Specialization: Web development, Angular, PHP, Python<br />
<div class="font-noto-jp text-base text-nier-dark leading-relaxed info-panel-content"> Location: Remote-ready, Toulouse, France"
Currently seeking: Full-time opportunities, internships, freelance projects<br> />
Specialization: Web development, Angular, modern tech stack<br>
Location: Remote-ready, French hideout base of operations
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -1,11 +1,11 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { InfoPanelComponent } from './info-panel/info-panel.component';
import { LinkCardComponent } from './link-card/link-card.component';
@Component({ @Component({
selector: 'app-contact-content', selector: 'app-contact-content',
imports: [], imports: [InfoPanelComponent, LinkCardComponent],
templateUrl: './contact-content.component.html', templateUrl: './contact-content.component.html',
styleUrl: './contact-content.component.css' styleUrl: './contact-content.component.css',
}) })
export class ContactContentComponent { export class ContactContentComponent {}
}

View File

@@ -0,0 +1,84 @@
/* ===================== CONTACT PAGE ANIMATIONS ===================== */
/* Core keyframes - reused across components */
@keyframes slideInLeft {
from {
opacity: 0;
transform: translate3d(-30px, 0, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* ===================== INFO PANELS ===================== */
/* Info panels */
.info-panel {
opacity: 0;
animation: scaleIn 0.6s ease-out forwards;
}
.info-panel:nth-child(1) { animation-delay: 1.6s; }
.info-panel:nth-child(2) { animation-delay: 1.7s; }
/* Info panel titles and content */
.info-panel-title {
opacity: 0;
animation: slideInLeft 0.4s ease-out forwards;
}
.info-panel-content {
opacity: 0;
animation: fadeIn 0.4s ease-out forwards;
}
.info-panel:nth-child(1) .info-panel-title { animation-delay: 1.8s; }
.info-panel:nth-child(2) .info-panel-title { animation-delay: 1.9s; }
.info-panel:nth-child(1) .info-panel-content { animation-delay: 1.9s; }
.info-panel:nth-child(2) .info-panel-content { animation-delay: 2.0s; }
/* ===================== RESPONSIVE DESIGN ===================== */
@media (max-width: 768px) {
.info-panel:nth-child(1) { animation-delay: 1.3s; }
.info-panel:nth-child(2) { animation-delay: 1.4s; }
/* Faster animations on mobile */
.info-panel {
animation-duration: 0.6s;
}
.info-panel-title,
.info-panel-content {
animation-duration: 0.3s;
}
}
/* ===================== ACCESSIBILITY ===================== */
@media (prefers-reduced-motion: reduce) {
*[class*="info-"] {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
}

View File

@@ -0,0 +1,11 @@
<div class="bg-nier-mid border border-nier-border p-6 info-panel">
<div
class="font-terminal text-base font-medium text-nier-dark mb-3 uppercase tracking-wide info-panel-title"
>
{{ title() }}
</div>
<div
class="font-noto-jp text-base text-nier-dark leading-relaxed info-panel-content"
[innerHTML]="description()"
></div>
</div>

View File

@@ -0,0 +1,12 @@
import { Component, input } from '@angular/core';
@Component({
selector: 'app-info-panel',
imports: [],
templateUrl: './info-panel.component.html',
styleUrl: './info-panel.component.css',
})
export class InfoPanelComponent {
title = input.required<string>();
description = input.required<string>();
}

View File

@@ -0,0 +1,141 @@
/* ===================== CONTACT PAGE ANIMATIONS ===================== */
/* Core keyframes - reused across components */
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes scanLine {
from { transform: translate3d(-100%, 0, 0); opacity: 0; }
50% { opacity: 1; }
to { transform: translate3d(100%, 0, 0); opacity: 0; }
}
/* ===================== CONTACT ELEMENTS ===================== */
/* Contact items */
.contact-item {
opacity: 0;
animation: scaleIn 0.8s ease-out forwards;
position: relative;
}
.contact-item:nth-child(1) { animation-delay: 1.0s; }
.contact-item:nth-child(2) { animation-delay: 1.1s; }
.contact-item:nth-child(3) { animation-delay: 1.2s; }
/* Scan line effect */
.contact-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 2px;
background: linear-gradient(90deg, transparent, var(--color-nier-accent), transparent);
animation: scanLine 1.5s ease-out forwards;
z-index: 20;
}
.contact-item:nth-child(1)::before { animation-delay: 1.2s; }
.contact-item:nth-child(2)::before { animation-delay: 1.3s; }
.contact-item:nth-child(3)::before { animation-delay: 1.4s; }
/* Contact icons */
.contact-icon {
opacity: 0;
animation: scaleIn 0.5s ease-out forwards;
}
.contact-item:nth-child(1) .contact-icon { animation-delay: 1.3s; }
.contact-item:nth-child(2) .contact-icon { animation-delay: 1.4s; }
.contact-item:nth-child(3) .contact-icon { animation-delay: 1.5s; }
/* Contact labels and values */
.contact-label,
.contact-value {
opacity: 0;
animation: slideInLeft 0.4s ease-out forwards;
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translate3d(-30px, 0, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.contact-item:nth-child(1) .contact-label { animation-delay: 1.4s; }
.contact-item:nth-child(2) .contact-label { animation-delay: 1.5s; }
.contact-item:nth-child(3) .contact-label { animation-delay: 1.6s; }
.contact-item:nth-child(1) .contact-value { animation-delay: 1.5s; }
.contact-item:nth-child(2) .contact-value { animation-delay: 1.6s; }
.contact-item:nth-child(3) .contact-value { animation-delay: 1.7s; }
/* ===================== HOVER EFFECTS ===================== */
.contact-item:hover {
transform: translateY(-3px);
box-shadow:
0 8px 25px rgba(0, 0, 0, 0.2),
0 0 20px rgba(90, 90, 80, 0.1);
transition: all 0.3s ease;
}
.contact-item:hover .contact-icon {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(90, 90, 80, 0.3);
transition: all 0.3s ease;
}
/* ===================== RESPONSIVE DESIGN ===================== */
@media (max-width: 768px) {
.contact-item:nth-child(1) { animation-delay: 0.8s; }
.contact-item:nth-child(2) { animation-delay: 0.9s; }
.contact-item:nth-child(3) { animation-delay: 1.0s; }
/* Faster animations on mobile */
.contact-item {
animation-duration: 0.6s;
}
.contact-icon,
.contact-label,
.contact-value {
animation-duration: 0.3s;
}
}
/* ===================== ACCESSIBILITY ===================== */
@media (prefers-reduced-motion: reduce) {
.contact-item,
.contact-icon,
.contact-label,
.contact-value {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
.contact-item::before {
display: none !important;
}
.contact-item:hover {
transform: none;
}
}

View File

@@ -0,0 +1,15 @@
<a
[href]="contact_link()" target="_blank"
class="bg-nier-bg border border-nier-border p-8 flex items-center gap-6 text-nier-dark no-underline transition-all duration-200 hover:bg-nier-highlight hover:text-nier-light hover:border-nier-accent group contact-item relative"
>
<div class="w-14 h-14 bg-nier-mid border border-nier-border flex items-center justify-center text-xl text-nier-dark flex-shrink-0 transition-all duration-200 group-hover:bg-nier-light group-hover:text-nier-dark contact-icon">
<i class="fas fa-envelope"></i>
</div>
<div class="flex-1">
<div class="font-terminal font-medium text-base text-nier-dark uppercase tracking-wide mb-2 group-hover:text-nier-light contact-label">
{{ title() }}
</div>
<div class="font-noto-jp text-base text-nier-mid leading-relaxed group-hover:text-nier-light contact-value" [innerHTML]="description()">
</div>
</div>
</a>

View File

@@ -0,0 +1,13 @@
import { Component, input } from '@angular/core';
@Component({
selector: 'app-link-card',
imports: [],
templateUrl: './link-card.component.html',
styleUrl: './link-card.component.css',
})
export class LinkCardComponent {
title = input.required<string>();
contact_link = input.required<string>();
description = input.required<string>();
}