129 lines
3.9 KiB
TypeScript
129 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import type { ContactItem, FooterContactId } from './IsoTypes';
|
|
import IsometricScene from './IsometricScene';
|
|
import {
|
|
MailIcon,
|
|
PhoneIcon,
|
|
LinkedInIcon,
|
|
GitHubIcon,
|
|
TelegramIcon,
|
|
} from './IsoElements';
|
|
import styles from './IsometricFooter.module.css';
|
|
|
|
export const contacts: ContactItem[] = [
|
|
{
|
|
id: 'phone',
|
|
name: 'Phone',
|
|
label: '09388263077',
|
|
href: 'tel:09388263077',
|
|
Icon: PhoneIcon,
|
|
},
|
|
{
|
|
id: 'linkedin',
|
|
name: 'LinkedIn',
|
|
label: '@amiirkhl',
|
|
href: 'https://linkedin.com/in/amiirkhl',
|
|
Icon: LinkedInIcon,
|
|
},
|
|
{
|
|
id: 'github',
|
|
name: 'GitHub',
|
|
label: 'git.amiirkhl.ir',
|
|
href: 'https://git.amiirkhl.ir',
|
|
Icon: GitHubIcon,
|
|
},
|
|
{
|
|
id: 'telegram',
|
|
name: 'Telegram',
|
|
label: '@amiirkhl',
|
|
href: 'https://t.me/amiirkhl',
|
|
Icon: TelegramIcon,
|
|
},
|
|
];
|
|
|
|
export default function IsometricFooter() {
|
|
const [activePost, setActivePost] = useState<FooterContactId | null>(null);
|
|
|
|
const handlePostClick = (id: FooterContactId) => {
|
|
const item = contacts.find((c) => c.id === id);
|
|
if (item && item.href) {
|
|
if (item.href.startsWith('tel:')) {
|
|
window.location.href = item.href;
|
|
} else {
|
|
window.open(item.href, '_blank', 'noopener,noreferrer');
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={styles.footerContainer}>
|
|
{/* Top Header & Contact Section */}
|
|
<header className={styles.footerHeader}>
|
|
<h2 className={styles.headerTitle}>
|
|
Let's build something meaningful.
|
|
</h2>
|
|
|
|
<p className={styles.headerSubtitle}>
|
|
Open to opportunities and interesting projects.
|
|
</p>
|
|
|
|
{/* Email Pill Button */}
|
|
<div className={styles.emailWrapper}>
|
|
<a
|
|
href="mailto:amirhosseinkhalili901@gmail.com"
|
|
className={styles.emailPill}
|
|
aria-label="Send email to amirhosseinkhalili901@gmail.com"
|
|
>
|
|
<span className={styles.emailIcon}>
|
|
<MailIcon size={16} color="currentColor" />
|
|
</span>
|
|
<span className={styles.emailText}>amirhosseinkhalili901@gmail.com</span>
|
|
</a>
|
|
</div>
|
|
</header>
|
|
|
|
{/* 3D Isometric SVG Scene */}
|
|
<div className={styles.sceneContainer}>
|
|
<IsometricScene
|
|
activePost={activePost}
|
|
onPostHover={setActivePost}
|
|
onPostClick={handlePostClick}
|
|
/>
|
|
</div>
|
|
|
|
{/* Responsive Synchronized Contact Cards Section */}
|
|
<section className={styles.contactCardsSection} aria-label="Social and contact links">
|
|
<div className={styles.contactCardsGrid}>
|
|
{contacts.map((contact) => {
|
|
const IconComponent = contact.Icon;
|
|
const isHovered = activePost === contact.id;
|
|
return (
|
|
<a
|
|
key={contact.id}
|
|
href={contact.href}
|
|
target={contact.href.startsWith('tel:') ? undefined : '_blank'}
|
|
rel={contact.href.startsWith('tel:') ? undefined : 'noopener noreferrer'}
|
|
className={`${styles.contactCard} ${isHovered ? styles.active : ''}`}
|
|
onMouseEnter={() => setActivePost(contact.id)}
|
|
onMouseLeave={() => setActivePost(null)}
|
|
onClick={() => setActivePost(contact.id)}
|
|
aria-label={`${contact.name}: ${contact.label}`}
|
|
>
|
|
<div className={styles.contactCardIconWrap}>
|
|
<IconComponent size={18} color="currentColor" />
|
|
</div>
|
|
<div className={styles.contactCardInfo}>
|
|
<span className={styles.contactCardName}>{contact.name}</span>
|
|
<span className={styles.contactCardLabel}>{contact.label}</span>
|
|
</div>
|
|
</a>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|