浏览代码

完善搜索功能,mock几条航线,优化部分代码

chenhg 1 月之前
父节点
当前提交
abd2356a0c

+ 29 - 18
src/App.tsx

@@ -1,32 +1,43 @@
 
-import React from 'react';
+import React, { Suspense } from 'react';
 import { HashRouter as Router, Routes, Route } from 'react-router-dom';
-import Home from '@/src/pages/Home.tsx';
-import Ships from '@/src/pages/Ships.tsx';
-import Itineraries from '@/src/pages/Itineraries.tsx';
-import AboutUs from '@/src/pages/AboutUs.tsx';
-import Guide from '@/src/pages/Guide.tsx';
-import CruiseExperience from '@/src/pages/CruiseExperience.tsx';
 import { LanguageProvider } from '@/src/contexts/LanguageContext.tsx';
 import { ThemeProvider } from '@/src/contexts/ThemeContext.tsx';
 import './styles.css';
-import CruiseSpace from "@/src/pages/CruiseSpace.tsx";
+
+// 路由级代码分割
+const Home = React.lazy(() => import('@/src/pages/Home.tsx'));
+const Ships = React.lazy(() => import('@/src/pages/Ships.tsx'));
+const Itineraries = React.lazy(() => import('@/src/pages/Itineraries.tsx'));
+const AboutUs = React.lazy(() => import('@/src/pages/AboutUs.tsx'));
+const Guide = React.lazy(() => import('@/src/pages/Guide.tsx'));
+const CruiseExperience = React.lazy(() => import('@/src/pages/CruiseExperience.tsx'));
+const CruiseSpace = React.lazy(() => import('@/src/pages/CruiseSpace.tsx'));
+
+// 加载占位符组件
+const LoadingFallback = () => (
+  <div className="flex justify-center items-center h-screen bg-gray-50">
+    <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
+  </div>
+);
 
 const App: React.FC = () => {
   return (
     <ThemeProvider>
       <LanguageProvider>
         <Router>
-          <Routes>
-            <Route path="/" element={<Home />} />
-            <Route path="/ships" element={<Ships />} />
-            <Route path="/itineraries" element={<Itineraries />} />
-            <Route path="/guide" element={<Guide />} />
-            <Route path="/spaces" element={<CruiseSpace />} />
-            <Route path="/experience" element={<CruiseExperience />} />
-            <Route path="/about" element={<AboutUs />} />
-            <Route path="*" element={<Home />} />
-          </Routes>
+          <Suspense fallback={<LoadingFallback />}>
+            <Routes>
+              <Route path="/" element={<Home />} />
+              <Route path="/ships" element={<Ships />} />
+              <Route path="/itineraries" element={<Itineraries />} />
+              <Route path="/guide" element={<Guide />} />
+              <Route path="/spaces" element={<CruiseSpace />} />
+              <Route path="/experience" element={<CruiseExperience />} />
+              <Route path="/about" element={<AboutUs />} />
+              <Route path="*" element={<Home />} />
+            </Routes>
+          </Suspense>
         </Router>
       </LanguageProvider>
     </ThemeProvider>

+ 337 - 31
src/components/SearchOverlay.tsx

@@ -18,10 +18,17 @@ interface SearchResult {
   matchType: 'title' | 'content';
 }
 
+interface SearchSuggestion {
+  text: string;
+  count: number;
+  category: 'home' | 'itinerary' | 'ships' | 'dining' | 'activity' | 'all';
+}
+
 const SearchOverlay: React.FC<SearchOverlayProps> = ({ isOpen, onClose }) => {
   const { language } = useLanguage();
   const { itineraries, ships, dining, videoSection } = useTheme();
   const [query, setQuery] = useState('');
+  const [showSuggestions, setShowSuggestions] = useState(true);
   const inputRef = useRef<HTMLInputElement>(null);
   const navigate = useNavigate();
 
@@ -142,29 +149,281 @@ const SearchOverlay: React.FC<SearchOverlayProps> = ({ isOpen, onClose }) => {
         });
     }
 
+    // 7. CruiseSpace Page Content
+    const cruiseSpacePage = (t as any).shipsPage?.spaces;
+    if (cruiseSpacePage) {
+        // Facilities
+        index.push({
+            title: cruiseSpacePage.facilities.title,
+            subtitle: cruiseSpacePage.facilities.desc,
+            category: 'ships',
+            link: '/cruise-space?section=facilities',
+            matchType: 'title'
+        });
+        // Facilities Items
+        cruiseSpacePage.facilities.items?.forEach((item: any) => {
+            index.push({
+                title: item.title,
+                subtitle: item.desc,
+                category: 'ships',
+                link: '/cruise-space?section=facilities',
+                matchType: 'content'
+            });
+        });
+        // Rooms
+        index.push({
+            title: cruiseSpacePage.rooms.title,
+            subtitle: cruiseSpacePage.rooms.desc,
+            category: 'ships',
+            link: '/cruise-space?section=rooms',
+            matchType: 'title'
+        });
+        // Rooms Types
+        cruiseSpacePage.rooms.types?.forEach((room: any) => {
+            index.push({
+                title: room.name,
+                subtitle: room.desc,
+                category: 'ships',
+                link: '/cruise-space?section=rooms',
+                matchType: 'content'
+            });
+        });
+        // VIP Privileges
+        index.push({
+            title: cruiseSpacePage.vip.title,
+            subtitle: cruiseSpacePage.vip.desc,
+            category: 'ships',
+            link: '/cruise-space?section=vip',
+            matchType: 'title'
+        });
+        // VIP Benefits
+        cruiseSpacePage.vip.benefits?.forEach((benefit: string) => {
+            index.push({
+                title: benefit,
+                category: 'ships',
+                link: '/cruise-space?section=vip',
+                matchType: 'content'
+            });
+        });
+    }
+
+    // 8. Guide Page Content
+    const guidePage = t.guide;
+    if (guidePage) {
+        // Hero
+        index.push({
+            title: guidePage.hero.title,
+            subtitle: guidePage.hero.subtitle,
+            category: 'activity',
+            link: '/guide',
+            matchType: 'title'
+        });
+        // Travel Tips
+        index.push({
+            title: guidePage.tips.sectionSubtitle,
+            subtitle: guidePage.tips.sectionTitle,
+            category: 'activity',
+            link: '/guide?section=tips',
+            matchType: 'title'
+        });
+        // Tips Categories
+        guidePage.tips.categories?.forEach((category: any) => {
+            index.push({
+                title: category.title,
+                category: 'activity',
+                link: '/guide?section=tips',
+                matchType: 'content'
+            });
+            // Tips Items
+            category.items?.forEach((item: string) => {
+                index.push({
+                    title: item,
+                    category: 'activity',
+                    link: '/guide?section=tips',
+                    matchType: 'content'
+                });
+            });
+        });
+        // FAQ
+        index.push({
+            title: guidePage.faq.sectionSubtitle,
+            subtitle: guidePage.faq.sectionTitle,
+            category: 'activity',
+            link: '/guide?section=faq',
+            matchType: 'title'
+        });
+        // FAQ Items
+        guidePage.faq.items?.forEach((faq: any) => {
+            index.push({
+                title: faq.question,
+                subtitle: faq.answer,
+                category: 'activity',
+                link: '/guide?section=faq',
+                matchType: 'content'
+            });
+        });
+    }
+
     return index;
   }, [language, t, itineraries, ships, dining, videoSection]);
 
-  // Filter Results
+  // Generate Search Suggestions
+  const suggestions = useMemo(() => {
+    if (!query.trim() || query.length < 2 || !showSuggestions) return [];
+    const lowerQuery = query.toLowerCase();
+    
+    // Extract unique terms from search index
+    const allTerms = new Set<string>();
+    searchIndex.forEach(item => {
+      // Split title into words
+      item.title.toLowerCase().split(/\s+/).forEach(word => {
+        if (word.length > 2) allTerms.add(word);
+      });
+      // Split subtitle into words if exists
+      if (item.subtitle) {
+        item.subtitle.toLowerCase().split(/\s+/).forEach(word => {
+          if (word.length > 2) allTerms.add(word);
+        });
+      }
+    });
+    
+    // Find terms that start with or contain the query
+    const matchingTerms = Array.from(allTerms)
+      .filter(term => term.startsWith(lowerQuery))
+      .sort();
+    
+    // Limit to top 5 suggestions
+    return matchingTerms.slice(0, 5).map(term => ({
+      text: term,
+      count: searchIndex.filter(item => 
+        item.title.toLowerCase().includes(term) || 
+        (item.subtitle && item.subtitle.toLowerCase().includes(term))
+      ).length,
+      category: 'all'
+    }));
+  }, [query, searchIndex, showSuggestions]);
+
+  // Filter Results with Enhanced Matching and Grouping
   const filteredResults = useMemo(() => {
     if (!query.trim()) return [];
     const lowerQuery = query.toLowerCase();
-    return searchIndex.filter(item => 
-      item.title.toLowerCase().includes(lowerQuery) || 
-      (item.subtitle && item.subtitle.toLowerCase().includes(lowerQuery))
-    );
+    
+    // Calculate relevance score for each match
+    const resultsWithScore = searchIndex
+      .map(item => {
+        const titleLower = item.title.toLowerCase();
+        const subtitleLower = item.subtitle?.toLowerCase() || '';
+        
+        // Basic match check
+        const titleMatches = titleLower.includes(lowerQuery);
+        const subtitleMatches = subtitleLower.includes(lowerQuery);
+        
+        if (!titleMatches && !subtitleMatches) return null;
+        
+        // Calculate relevance score
+        let score = 0;
+        
+        // Title matches are more important
+        if (titleMatches) {
+          score += 10;
+          // Exact match in title gives extra points
+          if (titleLower === lowerQuery) score += 20;
+          // Start of title match gives more points
+          if (titleLower.startsWith(lowerQuery)) score += 5;
+        }
+        
+        // Subtitle matches are less important
+        if (subtitleMatches) {
+          score += 5;
+          if (subtitleLower === lowerQuery) score += 10;
+          if (subtitleLower.startsWith(lowerQuery)) score += 3;
+        }
+        
+        // Match type bonus
+        if (item.matchType === 'title') score += 3;
+        
+        // Category priority (home > itinerary > ships > dining > activity)
+        const categoryPriority = {
+          home: 5,
+          itinerary: 4,
+          ships: 3,
+          dining: 2,
+          activity: 1
+        };
+        score += categoryPriority[item.category] || 0;
+        
+        return { ...item, score };
+      })
+      .filter((item): item is typeof item & { score: number } => item !== null);
+    
+    // Sort by relevance score (descending)
+    const sortedResults = resultsWithScore.sort((a, b) => b.score - a.score);
+    
+    return sortedResults;
   }, [query, searchIndex]);
 
+  // Group results by category for better display
+  const groupedResults = useMemo(() => {
+    if (!filteredResults.length) return [];
+    
+    const categories = ['home', 'itinerary', 'ships', 'dining', 'activity'] as const;
+    const groups: { category: string; results: typeof filteredResults }[] = [];
+    
+    categories.forEach(category => {
+      const categoryResults = filteredResults.filter(item => item.category === category);
+      if (categoryResults.length > 0) {
+        groups.push({ category, results: categoryResults });
+      }
+    });
+    
+    return groups;
+  }, [filteredResults]);
+
   const handleResultClick = (link: string) => {
     onClose();
+    
     if (link.startsWith('/?section=')) {
         const sectionId = link.split('=')[1];
         navigate('/');
+        // Use a safer timeout and scroll logic
         setTimeout(() => {
-            document.getElementById(sectionId)?.scrollIntoView({ behavior: 'smooth' });
-        }, 100);
-    } else if (link.startsWith('/ships?section=')) {
-        navigate(link);
+            const element = document.getElementById(sectionId);
+            if (element) {
+                // Add some offset to account for fixed header
+                const headerOffset = 80;
+                const elementPosition = element.getBoundingClientRect().top;
+                const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
+                
+                window.scrollTo({
+                    top: offsetPosition,
+                    behavior: 'smooth'
+                });
+            }
+        }, 150);
+    } else if (link.includes('?section=')) {
+        // Handle other section links with proper scroll logic
+        const [path, queryString] = link.split('?');
+        const params = new URLSearchParams(queryString);
+        const section = params.get('section');
+        
+        navigate(path);
+        
+        if (section) {
+            setTimeout(() => {
+                const elementId = link.startsWith('/cruise-space') ? `space-${section}` : section;
+                const element = document.getElementById(elementId);
+                if (element) {
+                    const headerOffset = 80;
+                    const elementPosition = element.getBoundingClientRect().top;
+                    const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
+                    
+                    window.scrollTo({
+                        top: offsetPosition,
+                        behavior: 'smooth'
+                    });
+                }
+            }, 200);
+        }
     } else {
         navigate(link);
     }
@@ -209,41 +468,88 @@ const SearchOverlay: React.FC<SearchOverlayProps> = ({ isOpen, onClose }) => {
         {/* Results Dropdown - Floating immediately below the bar */}
         {(query.trim() !== '') && (
             <div className="absolute top-full left-0 right-0 mt-2 bg-vista-darkblue/95 backdrop-blur-xl rounded border border-white/10 max-h-[60vh] overflow-y-auto no-scrollbar shadow-2xl">
-                 {filteredResults.length > 0 ? (
-                    <div className="p-2">
-                        <div className="px-4 py-2 text-vista-gold text-[10px] font-bold uppercase tracking-widest border-b border-white/5">
-                            {searchT.results_for} "{query}"
+                {/* Search Suggestions */}
+                {suggestions.length > 0 && showSuggestions && query.length < 20 && (
+                    <div className="p-2 border-b border-white/5">
+                        <div className="px-4 py-2 text-vista-gold text-[10px] font-bold uppercase tracking-widest">
+                            Suggestions
                         </div>
-                        {filteredResults.map((result, idx) => (
+                        {suggestions.map((suggestion, idx) => (
                             <div 
                                 key={idx} 
-                                onClick={() => handleResultClick(result.link)}
+                                onClick={() => {
+                                    setQuery(suggestion.text);
+                                    setShowSuggestions(false);
+                                }}
                                 className="group flex items-center justify-between p-3 hover:bg-white/10 cursor-pointer transition-colors rounded-sm"
                             >
                                 <div className="flex items-center gap-3">
-                                    <div className="text-white/40 group-hover:text-vista-gold transition-colors">
-                                        {result.category === 'itinerary' && <Compass size={16} />}
-                                        {result.category === 'ships' && <Ship size={16} />}
-                                        {result.category === 'dining' && <Utensils size={16} />}
-                                        {result.category === 'activity' && <Film size={16} />}
-                                        {result.category === 'home' && <Anchor size={16} />}
-                                    </div>
+                                    <Search className="text-white/40 group-hover:text-vista-gold transition-colors w-4 h-4" />
                                     <div>
-                                        <h3 className="text-base font-serif text-white group-hover:text-vista-gold transition-colors">{result.title}</h3>
-                                        {result.subtitle && (
-                                            <p className="text-white/50 text-[10px] mt-0.5 line-clamp-1">{result.subtitle}</p>
-                                        )}
+                                        <h3 className="text-base font-serif text-white group-hover:text-vista-gold transition-colors">{suggestion.text}</h3>
+                                        <p className="text-white/50 text-[10px] mt-0.5">{suggestion.count} results</p>
                                     </div>
                                 </div>
-                                <ArrowRight className="text-white/20 group-hover:text-vista-gold w-3 h-3" />
                             </div>
                         ))}
+                        <button
+                            onClick={() => setShowSuggestions(false)}
+                            className="w-full px-4 py-2 text-left text-vista-gold text-[10px] font-bold uppercase tracking-widest hover:bg-white/5 transition-colors"
+                        >
+                            Show Results for "{query}"
+                        </button>
                     </div>
-                 ) : (
-                    <div className="p-6 text-center text-white/40 font-serif italic text-base">
-                        {searchT.no_results}
+                )}
+
+                {/* Search Results */}
+                {(!suggestions.length || !showSuggestions) && (
+                    <div>
+                        {filteredResults.length > 0 ? (
+                            <div className="p-2">
+                                <div className="px-4 py-2 text-vista-gold text-[10px] font-bold uppercase tracking-widest border-b border-white/5 mb-2">
+                                    {searchT.results_for} "{query}"
+                                </div>
+                                {groupedResults.map((group, groupIdx) => (
+                                    <div key={groupIdx} className="mb-4 last:mb-0">
+                                        <div className="px-4 py-2 text-white/60 text-[10px] font-bold uppercase tracking-wider border-b border-white/5 flex items-center gap-2">
+                                            {group.category === 'itinerary' && <Compass size={14} />}
+                                            {group.category === 'ships' && <Ship size={14} />}
+                                            {group.category === 'dining' && <Utensils size={14} />}
+                                            {group.category === 'activity' && <Film size={14} />}
+                                            {group.category === 'home' && <Anchor size={14} />}
+                                            {searchT.categories?.[group.category] || group.category}
+                                            <span className="text-white/30">({group.results.length})</span>
+                                        </div>
+                                        <div className="mt-2">
+                                            {group.results.map((result, resultIdx) => (
+                                                <div 
+                                                    key={resultIdx} 
+                                                    onClick={() => handleResultClick(result.link)}
+                                                    className="group flex items-center justify-between p-3 hover:bg-white/10 cursor-pointer transition-colors rounded-sm mx-2"
+                                                >
+                                                    <div className="flex items-center gap-3">
+                                                        <div className="w-1 h-1 rounded-full bg-vista-gold group-hover:scale-150 transition-transform"></div>
+                                                        <div>
+                                                            <h3 className="text-base font-serif text-white group-hover:text-vista-gold transition-colors">{result.title}</h3>
+                                                            {result.subtitle && (
+                                                                <p className="text-white/50 text-[10px] mt-0.5 line-clamp-1">{result.subtitle}</p>
+                                                            )}
+                                                        </div>
+                                                    </div>
+                                                    <ArrowRight className="text-white/20 group-hover:text-vista-gold w-3 h-3" />
+                                                </div>
+                                            ))}
+                                        </div>
+                                    </div>
+                                ))}
+                            </div>
+                        ) : (
+                            <div className="p-6 text-center text-white/40 font-serif italic text-base">
+                                {searchT.no_results}
+                            </div>
+                        )}
                     </div>
-                 )}
+                )}
             </div>
         )}
       </div>

+ 4 - 27
src/components/Sidebar.tsx

@@ -1,6 +1,5 @@
-import React, { useState } from 'react';
-import { Phone, ArrowUp, Settings } from 'lucide-react';
-import ThemeSettings from './ThemeSettings.tsx';
+import React from 'react';
+import { Phone, ArrowUp } from 'lucide-react';
 import MiniProgramQRCode from '@/src/assets/QRPicture/wechat-QR.png';
 import TiktokQRCode from '@/src/assets/QRPicture/Tiktok-QR.png';
 import RedBookQRCode from '@/src/assets/QRPicture/redbook-QR.png';
@@ -9,7 +8,6 @@ import TiktokIcon from '@/src/assets/logo/tiktok.png';
 import RedBook from '@/src/assets/logo/redbook.png';
 
 const Sidebar: React.FC = () => {
-  const [settingsOpen, setSettingsOpen] = useState(false);
 
   const scrollToTop = () => {
     window.scrollTo({ top: 0, behavior: 'smooth' });
@@ -38,7 +36,6 @@ const Sidebar: React.FC = () => {
                   src={MiniProgramQRCode as string}  // 替换为你的图片路径
                   alt="公众号二维码"
                   className="w-24 h-24 object-cover rounded"
-                  loading="lazy"
               />
             </div>
 
@@ -49,7 +46,6 @@ const Sidebar: React.FC = () => {
               src={WeChatIcon as string}
               alt="微信"
               className="w-5 h-5 object-contain"
-              loading="lazy"
             />
           </button>
         </div>
@@ -64,7 +60,6 @@ const Sidebar: React.FC = () => {
                   src={RedBookQRCode as string}  // 替换为你的图片路径
                   alt="公众号二维码"
                   className="w-24 h-24 object-cover rounded"
-                  loading="lazy"
               />
             </div>
 
@@ -75,7 +70,6 @@ const Sidebar: React.FC = () => {
               src={RedBook as string}
               alt="小红书"
               className="w-8 h-8 object-contain"
-              loading="lazy"
             />
           </button>
         </div>
@@ -90,7 +84,6 @@ const Sidebar: React.FC = () => {
                   src={TiktokQRCode as string}  // 替换为你的图片路径
                   alt="公众号二维码"
                   className="w-24 h-24 object-cover rounded"
-                  loading="lazy"
               />
             </div>
           </div>
@@ -100,27 +93,12 @@ const Sidebar: React.FC = () => {
                 src={TiktokIcon as string}
                 alt="抖音"
                 className="w-8 h-8 object-contain"
-                loading="lazy"
             />
           </button>
         </div>
 
 
-        {/* Customization Settings Trigger (New) */}
-        <div className="group relative flex items-center">
-           <div className="absolute right-12 bg-vista-darkblue text-white text-xs px-3 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none">
-            自定义设置
-          </div>
-          <button
-            onClick={() => setSettingsOpen(true)}
-            className="w-12 h-12 bg-white rounded-full shadow-lg flex items-center justify-center text-vista-darkblue hover:bg-vista-gold hover:text-white transition-colors border border-vista-darkblue/10"
-            type="button"
-            aria-label="Customization settings"
-            aria-expanded={settingsOpen}
-          >
-            <Settings size={20} />
-          </button>
-        </div>
+
 
         {/* Back to Top */}
         <button
@@ -133,8 +111,7 @@ const Sidebar: React.FC = () => {
         </button>
       </div>
 
-      {/* Settings Modal */}
-      <ThemeSettings isOpen={settingsOpen} onClose={() => setSettingsOpen(false)} />
+
     </>
   );
 };

+ 173 - 0
src/constants.ts

@@ -463,6 +463,123 @@ export const CONTENT = {
           { day: 7, title: "南京", description: "中山陵,夫子庙" },
           { day: 8, title: "上海离船", description: "外滩,豫园,离船" }
         ]
+      },
+      {
+        id: "4",
+        title: "三峡深度体验之旅",
+        days: 5,
+        price: "¥5,299 起",
+        image: "https://picsum.photos/600/400?random=13",
+        route: "重庆 - 宜昌",
+        description: "深度探索三峡的自然景观和人文历史,增加更多岸上活动和特色体验。",
+        highlights: ["三峡大坝内部参观", "神女溪徒步探险", "夔门日出摄影", "三峡民间艺术表演"],
+        itinerary: [
+          { day: 1, title: "重庆登船", description: "下午登船,欢迎晚宴,船上文化讲座" },
+          { day: 2, title: "丰都鬼城", description: "游览丰都鬼城,了解长江文化" },
+          { day: 3, title: "瞿塘峡", description: "白帝城,夔门,巫峡,神女峰" },
+          { day: 4, title: "西陵峡", description: "神女溪徒步,三峡大坝内部参观,升船机体验" },
+          { day: 5, title: "宜昌离船", description: "早餐后离船,行程结束" }
+        ]
+      },
+      {
+        id: "5",
+        title: "长江中下游之旅",
+        days: 4,
+        price: "¥3,699 起",
+        image: "https://picsum.photos/600/400?random=14",
+        route: "武汉 - 上海",
+        description: "游览长江中下游的重要城市和景点,感受江南水乡的独特魅力。",
+        highlights: ["武汉黄鹤楼", "南京中山陵", "苏州园林", "上海外滩夜景"],
+        itinerary: [
+          { day: 1, title: "武汉登船", description: "下午登船,欢迎晚宴,游轮启航" },
+          { day: 2, title: "南京", description: "中山陵,夫子庙,秦淮河" },
+          { day: 3, title: "苏州", description: "拙政园,狮子林,平江路" },
+          { day: 4, title: "上海离船", description: "外滩,豫园,东方明珠塔" }
+        ]
+      },
+      {
+        id: "6",
+        title: "三峡大坝专项之旅",
+        days: 3,
+        price: "¥2,899 起",
+        image: "https://picsum.photos/600/400?random=15",
+        route: "宜昌 - 重庆",
+        description: "专注于三峡大坝工程的参观和学习,了解这一世界奇迹的建设历程和运行原理。",
+        highlights: ["三峡大坝全景参观", "大坝内部结构讲解", "升船机全程体验", "三峡工程博物馆"],
+        itinerary: [
+          { day: 1, title: "宜昌登船", description: "下午登船,欢迎仪式,游轮启航" },
+          { day: 2, title: "三峡大坝", description: "大坝全景,内部参观,升船机体验,工程博物馆" },
+          { day: 3, title: "重庆离船", description: "早餐后离船,行程结束" }
+        ]
+      },
+      {
+        id: "7",
+        title: "长江三峡全景之旅",
+        days: 6,
+        price: "¥5,999 起",
+        image: "https://picsum.photos/600/400?random=16",
+        route: "重庆 - 武汉",
+        description: "全景式游览长江三峡,从重庆出发,经三峡到达武汉,深度体验长江文化和自然景观。",
+        highlights: ["三峡全景游览", "武汉黄鹤楼", "长江大桥", "船上文化活动"],
+        itinerary: [
+          { day: 1, title: "重庆登船", description: "下午登船,欢迎晚宴,游轮启航" },
+          { day: 2, title: "丰都鬼城", description: "游览丰都鬼城,了解长江文化" },
+          { day: 3, title: "瞿塘峡", description: "白帝城,夔门,巫峡,神女峰" },
+          { day: 4, title: "西陵峡", description: "神女溪,三峡大坝,升船机体验" },
+          { day: 5, title: "荆州古城", description: "游览荆州古城,了解三国历史" },
+          { day: 6, title: "武汉离船", description: "早餐后离船,行程结束" }
+        ]
+      },
+      {
+        id: "8",
+        title: "三峡亲子之旅",
+        days: 4,
+        price: "¥4,299 起",
+        image: "https://picsum.photos/600/400?random=17",
+        route: "重庆 - 宜昌",
+        description: "专为家庭设计的三峡之旅,包含亲子互动活动和教育体验,让孩子在游玩中学习长江文化。",
+        highlights: ["亲子互动活动", "三峡大坝科普教育", "神女溪游船", "船上儿童俱乐部"],
+        itinerary: [
+          { day: 1, title: "重庆登船", description: "下午登船,欢迎晚宴,亲子破冰活动" },
+          { day: 2, title: "丰都鬼城", description: "游览丰都鬼城,了解长江文化,亲子互动游戏" },
+          { day: 3, title: "瞿塘峡", description: "白帝城,夔门,巫峡,亲子摄影比赛" },
+          { day: 4, title: "西陵峡", description: "神女溪,三峡大坝科普教育,升船机体验" }
+        ]
+      },
+      {
+        id: "9",
+        title: "长江夜景之旅",
+        days: 5,
+        price: "¥4,799 起",
+        image: "https://picsum.photos/600/400?random=18",
+        route: "重庆 - 宜昌",
+        description: "欣赏长江两岸的美丽夜景,体验长江夜游的独特魅力,包含多个城市的夜景游览。",
+        highlights: ["重庆夜景", "万州夜景", "宜昌夜景", "船上夜间表演"],
+        itinerary: [
+          { day: 1, title: "重庆登船", description: "下午登船,欢迎晚宴,重庆夜景游览" },
+          { day: 2, title: "万州夜景", description: "白天游览白帝城,晚上欣赏万州夜景" },
+          { day: 3, title: "巫峡夜景", description: "白天游览巫峡,晚上欣赏巫峡夜景" },
+          { day: 4, title: "宜昌夜景", description: "白天游览三峡大坝,晚上欣赏宜昌夜景" },
+          { day: 5, title: "宜昌离船", description: "早餐后离船,行程结束" }
+        ]
+      },
+      {
+        id: "10",
+        title: "三峡摄影之旅",
+        days: 6,
+        price: "¥5,499 起",
+        image: "https://picsum.photos/600/400?random=19",
+        route: "重庆 - 宜昌",
+        description: "专为摄影爱好者设计的三峡之旅,包含专业摄影指导和最佳摄影地点推荐,捕捉三峡的美丽瞬间。",
+        highlights: ["夔门日出", "巫峡云海", "三峡大坝日落", "专业摄影指导"],
+        itinerary: [
+          { day: 1, title: "重庆登船", description: "下午登船,欢迎晚宴,摄影准备会" },
+          { day: 2, title: "丰都鬼城", description: "游览丰都鬼城,摄影指导" },
+          { day: 3, title: "瞿塘峡日出", description: "早上升船拍摄夔门日出,白天游览白帝城" },
+          { day: 4, title: "巫峡云海", description: "拍摄巫峡云海,神女峰" },
+          { day: 5, title: "三峡大坝日落", description: "下午拍摄三峡大坝日落,升船机体验" },
+          { day: 6, title: "宜昌离船", description: "早餐后离船,摄影作品点评" }
+        ]
       }
     ],
     features: [
@@ -899,6 +1016,62 @@ export const CONTENT = {
         price: "¥8,888",
         image: "https://picsum.photos/600/400?random=12",
         route: "Chongqing - Shanghai"
+      },
+      {
+        id: "4",
+        title: "Three Gorges Deep Experience",
+        days: 5,
+        price: "¥5,299",
+        image: "https://picsum.photos/600/400?random=13",
+        route: "Chongqing - Yichang"
+      },
+      {
+        id: "5",
+        title: "Yangtze Middle and Lower Reaches",
+        days: 4,
+        price: "¥3,699",
+        image: "https://picsum.photos/600/400?random=14",
+        route: "Wuhan - Shanghai"
+      },
+      {
+        id: "6",
+        title: "Three Gorges Dam Special Tour",
+        days: 3,
+        price: "¥2,899",
+        image: "https://picsum.photos/600/400?random=15",
+        route: "Yichang - Chongqing"
+      },
+      {
+        id: "7",
+        title: "Yangtze Three Gorges Panoramic Tour",
+        days: 6,
+        price: "¥5,999",
+        image: "https://picsum.photos/600/400?random=16",
+        route: "Chongqing - Wuhan"
+      },
+      {
+        id: "8",
+        title: "Three Gorges Family Tour",
+        days: 4,
+        price: "¥4,299",
+        image: "https://picsum.photos/600/400?random=17",
+        route: "Chongqing - Yichang"
+      },
+      {
+        id: "9",
+        title: "Yangtze Night View Tour",
+        days: 5,
+        price: "¥4,799",
+        image: "https://picsum.photos/600/400?random=18",
+        route: "Chongqing - Yichang"
+      },
+      {
+        id: "10",
+        title: "Three Gorges Photography Tour",
+        days: 6,
+        price: "¥5,499",
+        image: "https://picsum.photos/600/400?random=19",
+        route: "Chongqing - Yichang"
       }
     ],
     features: [

+ 28 - 0
src/contexts/ThemeContext.tsx

@@ -45,6 +45,34 @@ const DEFAULT_ITINERARIES: Itinerary[] = [
   {
     ...CONTENT.zh.itineraries[2],
     video: "https://videos.pexels.com/video-files/2927233/2927233-uhd_2560_1440_24fps.mp4"
+  },
+  {
+    ...CONTENT.zh.itineraries[3],
+    video: "https://videos.pexels.com/video-files/3252327/3252327-uhd_2560_1440_25fps.mp4" 
+  },
+  {
+    ...CONTENT.zh.itineraries[4],
+    video: "https://videos.pexels.com/video-files/5049352/5049352-uhd_2560_1440_30fps.mp4"
+  },
+  {
+    ...CONTENT.zh.itineraries[5],
+    video: "https://videos.pexels.com/video-files/2927233/2927233-uhd_2560_1440_24fps.mp4"
+  },
+  {
+    ...CONTENT.zh.itineraries[6],
+    video: "https://videos.pexels.com/video-files/3252327/3252327-uhd_2560_1440_25fps.mp4" 
+  },
+  {
+    ...CONTENT.zh.itineraries[7],
+    video: "https://videos.pexels.com/video-files/5049352/5049352-uhd_2560_1440_30fps.mp4"
+  },
+  {
+    ...CONTENT.zh.itineraries[8],
+    video: "https://videos.pexels.com/video-files/2927233/2927233-uhd_2560_1440_24fps.mp4"
+  },
+  {
+    ...CONTENT.zh.itineraries[9],
+    video: "https://videos.pexels.com/video-files/3252327/3252327-uhd_2560_1440_25fps.mp4" 
   }
 ];
 

+ 1 - 5
src/pages/AboutUs.tsx

@@ -111,8 +111,7 @@ const AboutUs: React.FC = () => {
           <img 
             src={aboutHeroImage || "https://images.unsplash.com/photo-1578474843222-9593bc88d8b0?q=80&w=1920&auto=format&fit=crop"} 
             alt="About Us" 
-            className="w-full h-full object-cover object-center" 
-            loading="lazy"
+            className="w-full h-full object-cover object-center"
           />
           <div className="absolute inset-0 bg-black/40 pointer-events-none"></div>
         </div>
@@ -134,7 +133,6 @@ const AboutUs: React.FC = () => {
                     src={ CompanyLogo || "https://images.unsplash.com/photo-1599640845513-2627a35c602a?q=80&w=1920&auto=format&fit=crop"}
                   alt="Company" 
                   className="w-full h-auto rounded-lg shadow-xl"
-                  loading="lazy"
                 />
                 <div className="absolute -bottom-6 -right-6 bg-vista-gold text-white p-6 rounded-lg shadow-lg">
                   <span className="text-3xl font-serif">10+</span>
@@ -187,7 +185,6 @@ const AboutUs: React.FC = () => {
                       src={media.icon} 
                       alt={media.name} 
                       className="w-8 h-8 object-contain"
-                      loading="lazy"
                     />
                   </div>
                   <h3 className="text-xl font-serif text-vista-darkblue mb-2">
@@ -236,7 +233,6 @@ const AboutUs: React.FC = () => {
                   src={selectedMedia.qrCode as string} 
                   alt={`${language === 'zh' ? selectedMedia.name : selectedMedia.nameEn} QR Code`} 
                   className="w-64 h-64 object-contain border border-vista-gold/30 p-4"
-                  loading="lazy"
                 />
               </div>
             </div>

+ 0 - 1
src/pages/CruiseSpace.tsx

@@ -58,7 +58,6 @@ const CruiseSpace: React.FC = () => {
                     src="https://images.unsplash.com/photo-1548291616-3c0f5f743538?q=80&w=1920&auto=format&fit=crop"
                     alt="Ships Hero"
                     className="absolute inset-0 w-full h-full object-cover animate-slow-zoom"
-                    loading="lazy"
                 />
                 <div className="relative z-20 text-center text-white px-4 animate-fade-in-up">
                     <span className="block text-sm md:text-base tracking-[0.3em] uppercase mb-4 text-vista-gold">{t.hero_sub}</span>

+ 0 - 1
src/pages/Guide.tsx

@@ -46,7 +46,6 @@ const Guide: React.FC = () => {
             src={guideHeroImage || "https://images.unsplash.com/photo-1578474843222-9593bc88d8b0?q=80&w=1920&auto=format&fit=crop"} 
             alt="Travel Guide" 
             className="w-full h-full object-cover object-center" 
-            loading="lazy"
             onError={(e) => {
               const target = e.target as HTMLImageElement;
               target.src = "https://images.unsplash.com/photo-1578474843222-9593bc88d8b0?q=80&w=1920&auto=format&fit=crop";

+ 111 - 11
src/pages/Home.tsx

@@ -4,12 +4,14 @@ import Navbar from '@/src/components/Navbar.tsx';
 import Sidebar from '@/src/components/Sidebar.tsx';
 import Footer from '@/src/components/Footer.tsx';
 import { CONTENT, HERO_IMAGES } from '../constants.ts';
-import { ChevronRight, Play } from 'lucide-react';
+import { ChevronRight, Play, X, MapPin, Calendar, DollarSign } from 'lucide-react';
 import { useLanguage } from '@/src/contexts/LanguageContext.tsx';
 import { useTheme } from '@/src/contexts/ThemeContext.tsx';
+import { Itinerary } from '../types.ts';
 
 const Home: React.FC = () => {
   const [activeSlide, setActiveSlide] = useState(0);
+  const [selectedItinerary, setSelectedItinerary] = useState<Itinerary | null>(null);
   const { language } = useLanguage();
   // Fetch all customizable data from ThemeContext
   const { heroImages, itineraries, ships, dining, videoSection } = useTheme();
@@ -45,8 +47,7 @@ const Home: React.FC = () => {
             <img 
               src={img} 
               alt={`Slide ${index + 1}`} 
-              className="w-full h-full object-cover object-center scale-105 animate-slow-zoom" 
-              loading="lazy"
+              className="w-full h-full object-cover object-center scale-105 animate-slow-zoom"
               onError={(e) => {
                 // Fallback to default image if API image fails to load
                 const target = e.target as HTMLImageElement;
@@ -111,7 +112,7 @@ const Home: React.FC = () => {
 
             <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
                 {itineraries.map((item) => (
-                    <div key={item.id} className="group bg-white border border-gray-100 shadow-sm hover:shadow-xl transition-all duration-300 cursor-pointer">
+                    <div key={item.id} className="group bg-white border border-gray-100 shadow-sm hover:shadow-xl transition-all duration-300 cursor-pointer" onClick={() => setSelectedItinerary(item)}>
                         {/* Media Container: Renders Video if available, else Image */}
                         <div className="relative overflow-hidden h-64">
                             {item.video ? (
@@ -123,14 +124,12 @@ const Home: React.FC = () => {
                                 muted
                                 loop
                                 playsInline
-                                loading="lazy"
                               />
                             ) : (
                               <img 
                                 src={item.image} 
                                 alt={item.title} 
-                                className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700" 
-                                loading="lazy"
+                                className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700"
                               />
                             )}
                             <div className="absolute top-4 left-4 bg-white px-3 py-1 text-xs font-bold tracking-widest uppercase z-10 text-vista-darkblue">
@@ -154,7 +153,7 @@ const Home: React.FC = () => {
       {/* Banner / Activity Highlight (Customizable Dining) */}
       <section className="relative py-32 flex items-center justify-center">
          <div className="absolute inset-0 z-0">
-             <img src={dining.image} alt="Dining" className="w-full h-full object-cover brightness-50" loading="lazy" />
+             <img src={dining.image} alt="Dining" className="w-full h-full object-cover brightness-50" />
          </div>
          <div className="relative z-10 text-center max-w-4xl px-6">
              <h2 className="text-4xl md:text-5xl font-serif text-white italic mb-6">{dining.title}</h2>
@@ -180,7 +179,7 @@ const Home: React.FC = () => {
                     <div key={ship.id} className="min-w-[85vw] md:min-w-[600px] relative group cursor-pointer overflow-hidden">
                         <div className="aspect-[16/9] overflow-hidden">
                             {/* Removed grayscale, added scale transform */}
-                            <img src={ship.image} alt={ship.name} className="w-full h-full object-cover transition-transform duration-1000 ease-out group-hover:scale-105" loading="lazy" />
+                            <img src={ship.image} alt={ship.name} className="w-full h-full object-cover transition-transform duration-1000 ease-out group-hover:scale-105" />
                         </div>
                         <div className="absolute bottom-0 left-0 bg-white p-6 md:p-8 max-w-md shadow-lg transform translate-y-4 group-hover:translate-y-0 transition-transform duration-500">
                             <h3 className="text-3xl font-serif text-vista-darkblue mb-2">{ship.name}</h3>
@@ -225,11 +224,10 @@ const Home: React.FC = () => {
                               className="w-full h-full object-cover" 
                               controls 
                               poster={videoSection.thumbnail}
-                              loading="lazy"
                           />
                       ) : (
                           <>  
-                              <img src={videoSection.thumbnail} className="w-full h-full object-cover opacity-60 group-hover:opacity-40 transition-opacity" alt="Video Thumbnail" loading="lazy" />
+                              <img src={videoSection.thumbnail} className="w-full h-full object-cover opacity-60 group-hover:opacity-40 transition-opacity" alt="Video Thumbnail" />
                               <div className="absolute inset-0 flex items-center justify-center">
                                   <div className="w-20 h-20 rounded-full border border-white flex items-center justify-center group-hover:bg-white group-hover:text-vista-darkblue transition-all duration-300">
                                       <Play size={32} fill="currentColor" />
@@ -242,6 +240,108 @@ const Home: React.FC = () => {
           </div>
       </section>
 
+      {/* Itinerary Details Modal */}
+      {selectedItinerary && (
+        <div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4 overflow-y-auto">
+          <div className="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto transform transition-all duration-500 ease-out scale-100 opacity-100">
+            <div className="relative h-80 overflow-hidden">
+              <img 
+                src={selectedItinerary.image} 
+                alt={selectedItinerary.title} 
+                className="w-full h-full object-cover transition-transform duration-500 hover:scale-105"
+              />
+              <button 
+                className="absolute top-4 right-4 bg-white/90 backdrop-blur-sm rounded-full p-3 hover:bg-white transition-all duration-300 shadow-lg hover:shadow-xl"
+                onClick={() => setSelectedItinerary(null)}
+              >
+                <X size={24} className="text-vista-darkblue" />
+              </button>
+              <div className="absolute top-4 left-4 bg-white/95 backdrop-blur-sm px-4 py-2 rounded-full text-xs font-bold tracking-widest uppercase z-10 text-vista-darkblue shadow-sm">
+                {selectedItinerary.days} {t.home.days}
+              </div>
+            </div>
+            
+            <div className="p-8">
+              <div className="flex flex-col md:flex-row md:items-center justify-between mb-8">
+                <div>
+                  <h2 className="text-3xl md:text-4xl font-serif text-vista-darkblue mb-2 leading-tight">{selectedItinerary.title}</h2>
+                  <div className="flex items-center text-xs text-vista-darkblue/50 uppercase tracking-widest">
+                    <MapPin size={14} className="mr-1" />
+                    {selectedItinerary.route}
+                  </div>
+                </div>
+                <div className="mt-4 md:mt-0 flex items-center gap-8">
+                  <div className="flex items-center gap-2">
+                    <Calendar size={20} className="text-vista-gold" />
+                    <span className="text-vista-darkblue font-bold">{selectedItinerary.days}天{selectedItinerary.days - 1}晚</span>
+                  </div>
+                  <div className="flex items-center gap-2">
+                    <DollarSign size={20} className="text-vista-gold" />
+                    <span className="text-vista-gold font-serif italic text-2xl">{selectedItinerary.price}</span>
+                  </div>
+                </div>
+              </div>
+              
+              <div className="space-y-10">
+                <div>
+                  <h3 className="text-xl font-serif text-vista-darkblue mb-5 uppercase tracking-wider">{t.features[2].title}</h3>
+                  <p className="text-vista-darkblue/80 leading-relaxed text-lg">
+                    {selectedItinerary.description}
+                  </p>
+                </div>
+                
+                <div>
+                  <h3 className="text-xl font-serif text-vista-darkblue mb-5 uppercase tracking-wider">行程亮点</h3>
+                  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+                    {selectedItinerary.highlights.map((highlight: string, index: number) => (
+                      <div key={index} className="flex items-start gap-3 p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
+                        <div className="w-3 h-3 bg-vista-gold rounded-full mt-2 flex-shrink-0"></div>
+                        <span className="text-vista-darkblue/80 leading-relaxed">{highlight}</span>
+                      </div>
+                    ))}
+                  </div>
+                </div>
+                
+                <div>
+                  <h3 className="text-xl font-serif text-vista-darkblue mb-5 uppercase tracking-wider">每日行程</h3>
+                  <div className="relative space-y-12">
+                    {/* Timeline line */}
+                    <div className="absolute left-1/2 transform -translate-x-1/2 w-1 bg-vista-gold/20 h-full"></div>
+                    
+                    {selectedItinerary.itinerary.map((day: any, index: number) => (
+                      <div key={index} className={`relative flex ${index % 2 === 0 ? 'md:flex-row' : 'md:flex-row-reverse'} items-center gap-8`}>
+                        {/* Timeline dot */}
+                        <div className="absolute left-1/2 transform -translate-x-1/2 w-6 h-6 rounded-full bg-vista-gold border-4 border-white shadow-lg z-10 flex items-center justify-center">
+                          <span className="text-white text-xs font-bold">{day.day}</span>
+                        </div>
+                        
+                        {/* Content card */}
+                        <div className="w-full md:w-5/12 bg-white border border-gray-100 rounded-lg p-6 shadow-md hover:shadow-xl transition-all duration-300">
+                          <div className="flex items-center justify-between mb-3">
+                            <h4 className="text-lg font-bold text-vista-darkblue">{day.title}</h4>
+                            <span className="text-xs font-bold text-vista-gold uppercase tracking-wider">第 {day.day} 天</span>
+                          </div>
+                          <p className="text-vista-darkblue/80 leading-relaxed">{day.description}</p>
+                        </div>
+                        
+                        {/* Empty space for alternating layout */}
+                        <div className="hidden md:block w-5/12"></div>
+                      </div>
+                    ))}
+                  </div>
+                </div>
+              </div>
+              
+              <div className="mt-12 flex justify-center">
+                <button className="px-12 py-5 bg-vista-gold text-white font-bold tracking-widest uppercase text-sm hover:bg-vista-darkblue transition-all duration-300 shadow-lg hover:shadow-xl transform hover:-translate-y-1">
+                  {t.nav.book}
+                </button>
+              </div>
+            </div>
+          </div>
+        </div>
+      )}
+
       <Footer />
     </div>
   );

+ 1 - 4
src/pages/Itineraries.tsx

@@ -180,14 +180,12 @@ const Itineraries: React.FC = () => {
                       muted
                       loop
                       playsInline
-                      loading="lazy"
                     />
                   ) : (
                     <img 
                       src={item.image} 
                       alt={item.title} 
-                      className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700" 
-                      loading="lazy"
+                      className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700"
                     />
                   )}
                   <div className="absolute top-4 left-4 bg-white/95 backdrop-blur-sm px-4 py-2 rounded-full text-xs font-bold tracking-widest uppercase z-10 text-vista-darkblue shadow-sm">
@@ -374,7 +372,6 @@ const Itineraries: React.FC = () => {
                 src={selectedItinerary.image} 
                 alt={selectedItinerary.title} 
                 className="w-full h-full object-cover transition-transform duration-500 hover:scale-105"
-                loading="lazy"
               />
               <button 
                 className="absolute top-4 right-4 bg-white/90 backdrop-blur-sm rounded-full p-3 hover:bg-white transition-all duration-300 shadow-lg hover:shadow-xl"

+ 0 - 8
src/pages/Ships.tsx

@@ -48,7 +48,6 @@ const Ships: React.FC = () => {
                     src="https://images.unsplash.com/photo-1548291616-3c0f5f743538?q=80&w=1920&auto=format&fit=crop"
                     alt="Ships Hero"
                     className="absolute inset-0 w-full h-full object-cover animate-slow-zoom"
-                    loading="lazy"
                 />
                 <div className="relative z-20 text-center text-white px-4 animate-fade-in-up">
                     <span className="block text-sm md:text-base tracking-[0.3em] uppercase mb-4 text-vista-gold">{t.hero_sub}</span>
@@ -96,7 +95,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.lanyue[0]}
                                 alt="Lanyue"
                                 className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
-                                loading="lazy"
                             />
                             <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-90 transition-opacity"></div>
                             <div className="absolute bottom-8 left-8 text-white">
@@ -112,7 +110,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.aurora}
                                 alt="Aurora"
                                 className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110 grayscale group-hover:grayscale-0"
-                                loading="lazy"
                             />
                             <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-90 transition-opacity"></div>
                             <div className="absolute bottom-8 left-8 text-white">
@@ -170,7 +167,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.lanyue[0]}
                                 alt="Lanyue Exterior"
                                 className="w-full h-full object-cover transition-transform duration-1000 group-hover:scale-105"
-                                loading="lazy"
                             />
                         </div>
                         {/* Smaller Detail Images */}
@@ -179,7 +175,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.lanyue[1]}
                                 alt="Lanyue Interior"
                                 className="w-full h-full object-cover transition-transform duration-1000 group-hover:scale-105"
-                                loading="lazy"
                             />
                         </div>
                         <div className="lg:col-span-4 lg:row-span-1 relative group overflow-hidden shadow-lg">
@@ -187,7 +182,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.lanyue[2]}
                                 alt="Lanyue Deck"
                                 className="w-full h-full object-cover transition-transform duration-1000 group-hover:scale-105"
-                                loading="lazy"
                             />
                         </div>
                         <div className="lg:col-span-12 lg:row-span-1 relative group overflow-hidden shadow-lg md:hidden lg:block">
@@ -195,7 +189,6 @@ const Ships: React.FC = () => {
                                 src={shipsPageImages.lanyue[3]}
                                 alt="Lanyue Wide"
                                 className="w-full h-full object-cover transition-transform duration-1000 group-hover:scale-105"
-                                loading="lazy"
                             />
                         </div>
                     </div>
@@ -215,7 +208,6 @@ const Ships: React.FC = () => {
                         src={shipsPageImages.aurora}
                         alt="Aurora"
                         className="w-full h-full object-cover animate-slow-zoom"
-                        loading="lazy"
                     />
                     <div className="absolute inset-0 bg-gradient-to-b from-black via-transparent to-black"></div>
                 </div>