feat: complete Changan digital manuals web application with mobile layout fix
This commit is contained in:
+1099
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,369 @@
|
||||
/**
|
||||
* CHANGAN DIGITAL MANUALS — HOME PORTAL APPLICATION
|
||||
* Manages vehicle catalog, first-visit language modal, and trilingual localization
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Supported Languages
|
||||
const SUPPORTED_LANGS = ['en', 'fa', 'zh'];
|
||||
|
||||
// Localization Dictionary for Home Portal
|
||||
const HOME_I18N = {
|
||||
en: {
|
||||
brandSub: "Official Digital Vehicle Manuals",
|
||||
heroBadge: "🚘 Official Digital Driver's Guides",
|
||||
heroHeading: "Select Your Changan Model",
|
||||
heroDesc: "Browse official interactive owner manuals, control stalks, warning lamp indicators, and maintenance specifications.",
|
||||
catalogTitle: "Available Vehicle Models",
|
||||
activeModelBadge: "Active Manual",
|
||||
upcomingBadge: "Coming Soon",
|
||||
openManualBtn: "Open Owner's Manual →",
|
||||
comingSoonBtn: "Coming Soon",
|
||||
// Features
|
||||
featuresHeading: "Why Changan Digital Manuals?",
|
||||
feat1Title: "Interactive Switches",
|
||||
feat1Desc: "Interactive 3D diagrams of steering wheel stalks, smart key fobs, and climate panels.",
|
||||
feat2Title: "Warning Lamp Guide",
|
||||
feat2Desc: "34 dashboard indicators with full diagnostic troubleshooting steps.",
|
||||
feat3Title: "Scoped Search Engine",
|
||||
feat3Desc: "Fast full-text search filtered specifically to your selected vehicle model.",
|
||||
feat4Title: "100% Offline & Trilingual",
|
||||
feat4Desc: "Supports English, Persian with fluent RTL, and original Chinese with all images.",
|
||||
// Footer
|
||||
footerCopy: "© Chongqing Changan Automobile Co., Ltd. All rights reserved.",
|
||||
footerHotline: "Customer Service Hotline: 951999"
|
||||
},
|
||||
fa: {
|
||||
brandSub: "سامانه رسمی راهنمای دیجیتال خودروهای چانگان",
|
||||
heroBadge: "🚘 راهنمای رسمی و تعاملی خودروهای چانگان",
|
||||
heroHeading: "مدل خودروی خود را انتخاب کنید",
|
||||
heroDesc: "راهنمای جامع کاربری، کلیدها و ادوات کنترلی، دانشنامه چراغهای هشدار و جدول سرویسهای دورهای خودروی خود را مشاهده فرمایید.",
|
||||
catalogTitle: "مدلهای موجود و در دسترس",
|
||||
activeModelBadge: "راهنمای فعال",
|
||||
upcomingBadge: "بهزودی",
|
||||
openManualBtn: "مشاهده کتابچه راهنما ←",
|
||||
comingSoonBtn: "بهزودی عرضه میشود",
|
||||
// Features
|
||||
featuresHeading: "ویژگیهای راهنمای دیجیتال چانگان",
|
||||
feat1Title: "کلیدهای تعاملی و ادوات کابین",
|
||||
feat1Desc: "بررسی تعاملی ریموت هوشمند، شیفتر دنده ستونی، کلیدهای فرمان و پنل تهویه مطبوع.",
|
||||
feat2Title: "دانشنامه چراغهای هشدار",
|
||||
feat2Desc: "تفسیر کامل ۳۴ چراغ اخطار صفحه کیلومتر همراه با اقدامات فوری و پیشگیرانه راننده.",
|
||||
feat3Title: "موتور جستجوی اختصاصی خودرو",
|
||||
feat3Desc: "جستجوی فوقالعاده سریع و عمیق، محدود و اختصاصی به مدل خودروی انتخابشده.",
|
||||
feat4Title: "سهزبانه و کاملاً آفلاین",
|
||||
feat4Desc: "پشتیبانی کامل از زبان فارسی با چیدمان اصیل راستبهچپ (RTL)، انگلیسی و چینی همراه با تمام تصاویر.",
|
||||
// Footer
|
||||
footerCopy: "© شرکت خودروسازی چانگان چونگکینگ. تمامی حقوق محفوظ است.",
|
||||
footerHotline: "مرکز پاسخگویی مشتریان چانگان: ۹۵۱۹۹۹"
|
||||
},
|
||||
zh: {
|
||||
brandSub: "长安汽车官方数字化车主手册平台",
|
||||
heroBadge: "🚘 官方数字化互动驾驶指南",
|
||||
heroHeading: "请选择您的车型",
|
||||
heroDesc: "便捷查阅官方互动车主手册、拨杆与控制按键、仪表盘指示灯详解及车辆保养技术规范。",
|
||||
catalogTitle: "在售与即将上线车型",
|
||||
activeModelBadge: "手册已上线",
|
||||
upcomingBadge: "敬请期待",
|
||||
openManualBtn: "进入车主手册 →",
|
||||
comingSoonBtn: "即将上线",
|
||||
// Features
|
||||
featuresHeading: "长安数字化手册亮点",
|
||||
feat1Title: "全车按键互动指南",
|
||||
feat1Desc: "方向盘怀挡、无线遥控钥匙、多功能按键及空调面板的高清互动图解。",
|
||||
feat2Title: "仪表警报灯全百科",
|
||||
feat2Desc: "34项仪表指示灯与警告灯权威解读及应急处理指引。",
|
||||
feat3Title: "专属车型检索系统",
|
||||
feat3Desc: "极速精准搜索,内容深度聚焦于当前所选车型的专属知识库。",
|
||||
feat4Title: "全离线与多语言支持",
|
||||
feat4Desc: "完整支持中文、英语及波斯语(RTL),包含所有离线高清图表。",
|
||||
// Footer
|
||||
footerCopy: "© 重庆长安汽车股份有限公司 版权所有",
|
||||
footerHotline: "长安汽车客户服务热线:951999"
|
||||
}
|
||||
};
|
||||
|
||||
// Vehicles Catalog Data
|
||||
const VEHICLES = [
|
||||
{
|
||||
id: "cs55plus",
|
||||
code: "CAOM725311",
|
||||
active: true,
|
||||
image: "assets/images/ui/cs55plus_car_card.jpg",
|
||||
manualUrl: "manual.html?car=cs55plus",
|
||||
names: {
|
||||
en: "Changan CS55 PLUS",
|
||||
fa: "چانگان CS55 پلاس",
|
||||
zh: "长安第四代 CS55 PLUS"
|
||||
},
|
||||
generation: {
|
||||
en: "4th Generation • Compact SUV",
|
||||
fa: "نسل چهارم • کراساوور هوشمند",
|
||||
zh: "第四代 • 智电智能紧凑型SUV"
|
||||
},
|
||||
specs: [
|
||||
{ en: "1.5T BlueCore Direct Injection", fa: "پیشرانه ۱.۵ لیتری توربو بلوکور", zh: "蓝鲸新一代NE1.5T直喷发动机" },
|
||||
{ en: "7-Speed Wet DCT", fa: "گیربکس ۷ سرعته دوکلاچه تر", zh: "7速湿式双离合变速器" },
|
||||
{ en: "Column Shift (怀挡)", fa: "شیفتر ستونی پشت فرمان", zh: "电子怀挡" },
|
||||
{ en: "ADAS L2+ & ACC", fa: "کروز کنترل تطبیقی و رادار خطوط", zh: "L2级辅助驾驶与ACC" },
|
||||
{ en: "286 Technical Topics", fa: "۲۸۶ مبحث تخصصی و فنی", zh: "286篇专业技术篇目" }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "x5plus",
|
||||
code: "CAOM769911",
|
||||
active: true,
|
||||
image: "assets/images/ui/x5plus_car_card.jpg",
|
||||
manualUrl: "manual.html?car=x5plus",
|
||||
names: {
|
||||
en: "Changan X5 PLUS 2026",
|
||||
fa: "چانگان X5 پلاس ۲۰۲۶",
|
||||
zh: "长安第二代 X5 PLUS 2026款"
|
||||
},
|
||||
generation: {
|
||||
en: "2nd Generation • Sport Compact SUV",
|
||||
fa: "نسل دوم • کراساوور کامپکت اسپرت ۲۰۲۶",
|
||||
zh: "第二代 • 运动紧凑型SUV 2026款"
|
||||
},
|
||||
specs: [
|
||||
{ en: "1.5T BlueCore Direct Injection", fa: "پیشرانه ۱.۵ لیتری توربو بلوکور", zh: "蓝鲸新一代NE1.5T直喷发动机" },
|
||||
{ en: "7-Speed Wet DCT", fa: "گیربکس ۷ سرعته دوکلاچه تر", zh: "7速湿式双离合变速器" },
|
||||
{ en: "30-inch Triple Curved Display", fa: "نمایشگر سهگانه یکپارچه ۳۰ اینچ", zh: "30英寸一体化环抱三联屏" },
|
||||
{ en: "150 Technical Topics & Control Switches", fa: "۱۵۰ مبحث تخصصی و کلیدهای کابین", zh: "150篇专业技术篇目与全车按键" }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// Current State
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const urlLang = urlParams.get('lang');
|
||||
let currentLang = (urlLang && SUPPORTED_LANGS.includes(urlLang))
|
||||
? urlLang
|
||||
: (localStorage.getItem('cs55_manual_lang') || 'en');
|
||||
if (!SUPPORTED_LANGS.includes(currentLang)) currentLang = 'en';
|
||||
|
||||
if (urlLang && SUPPORTED_LANGS.includes(urlLang)) {
|
||||
localStorage.setItem('changan_user_lang_selected', 'true');
|
||||
localStorage.setItem('cs55_manual_lang', urlLang);
|
||||
}
|
||||
|
||||
// DOM Elements
|
||||
const dom = {
|
||||
langToggleBtn: document.getElementById('langToggleBtn'),
|
||||
currentLangIcon: document.getElementById('currentLangIcon'),
|
||||
currentLangLabel: document.getElementById('currentLangLabel'),
|
||||
langMenu: document.getElementById('langMenu'),
|
||||
firstVisitModal: document.getElementById('firstVisitModal'),
|
||||
vehiclesGrid: document.getElementById('vehiclesGrid'),
|
||||
brandSub: document.getElementById('brandSub'),
|
||||
heroBadge: document.getElementById('heroBadge'),
|
||||
heroHeading: document.getElementById('heroHeading'),
|
||||
heroDesc: document.getElementById('heroDesc'),
|
||||
catalogTitle: document.getElementById('catalogTitle'),
|
||||
featuresHeading: document.getElementById('featuresHeading'),
|
||||
feat1Title: document.getElementById('feat1Title'),
|
||||
feat1Desc: document.getElementById('feat1Desc'),
|
||||
feat2Title: document.getElementById('feat2Title'),
|
||||
feat2Desc: document.getElementById('feat2Desc'),
|
||||
feat3Title: document.getElementById('feat3Title'),
|
||||
feat3Desc: document.getElementById('feat3Desc'),
|
||||
feat4Title: document.getElementById('feat4Title'),
|
||||
feat4Desc: document.getElementById('feat4Desc'),
|
||||
footerCopy: document.getElementById('footerCopy'),
|
||||
footerHotline: document.getElementById('footerHotline')
|
||||
};
|
||||
|
||||
// Init App
|
||||
function init() {
|
||||
setupLanguageDropdown();
|
||||
setupFirstVisitModal();
|
||||
applyLanguage(currentLang);
|
||||
}
|
||||
|
||||
// Check and Show First Visit Modal
|
||||
function setupFirstVisitModal() {
|
||||
const hasChosenLang = localStorage.getItem('changan_user_lang_selected');
|
||||
if (!hasChosenLang && dom.firstVisitModal) {
|
||||
// Show modal for first-time visitors
|
||||
setTimeout(() => {
|
||||
dom.firstVisitModal.classList.add('open');
|
||||
}, 350);
|
||||
}
|
||||
|
||||
// Modal Option Buttons
|
||||
const choiceButtons = document.querySelectorAll('.lang-choice-btn');
|
||||
choiceButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const selected = btn.getAttribute('data-lang');
|
||||
if (SUPPORTED_LANGS.includes(selected)) {
|
||||
// Mark as selected
|
||||
localStorage.setItem('changan_user_lang_selected', 'true');
|
||||
setLanguage(selected);
|
||||
closeFirstVisitModal();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function closeFirstVisitModal() {
|
||||
if (dom.firstVisitModal) {
|
||||
dom.firstVisitModal.classList.remove('open');
|
||||
}
|
||||
}
|
||||
|
||||
// Language Dropdown in Header
|
||||
function setupLanguageDropdown() {
|
||||
if (dom.langToggleBtn) {
|
||||
dom.langToggleBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
dom.langMenu.classList.toggle('open');
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (dom.langMenu && !dom.langMenu.contains(e.target) && e.target !== dom.langToggleBtn) {
|
||||
dom.langMenu.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
const langOptions = document.querySelectorAll('.lang-option-btn');
|
||||
langOptions.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const selected = btn.getAttribute('data-lang');
|
||||
setLanguage(selected);
|
||||
dom.langMenu.classList.remove('open');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Switch Language
|
||||
function setLanguage(lang) {
|
||||
if (!SUPPORTED_LANGS.includes(lang)) return;
|
||||
currentLang = lang;
|
||||
localStorage.setItem('cs55_manual_lang', lang);
|
||||
applyLanguage(lang);
|
||||
}
|
||||
|
||||
// Apply Language to DOM
|
||||
function applyLanguage(lang) {
|
||||
const isRtl = (lang === 'fa');
|
||||
document.documentElement.setAttribute('dir', isRtl ? 'rtl' : 'ltr');
|
||||
document.documentElement.setAttribute('lang', lang);
|
||||
|
||||
// Update Header Button
|
||||
const icons = { en: '🇬🇧', fa: '🇮🇷', zh: '🇨🇳' };
|
||||
const labels = { en: 'English', fa: 'فارسی', zh: '中文' };
|
||||
if (dom.currentLangIcon) dom.currentLangIcon.textContent = icons[lang] || '🌐';
|
||||
if (dom.currentLangLabel) dom.currentLangLabel.textContent = labels[lang] || 'English';
|
||||
|
||||
// Update active class in dropdown menu
|
||||
document.querySelectorAll('.lang-option-btn').forEach(btn => {
|
||||
if (btn.getAttribute('data-lang') === lang) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Update Static Localized Text
|
||||
const t = HOME_I18N[lang] || HOME_I18N.en;
|
||||
if (dom.brandSub) dom.brandSub.textContent = t.brandSub;
|
||||
if (dom.heroBadge) dom.heroBadge.innerHTML = t.heroBadge;
|
||||
if (dom.heroHeading) dom.heroHeading.textContent = t.heroHeading;
|
||||
if (dom.heroDesc) dom.heroDesc.textContent = t.heroDesc;
|
||||
if (dom.catalogTitle) dom.catalogTitle.textContent = t.catalogTitle;
|
||||
|
||||
if (dom.featuresHeading) dom.featuresHeading.textContent = t.featuresHeading;
|
||||
if (dom.feat1Title) dom.feat1Title.textContent = t.feat1Title;
|
||||
if (dom.feat1Desc) dom.feat1Desc.textContent = t.feat1Desc;
|
||||
if (dom.feat2Title) dom.feat2Title.textContent = t.feat2Title;
|
||||
if (dom.feat2Desc) dom.feat2Desc.textContent = t.feat2Desc;
|
||||
if (dom.feat3Title) dom.feat3Title.textContent = t.feat3Title;
|
||||
if (dom.feat3Desc) dom.feat3Desc.textContent = t.feat3Desc;
|
||||
if (dom.feat4Title) dom.feat4Title.textContent = t.feat4Title;
|
||||
if (dom.feat4Desc) dom.feat4Desc.textContent = t.feat4Desc;
|
||||
|
||||
if (dom.footerCopy) dom.footerCopy.textContent = t.footerCopy;
|
||||
if (dom.footerHotline) dom.footerHotline.textContent = t.footerHotline;
|
||||
|
||||
// Render Vehicle Cards with localized names & buttons
|
||||
renderVehicleCatalog(lang);
|
||||
}
|
||||
|
||||
// Render Vehicles Catalog Grid
|
||||
function renderVehicleCatalog(lang) {
|
||||
if (!dom.vehiclesGrid) return;
|
||||
const t = HOME_I18N[lang] || HOME_I18N.en;
|
||||
|
||||
let html = '';
|
||||
for (const car of VEHICLES) {
|
||||
const carName = car.names[lang] || car.names.en;
|
||||
const carGen = car.generation[lang] || car.generation.en;
|
||||
const statusBadge = car.active
|
||||
? `<span class="car-status-badge badge-active">${t.activeModelBadge}</span>`
|
||||
: `<span class="car-status-badge badge-upcoming">${t.upcomingBadge}</span>`;
|
||||
|
||||
// Build specs chips
|
||||
const chipsHtml = car.specs.map(s => {
|
||||
const specText = s[lang] || s.en;
|
||||
return `<span class="spec-chip">${specText}</span>`;
|
||||
}).join('');
|
||||
|
||||
// Big Action Button
|
||||
let actionBtn = '';
|
||||
if (car.active) {
|
||||
actionBtn = `
|
||||
<a href="${car.manualUrl}" class="btn-car-select btn-primary">
|
||||
<span>${t.openManualBtn}</span>
|
||||
</a>
|
||||
`;
|
||||
} else {
|
||||
actionBtn = `
|
||||
<button class="btn-car-select btn-disabled" disabled>
|
||||
<span>${t.comingSoonBtn}</span>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="car-card ${car.active ? 'active-model' : ''}" data-car-id="${car.id}">
|
||||
<div class="car-photo-container">
|
||||
${statusBadge}
|
||||
<img src="${car.image}" alt="${carName}" class="car-photo-img" loading="lazy">
|
||||
</div>
|
||||
<div class="car-card-body">
|
||||
<!-- Requirement: Name of the car under their photo -->
|
||||
<h3 class="car-name-title">${carName}</h3>
|
||||
<div class="car-sub-label">${carGen}</div>
|
||||
|
||||
<div class="car-specs-chips">
|
||||
${chipsHtml}
|
||||
</div>
|
||||
|
||||
<!-- Requirement: Big buttons -->
|
||||
<div class="car-card-actions">
|
||||
${actionBtn}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
dom.vehiclesGrid.innerHTML = html;
|
||||
}
|
||||
|
||||
// Expose global for testing
|
||||
window.homeApp = {
|
||||
setLanguage,
|
||||
closeFirstVisitModal
|
||||
};
|
||||
|
||||
// Run on DOM Ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user