CruiseSpace.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import React, { useEffect } from 'react';
  2. import Navbar from '@/src/components/Navbar.tsx';
  3. import Sidebar from '@/src/components/Sidebar.tsx';
  4. import Footer from '@/src/components/Footer.tsx';
  5. import { CONTENT } from '../constants.ts';
  6. import { useLanguage } from '@/src/contexts/LanguageContext.tsx';
  7. import { useTheme } from '@/src/contexts/ThemeContext.tsx';
  8. import { useLocation, Link } from 'react-router-dom';
  9. import { ArrowRight, Anchor, Star, ChevronRight } from 'lucide-react';
  10. const CruiseSpace: React.FC = () => {
  11. const { language } = useLanguage();
  12. const { shipsPageImages } = useTheme();
  13. // We explicitly type 'any' here or assume CONTENT structure is updated because
  14. // TS might not immediately pick up the new keys added to constants without a full types reload in this context.
  15. // In a real app, types.ts should be updated, but here we access the object properties.
  16. const t = CONTENT[language].shipsPage as any;
  17. const location = useLocation();
  18. // Scroll to section on load or location change
  19. useEffect(() => {
  20. const SECTION_PREFIX = 'space-';
  21. const SCROLL_DELAY = 300; // ms - delay to ensure DOM is fully rendered
  22. const params = new URLSearchParams(location.search);
  23. const section = params.get('section');
  24. if (!section) {
  25. // Scroll to top when no section specified
  26. window.scrollTo({ top: 0, behavior: 'smooth' });
  27. return;
  28. }
  29. // Construct element ID and scroll to target section
  30. const elementId = `${SECTION_PREFIX}${section}`;
  31. const element = document.getElementById(elementId);
  32. if (element) {
  33. // Delay to ensure DOM is fully rendered before scrolling
  34. const timeoutId = setTimeout(() => {
  35. element.scrollIntoView({ behavior: 'smooth', block: 'start' });
  36. }, SCROLL_DELAY);
  37. // Cleanup timeout on unmount or search change
  38. return () => clearTimeout(timeoutId);
  39. }
  40. }, [location.search]);
  41. return (
  42. <div className="min-h-screen bg-white font-sans text-vista-darkblue overflow-x-hidden">
  43. <Navbar />
  44. <Sidebar />
  45. {/* Hero Section */}
  46. <div className="relative h-[70vh] w-full bg-vista-darkblue flex items-center justify-center overflow-hidden">
  47. <div className="absolute inset-0 bg-black/40 z-10"></div>
  48. <img
  49. src="https://images.unsplash.com/photo-1548291616-3c0f5f743538?q=80&w=1920&auto=format&fit=crop"
  50. alt="Ships Hero"
  51. className="absolute inset-0 w-full h-full object-cover animate-slow-zoom"
  52. />
  53. <div className="relative z-20 text-center text-white px-4 animate-fade-in-up">
  54. <span className="block text-sm md:text-base tracking-[0.3em] uppercase mb-4 text-vista-gold">{t.hero_sub}</span>
  55. <h1 className="text-5xl md:text-8xl font-serif italic mb-6">{CONTENT[language].nav.menu[1].title}</h1>
  56. <p className="max-w-xl mx-auto text-white/80 font-light text-lg">
  57. {t.hero_desc}
  58. </p>
  59. </div>
  60. </div>
  61. {/* Section 1: Facilities */}
  62. <section id="space-facilities" className="py-32 max-w-7xl mx-auto px-6">
  63. <div className="text-center mb-20">
  64. <h2 className="text-5xl md:text-7xl font-serif text-vista-darkblue mb-8">{t.spaces.facilities.title}</h2>
  65. <p className="text-vista-darkblue/70 text-lg md:text-xl leading-relaxed font-light max-w-3xl mx-auto">
  66. {t.spaces.facilities.desc}
  67. </p>
  68. </div>
  69. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
  70. {t.spaces.facilities.items.map((item: any, index: number) => (
  71. <div key={index} className="group bg-white p-8 rounded-lg shadow-lg hover:shadow-xl transition-all duration-300 hover:-translate-y-2">
  72. <div className="w-16 h-16 bg-vista-gold/10 rounded-full flex items-center justify-center mb-6 group-hover:bg-vista-gold transition-colors">
  73. <span className="text-vista-gold text-2xl">{index + 1}</span>
  74. </div>
  75. <h3 className="text-xl font-bold text-vista-darkblue mb-4">{item.title}</h3>
  76. <p className="text-vista-darkblue/70 leading-relaxed">{item.desc}</p>
  77. </div>
  78. ))}
  79. </div>
  80. </section>
  81. {/* Section 2: Room Types */}
  82. <section id="space-rooms" className="py-32 bg-vista-gray">
  83. <div className="max-w-7xl mx-auto px-6">
  84. <div className="text-center mb-20">
  85. <h2 className="text-5xl md:text-7xl font-serif text-vista-darkblue mb-8">{t.spaces.rooms.title}</h2>
  86. <p className="text-vista-darkblue/70 text-lg md:text-xl leading-relaxed font-light max-w-3xl mx-auto">
  87. {t.spaces.rooms.desc}
  88. </p>
  89. </div>
  90. <div className="grid grid-cols-1 md:grid-cols-2 gap-12">
  91. {t.spaces.rooms.types.map((room: any, index: number) => (
  92. <div key={index} className="bg-white rounded-lg overflow-hidden shadow-lg group">
  93. <div className="h-64 bg-vista-gold/20 relative overflow-hidden">
  94. <img
  95. src={`https://picsum.photos/600/400?random=${index + 10}`}
  96. alt={room.name}
  97. className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
  98. />
  99. <div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
  100. <div className="p-6 text-white">
  101. <div className="flex gap-4 mb-4">
  102. <span className="text-xs uppercase tracking-widest font-bold bg-white/20 px-3 py-1 rounded-full">{room.area}</span>
  103. <span className="text-xs uppercase tracking-widest font-bold bg-white/20 px-3 py-1 rounded-full">{room.view}</span>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. <div className="p-8">
  109. <h3 className="text-2xl font-serif text-vista-darkblue mb-4">{room.name}</h3>
  110. <p className="text-vista-darkblue/70 leading-relaxed mb-6">{room.desc}</p>
  111. <div className="flex justify-between items-center">
  112. <div className="flex gap-4">
  113. <div className="text-center">
  114. <div className="text-vista-gold font-bold">{room.area}</div>
  115. <div className="text-xs text-vista-darkblue/70">面积</div>
  116. </div>
  117. <div className="text-center">
  118. <div className="text-vista-gold font-bold">{room.view}</div>
  119. <div className="text-xs text-vista-darkblue/70">景观</div>
  120. </div>
  121. </div>
  122. <Link to="#" className="inline-flex items-center gap-2 text-vista-darkblue hover:text-vista-gold transition-colors font-bold uppercase text-xs tracking-wider">
  123. {t.view_itineraries} <ChevronRight size={16} />
  124. </Link>
  125. </div>
  126. </div>
  127. </div>
  128. ))}
  129. </div>
  130. </div>
  131. </section>
  132. {/* Section 3: VIP Privileges */}
  133. <section id="space-vip" className="py-32 relative overflow-hidden">
  134. {/* Background */}
  135. <div className="absolute inset-0 opacity-10">
  136. <img
  137. src={shipsPageImages.lanyue[0]}
  138. alt="VIP"
  139. className="w-full h-full object-cover"
  140. />
  141. </div>
  142. <div className="max-w-7xl mx-auto px-6 relative z-10">
  143. <div className="text-center mb-20">
  144. <h2 className="text-5xl md:text-7xl font-serif text-vista-darkblue mb-8">{t.spaces.vip.title}</h2>
  145. <p className="text-vista-darkblue/70 text-lg md:text-xl leading-relaxed font-light max-w-3xl mx-auto">
  146. {t.spaces.vip.desc}
  147. </p>
  148. </div>
  149. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 max-w-5xl mx-auto">
  150. {t.spaces.vip.benefits.map((benefit: string, index: number) => (
  151. <div key={index} className="bg-white p-6 rounded-lg shadow-md group hover:shadow-lg transition-all duration-300">
  152. <div className="w-12 h-12 bg-vista-gold/10 rounded-full flex items-center justify-center mb-4 group-hover:bg-vista-gold group-hover:text-white transition-colors">
  153. <Star size={20} className="text-vista-gold group-hover:text-white" />
  154. </div>
  155. <p className="text-center text-vista-darkblue font-medium">{benefit}</p>
  156. </div>
  157. ))}
  158. </div>
  159. <div className="mt-16 text-center">
  160. <Link to="/itineraries" className="inline-flex items-center gap-3 px-10 py-4 bg-vista-darkblue text-white uppercase tracking-widest text-xs font-bold hover:bg-vista-gold transition-colors duration-300">
  161. {t.view_itineraries} <ChevronRight size={16} />
  162. </Link>
  163. </div>
  164. </div>
  165. </section>
  166. <Footer />
  167. </div>
  168. );
  169. };
  170. export default CruiseSpace;