StylistProfilePage.tsx 10 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import { useState } from 'react'
  2. import { Link } from 'react-router-dom'
  3. import { Helmet } from 'react-helmet-async'
  4. import { PublicLayout } from '../../layouts/PublicLayout'
  5. import { ImageLightbox } from '../../components/common/ImageLightbox'
  6. import { publicHairstyleTemplates, type PublicHairstyleTemplate } from '../../shared/demoContent'
  7. import { getStoredStylistProfile } from '../../shared/stylistProfileStore'
  8. import { usePageContext } from '../../shared/pageContext'
  9. type TemplateFilter = '*' | PublicHairstyleTemplate['category']
  10. export function StylistProfilePage() {
  11. const { locale, path } = usePageContext()
  12. const [profile] = useState(getStoredStylistProfile)
  13. const [filter, setFilter] = useState<TemplateFilter>('*')
  14. const [preview, setPreview] = useState<PublicHairstyleTemplate | null>(null)
  15. const visibleTemplates = filter === '*' ? publicHairstyleTemplates : publicHairstyleTemplates.filter((item) => item.category === filter)
  16. const structuredData = {
  17. '@context': 'https://schema.org', '@type': 'Person', name: profile.displayName,
  18. description: profile.lead, image: profile.photo, worksFor: { '@type': 'HairSalon', name: profile.salonName },
  19. }
  20. return (
  21. <PublicLayout>
  22. <Helmet><html lang={locale === 'ja' ? 'ja' : 'zh-CN'} /><title>Aitori Stylist | Demo Stylist 发型模板</title><meta name="description" content="选择 Demo Stylist 设计的发型模板,并用自己的照片进行 AI 试发型。" /><script type="application/ld+json">{JSON.stringify(structuredData)}</script></Helmet>
  23. <section id="profile" className="stylist-profile-hero public-profile-hero cover-background ipad-top-space-margin">
  24. <div className="container"><div className="row align-items-center justify-content-center">
  25. <div className="col-lg-5 col-md-8 md-mb-40px"><div className="stylist-profile-photo public-profile-photo bg-white border-radius-8px box-shadow-quadruple-large p-15px"><img src={profile.photo} alt={`${profile.displayName} 的头像`} className="border-radius-6px w-100" /></div></div>
  26. <div className="col-lg-6 offset-lg-1"><span className="bg-base-color d-inline-block mb-20px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">{profile.displayName} 的发型模板</span><h1 className="fw-700 text-dark-gray ls-minus-1px mb-20px">用你的照片,试试这位发型师设计的发型。</h1><p className="fs-20 lh-32 text-dark-gray fw-600 mb-20px">这里收录了 {profile.displayName} 常用于咨询的发型模板。选择喜欢的发型后,可以上传自己的照片,用 AI 先看看大致效果。</p><p className="fs-17 lh-30 mb-30px">适合在预约前确认长度、脸周层次、刘海和整体氛围。模拟结果可作为到店咨询时的参考。</p><div className="mb-30px"><Link to={path('/customer-simulation')} className="btn btn-extra-large btn-rounded btn-base-color btn-box-shadow fw-700"><i className="feather icon-feather-camera me-10px"></i>用我的照片试发型</Link><a href="#templates" className="btn btn-extra-large btn-rounded btn-transparent-light-gray border border-1 border-color-dark-gray fw-700 ms-10px xs-ms-0 xs-mt-10px">先看发型模板</a></div><div className="row row-cols-3 g-3 text-center public-profile-stats"><div className="col"><div className="bg-white border-radius-8px p-20px h-100"><span className="d-block fs-24 fw-800 text-dark-gray">{profile.years}</span><span className="fs-14">经验</span></div></div><div className="col"><div className="bg-white border-radius-8px p-20px h-100"><span className="d-block fs-24 fw-800 text-dark-gray">8</span><span className="fs-14">公开模板</span></div></div><div className="col"><div className="bg-white border-radius-8px p-20px h-100"><span className="d-block fs-24 fw-800 text-dark-gray">{profile.rating}</span><span className="fs-14">评分</span></div></div></div></div>
  27. </div></div>
  28. </section>
  29. <section className="half-section public-profile-actions pt-0"><div className="container"><div className="row row-cols-1 row-cols-lg-3 row-cols-md-3 justify-content-center g-4"><div className="col"><a href="#templates" className="public-profile-action-card public-profile-action-gallery"><i className="feather icon-feather-grid"></i><span><strong>选择发型模板</strong><small>浏览这位发型师公开的推荐发型。</small></span></a></div><div className="col"><Link to={path('/customer-simulation')} className="public-profile-action-card public-profile-action-simulation"><i className="feather icon-feather-camera"></i><span><strong>上传照片试发型</strong><small>用你的照片生成 AI 模拟效果。</small></span></Link></div><div className="col"><a href="#stylist" className="public-profile-action-card public-profile-action-booking"><i className="feather icon-feather-user"></i><span><strong>了解发型师</strong><small>查看擅长风格和咨询特点。</small></span></a></div></div></div></section>
  30. <section id="templates" className="bg-gradient-very-light-gray"><div className="container">
  31. <div className="row justify-content-center mb-5"><div className="col-lg-8 text-center"><span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">Style Templates</span><h2 className="fw-700 text-dark-gray ls-minus-1px">选择你想尝试的发型</h2><p className="w-80 lg-w-100 mx-auto">点击图片可以放大查看。决定想试哪一款后,进入 AI 试发型流程,上传自己的照片进行模拟。</p></div></div>
  32. <div className="row"><div className="col-12 text-center"><ul className="portfolio-filter nav nav-tabs justify-content-center border-0 fw-500 alt-font pb-5">{([['*', '全部'], ['long', '长发'], ['medium', '中长发'], ['short', '短发']] as const).map(([value, label]) => <li key={value} className={`nav${filter === value ? ' active' : ''}`}><button type="button" onClick={() => setFilter(value)}>{label}</button></li>)}</ul></div></div>
  33. <ul className="aitori-template-gallery-grid">{visibleTemplates.map((item) => <li key={item.id} className="transition-inner-all"><div className="portfolio-box"><button type="button" onClick={() => setPreview(item)}><div className="portfolio-image"><img src={item.image} alt={item.name} /></div><div className="portfolio-hover justify-content-center align-items-center d-flex flex-column pt-40px pb-40px"><div className="text-uppercase portfolio-title mt-auto alt-font fs-26 fw-700 text-white" data-text={item.accent}></div><span className="mt-auto d-inline-block text-uppercase pt-5px pb-5px fw-500 ps-15px pe-15px bg-white text-dark-gray fs-12 lh-20 border-radius-2px">{item.name}</span></div></button></div></li>)}</ul>
  34. </div></section>
  35. <section id="stylist" className="half-section"><div className="container"><div className="row align-items-center justify-content-center"><div className="col-lg-5 md-mb-35px"><span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">Stylist</span><h2 className="fw-700 text-dark-gray ls-minus-1px mb-20px">{profile.displayName}</h2><p className="fs-18 lh-30 mb-20px">{profile.specialties}</p><p className="mb-0">如果你还不确定适合什么长度或风格,可以先用模板模拟,再把结果带到咨询里一起讨论。</p></div><div className="col-lg-5 offset-lg-1"><div className="row row-cols-1 g-3"><InfoCard label="沙龙" value={profile.address.replace(/\n/g, ' ')} /><InfoCard label="营业时间" value={profile.hours.replace(/\n/g, ' / ')} /><InfoCard label="擅长" value="脸周层次、自然长发、清爽短发、易打理造型" /></div></div></div></div></section>
  36. <section id="reviews" className="bg-gradient-very-light-gray half-section"><div className="container"><div className="row justify-content-center mb-5"><div className="col-lg-8 text-center"><span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">Voice</span><h2 className="fw-700 text-dark-gray ls-minus-1px">顾客反馈</h2></div></div><div className="row row-cols-1 row-cols-lg-3 row-cols-md-2 justify-content-center g-4"><Review title="到店前就比较安心" body="先看过模拟图,再和发型师讨论,比较容易说出自己想要的感觉。" /><Review title="更容易比较长度" body="长一点、短一点的差别可以先看效果,决定发型时不会那么犹豫。" /><Review title="咨询更具体" body="拿着模拟结果沟通,发型师也更容易理解我想改变的地方。" /></div></div></section>
  37. <section className="half-section"><div className="container"><div className="public-profile-bottom-cta"><div><span className="bg-base-color d-inline-block mb-15px fw-600 text-white text-uppercase border-radius-30px ps-20px pe-20px fs-12">AI Try-on</span><h2 className="fw-700 text-dark-gray fs-32 mb-10px">选好发型后,用你的照片试试看。</h2><p className="mb-0">模拟结果不是最终承诺,而是帮助你和发型师更快对齐方向的参考。</p></div><Link to={path('/customer-simulation')} className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700">开始 AI 试发型</Link></div></div></section>
  38. <ImageLightbox image={preview?.image || null} alt={preview?.name} onClose={() => setPreview(null)} action={<Link to={path('/customer-simulation')} className="btn btn-large btn-rounded btn-base-color btn-box-shadow fw-700">用我的照片试这款</Link>} />
  39. </PublicLayout>
  40. )
  41. }
  42. function InfoCard({ label, value }: { label: string; value: string }) { return <div className="col"><div className="bg-white border-radius-8px box-shadow-extra-large p-25px"><strong className="text-dark-gray d-block mb-5px">{label}</strong><span>{value}</span></div></div> }
  43. function Review({ title, body }: { title: string; body: string }) { return <div className="col"><div className="bg-white border-radius-8px box-shadow-extra-large p-30px h-100"><div className="review-star-icon mb-15px">{Array.from({ length: 5 }, (_, index) => <i key={index} className="bi bi-star-fill"></i>)}</div><h6 className="fw-700 text-dark-gray mb-10px">{title}</h6><p className="mb-0">{body}</p></div></div> }