108 lines
5.0 KiB
TypeScript
108 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
import { Icon, IconName, MarkdownText, Typography } from "@/components/ui";
|
|
|
|
import styles from "./PortraitView.module.scss";
|
|
|
|
interface PortraitViewProps {
|
|
id: string;
|
|
title: string;
|
|
imageUrl: string;
|
|
result?: string | null;
|
|
}
|
|
|
|
export default function PortraitView({ title, imageUrl, result }: PortraitViewProps) {
|
|
const router = useRouter();
|
|
|
|
const handleDownload = async () => {
|
|
try {
|
|
const response = await fetch(imageUrl);
|
|
const blob = await response.blob();
|
|
const url = window.URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = `${title.replace(/\s+/g, "_")}.jpg`;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
window.URL.revokeObjectURL(url);
|
|
} catch {
|
|
// Fallback: open in new tab if download fails
|
|
window.open(imageUrl, "_blank");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
{/* Header with back button and title */}
|
|
<div className={styles.header}>
|
|
<button className={styles.backButton} onClick={() => router.back()}>
|
|
<Icon name={IconName.ChevronLeft} size={{ width: 24, height: 24 }} />
|
|
</button>
|
|
<Typography as="h1" size="xl" weight="semiBold" className={styles.title}>
|
|
{title}
|
|
</Typography>
|
|
</div>
|
|
|
|
{/* Portrait Image and Description */}
|
|
<div className={styles.imageWrapper}>
|
|
<div className={styles.imageContainer}>
|
|
<div className={styles.imageInner}>
|
|
<Image
|
|
src={imageUrl}
|
|
alt="Partner Portrait"
|
|
fill
|
|
className={styles.image}
|
|
sizes="(max-width: 768px) 90vw, 600px"
|
|
priority
|
|
/>
|
|
</div>
|
|
|
|
{/* Download Button */}
|
|
<button
|
|
className={styles.downloadButton}
|
|
onClick={handleDownload}
|
|
aria-label="Download portrait"
|
|
>
|
|
<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<g filter="url(#filter0_dd_2449_3797)">
|
|
<path d="M6 22C6 10.9543 14.9543 2 26 2C37.0457 2 46 10.9543 46 22C46 33.0457 37.0457 42 26 42C14.9543 42 6 33.0457 6 22Z" fill="white" fillOpacity="0.75"/>
|
|
<path d="M25 13.0124C24.9983 12.4601 25.4446 12.011 25.9969 12.0093C26.5492 12.0076 26.9983 12.4539 27 13.0061L25 13.0124Z" fill="#646464"/>
|
|
<path d="M28.3158 20.2952L27.0269 21.5921L27 13.0063L25 13.0126L25.0269 21.5984L23.7301 20.3096C23.3383 19.9203 22.7051 19.9222 22.3158 20.314C21.9265 20.7057 21.9285 21.3389 22.3203 21.7282L22.3228 21.7307L22.3238 21.7317L26.039 25.4237L29.7206 21.7188L29.7262 21.7132L29.727 21.7124L29.7278 21.7116L29.7337 21.7057L28.3158 20.2952Z" fill="#646464"/>
|
|
<path d="M29.7345 21.7049C30.1238 21.3131 30.1218 20.6799 29.7301 20.2906C29.3383 19.9014 28.7051 19.9034 28.3159 20.2951L29.7345 21.7049Z" fill="#646464"/>
|
|
<path d="M18 22C18 20.8954 18.8954 20 20 20C20.5523 20 21 19.5523 21 19C21 18.4477 20.5523 18 20 18C17.7909 18 16 19.7909 16 22V28C16 30.2091 17.7909 32 20 32H31C33.7614 32 36 29.7614 36 27V22C36 19.7909 34.2091 18 32 18C31.4477 18 31 18.4477 31 19C31 19.5523 31.4477 20 32 20C33.1046 20 34 20.8954 34 22V27C34 28.6569 32.6569 30 31 30H20C18.8954 30 18 29.1046 18 28V22Z" fill="#646464"/>
|
|
</g>
|
|
<defs>
|
|
<filter id="filter0_dd_2449_3797" x="0" y="0" width="52" height="52" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
|
|
<feFlood floodOpacity="0" result="BackgroundImageFix"/>
|
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
|
<feOffset dy="4"/>
|
|
<feGaussianBlur stdDeviation="3"/>
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2449_3797"/>
|
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
|
<feOffset dy="2"/>
|
|
<feGaussianBlur stdDeviation="2"/>
|
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
|
<feBlend mode="normal" in2="effect1_dropShadow_2449_3797" result="effect2_dropShadow_2449_3797"/>
|
|
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_2449_3797" result="shape"/>
|
|
</filter>
|
|
</defs>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Portrait Description (Markdown) */}
|
|
{result && (
|
|
<div className={styles.descriptionWrapper}>
|
|
<MarkdownText content={result} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|