PublicLayout.tsx 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import React from 'react'
  2. import type { ReactNode } from 'react'
  3. import { Link, useLocation } from 'react-router-dom'
  4. import { useLegacyThemePage, usePageContext } from '../shared/pageContext'
  5. import { AppLogo } from '../components/common/AppLogo'
  6. import { LocaleSwitcher } from '../components/common/LocaleSwitcher'
  7. function PublicHeader() {
  8. const { locale, path, copy } = usePageContext()
  9. const location = useLocation()
  10. const profilePath = path('/profile')
  11. const customerSimulationPath = path('/customer-simulation')
  12. const isCustomerSimulation = location.pathname.startsWith(customerSimulationPath)
  13. const pageCopy = copy.publicLayout
  14. const navCopy = locale === 'zh'
  15. ? { profile: '美发师主页', templates: '发型参考', simulation: 'AI发型试试看', reviews: '评价' }
  16. : pageCopy.nav
  17. return (
  18. <header>
  19. <nav className="navbar navbar-expand-lg header-light bg-white box-shadow-small">
  20. <div className="container-fluid">
  21. <div className="col-auto me-auto">
  22. <Link className="navbar-brand" to={path('')}>
  23. <AppLogo />
  24. </Link>
  25. </div>
  26. <div className="col-auto menu-order position-static">
  27. <button
  28. className="navbar-toggler float-start"
  29. type="button"
  30. data-bs-toggle="collapse"
  31. data-bs-target="#publicNavbarNav"
  32. aria-controls="publicNavbarNav"
  33. aria-label="Toggle navigation"
  34. >
  35. <span className="navbar-toggler-line"></span>
  36. <span className="navbar-toggler-line"></span>
  37. <span className="navbar-toggler-line"></span>
  38. <span className="navbar-toggler-line"></span>
  39. </button>
  40. <div className="collapse navbar-collapse" id="publicNavbarNav">
  41. <ul className="navbar-nav">
  42. <li className="nav-item"><a href={`${profilePath}#profile`} className="nav-link">{navCopy.profile}</a></li>
  43. <li className="nav-item"><a href={`${profilePath}#templates`} className="nav-link">{navCopy.templates}</a></li>
  44. <li className="nav-item"><Link to={customerSimulationPath} className={`nav-link${isCustomerSimulation ? ' active' : ''}`}>{navCopy.simulation}</Link></li>
  45. <li className="nav-item"><a href={`${profilePath}#reviews`} className="nav-link">{navCopy.reviews}</a></li>
  46. </ul>
  47. </div>
  48. </div>
  49. <div className="col-auto d-flex stylist-dashboard-actions gap-2">
  50. <LocaleSwitcher locale={locale} />
  51. </div>
  52. </div>
  53. </nav>
  54. </header>
  55. )
  56. }
  57. export function PublicLayout({ children, footer = true }: { children: ReactNode; footer?: boolean }) {
  58. useLegacyThemePage({ bodyClassName: '', mobileNavStyle: 'classic' })
  59. const { copy } = usePageContext()
  60. return (
  61. <>
  62. <PublicHeader />
  63. {children}
  64. {footer ? (
  65. <footer className="p-0 footer-light position-relative">
  66. <div className="container">
  67. <div className="row justify-content-center pt-5 pb-5 sm-pt-40px sm-pb-40px">
  68. <div className="col-12 text-center">
  69. <img src="/images/logo_color.svg" alt="Aitori Stylist" className="footer-logo mb-20px" style={{ maxWidth: '160px' }} />
  70. <div className="fs-16 text-medium-gray">{copy.publicLayout.footer}</div>
  71. </div>
  72. </div>
  73. </div>
  74. </footer>
  75. ) : null}
  76. </>
  77. )
  78. }