88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
|
|
import IsometricScene from './IsometricScene';
|
|
import {
|
|
MailIcon,
|
|
PhoneIcon,
|
|
LinkedInIcon,
|
|
GitHubIcon,
|
|
TelegramIcon,
|
|
} from './IsoElements';
|
|
import styles from './IsometricFooter.module.css';
|
|
import type { PortfolioProps } from '@/server/content';
|
|
import { FooterInteraction } from './FooterInteraction';
|
|
|
|
const contactIcons = { phone: PhoneIcon, linkedin: LinkedInIcon, github: GitHubIcon, telegram: TelegramIcon };
|
|
|
|
export default function IsometricFooter({ portfolio }: PortfolioProps) {
|
|
const copy = portfolio.messages.footer;
|
|
const localizedContacts = portfolio.profile.contacts.filter(contact => contact.href).map((contact) => ({
|
|
...contact,
|
|
name: copy[contact.id], Icon: contactIcons[contact.id],
|
|
}));
|
|
return (
|
|
<FooterInteraction className={styles.footerContainer}>
|
|
{/* Top Header & Contact Section */}
|
|
<header className={styles.footerHeader}>
|
|
<h2 className={styles.headerTitle} data-reveal="soft">
|
|
{copy.title}
|
|
</h2>
|
|
|
|
<p className={styles.headerSubtitle} data-reveal="soft">
|
|
{copy.subtitle}
|
|
</p>
|
|
|
|
{/* Email Pill Button */}
|
|
{portfolio.profile.email && <div className={styles.emailWrapper} data-reveal="scale">
|
|
<a
|
|
href={`mailto:${portfolio.profile.email}`}
|
|
className={styles.emailPill}
|
|
aria-label={copy.emailLabel}
|
|
>
|
|
<span className={styles.emailIcon}>
|
|
<MailIcon size={16} color="currentColor" />
|
|
</span>
|
|
<span className={styles.emailText} dir="ltr">
|
|
{portfolio.profile.email}
|
|
</span>
|
|
</a>
|
|
</div>}
|
|
</header>
|
|
|
|
{/* 3D Isometric SVG Scene */}
|
|
<div className={styles.sceneContainer} data-footer-reveal>
|
|
<IsometricScene ariaLabel={copy.sceneLabel} contacts={portfolio.profile.contacts} />
|
|
</div>
|
|
|
|
{/* Responsive Synchronized Contact Cards Section */}
|
|
<section className={styles.contactCardsSection} aria-label={copy.contactsLabel}>
|
|
<div className={styles.contactCardsGrid}>
|
|
{localizedContacts.map((contact) => {
|
|
const IconComponent = contact.Icon;
|
|
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}
|
|
data-contact-id={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} dir="ltr">
|
|
{contact.label}
|
|
</span>
|
|
</div>
|
|
</a>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
</FooterInteraction>
|
|
);
|
|
}
|