Initial commit: AIFO official portal web.

Add static site, shared layout, and Node dev server with standard .gitignore.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-30 15:29:50 +08:00
commit 4d30803b60
1154 changed files with 184340 additions and 0 deletions
+842
View File
@@ -0,0 +1,842 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Probably the most complete UI kit out there. Multiple functionalities and controls added, extended color palette and beautiful typography, designed as its own extended version of Bootstrap at the highest level of quality. ">
<meta name="author" content="Webpixels">
<title>company_news_sub Page</title>
<!-- Fonts -->
<!-- <link href="https://fonts.googleapis.com/css?family=Nunito:400,600,700,800|Roboto:400,500,700" rel="stylesheet"> -->
<link type="text/css" href="../assets/vendor/icon/iconfont.css" rel="stylesheet">
<link href="../assets/css/style.css" rel="stylesheet">
<!-- Theme CSS -->
<link type="text/css" href="../assets/css/theme.css" rel="stylesheet">
<!-- Demo CSS - No need to use these in your project -->
<!-- <link type="text/css" href="../assets/css/demo.css" rel="stylesheet"> -->
<link type="text/css" href="../assets/css/index.css" rel="stylesheet">
<link type="text/css" href="../assets/css/academy.css" rel="stylesheet">
</head>
<body class="aifo-bg-primary">
<!-- Top code bar -->
<!-- <div class="top-code-bar bg-primary">
<div class="container d-flex align-items-center justify-content-center h-100">
<span class="top-code-label">35% OFF + 350% REFUND Limited Time</span>
<button type="button" class="btn btn-sm top-code-btn" data-code="AIFO2025">CODE:AIFO</button>
</div>
</div> -->
<div id="nav-container"></div>
<main class="main" id="company-news-sub">
<div class="main-wrapper"><!-- Navbar -->
<div class="container content-area ">
<div class="row"><!-- Left Column: Article -->
<div class="col-lg-8"><!-- Breadcrumb -->
<div class="breadcrumb-nav">
<div class="back-button"><span class="icon iconfont icon-arrowleft"></span></div>
<span class="breadcrumb-text">All Posts</span>
</div><!-- Hero Image -->
<div class="article-hero">
<img src="../assets/images/demo/article_pic.png">
</div><!-- Article Card -->
<div class="article-card">
<div class="article_content" id="article_content">
<h1 class="article-title" id="article-title">Building Global Trading Powerhouse Completes Acquisition of OANDA from CVC</h1>
<div class="article-meta">
<span id="publish-date">Published on Dec 16th</span>
<span id="update-date">Updated on Dec 18th</span>
</div>
<div class="article-content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.</p>
<p>Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p>
<p>Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam.</p>
</div>
</div>
</div><!-- Tags -->
<div class="article-tags">
<div class="tag-pill">
Key word
</div>
<div class="tag-pill">
Key word
</div>
<div class="tag-pill">
Key word
</div>
</div>
</div><!-- Right Column: Sidebar -->
<div class="col-lg-4">
<div class="sidebar-card"><!-- Newsletter -->
<div class="newsletter-module">
<div class="newsletter-header">
<div class="newsletter-icon">
<img src="../assets/images/backgrounds/icon/newsletter.png">
</div>
<div class="newsletter-title" id="newsletter-title">
Stay Up-To-Date With Our Newsletter
</div>
</div><input type="email" class="newsletter-input" id="email-input" placeholder="Email"> <button class="btn-subscribe" id="subscribe-btn">Subscribe</button>
<div class="subscribe-message" id="subscribe-message"></div>
</div><!-- Recommended Articles -->
<div class="recommended-item">
<div class="article_thumbnail">
<img src="../assets/images/demo/article_demo.png">
</div>
<div class="recommended-title">
Torem ipsum
</div>
<div class="recommended-excerpt">
Torem ipsum dolor sit amet, consectetur adipiscing elit. Eti…
</div>
</div>
<div class="recommended-item">
<div class="article_thumbnail">
<img src="../assets/images/demo/article_demo.png">
</div>
<div class="recommended-title">
Torem ipsum
</div>
<div class="recommended-excerpt">
Torem ipsum dolor sit amet, consectetur adipiscing elit. Eti…
</div>
</div>
<div class="recommended-item">
<div class="article_thumbnail">
<img src="../assets/images/demo/article_demo.png">
</div>
<div class="recommended-title">
Torem ipsum
</div>
<div class="recommended-excerpt">
Torem ipsum dolor sit amet, consectetur adipiscing elit. Eti…
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<section id="section-10" class="slice slice-lg d-flex align-items-center">
<div class="bg-orange-light"></div>
<div class="container">
<div class="mb-md text-center fade-in">
<h1 class="heading h1">Join <img src="../assets/images/backgrounds/Frame 1000008381.png" alt="Funded Trading" class="tx-img floating-img"></h1>
<h1 class="heading h1"> <img src="../assets/images/backgrounds/Frame 1000008386.png" alt="Funded Trading" class="zfj-img floating-img"><span class="text-orange">Our Community</span></h1>
<div class="fluid-paragraph text-center mt-4">
<p class="lead lh-180">
Join a <span class="text-orange">supportive network</span> of traders where you can <br>share insights, learn together, and celebrate <br>every step of your journey.
</p>
</div>
</div>
<div class="row justify-content-center ">
<div class="col-auto">
<div class="hero-buttons d-flex flex-wrap justify-content-center fade-in">
<a href="#" class="btn btn-start-challenge d-flex align-items-center justify-content-center"><img src="../assets/images/backgrounds/btn-icon-1.png" alt="Funded Trading"> Join Discord</a>
<a href="#" class="btn btn-free-trial">
<span class="btn-join-telegram-icon"></span>
<!--<img src="../assets/images/backgrounds/btn-icon-2.png" alt="Funded Trading" class="floating-img"> -->
Join Telegram
</a>
</div>
</div>
</div>
</div>
</section>
</main>
<div id="footer-container"></div>
<!-- Core -->
<script src="../assets/vendor/jquery/jquery-3.7.1.min.js"></script>
<script src="../assets/vendor/popper/popper.min.js"></script>
<script src="../assets/js/bootstrap/bootstrap.min.js"></script>
<!-- FontAwesome 5 -->
<script src="../assets/vendor/fontawesome/js/fontawesome-all.min.js" defer></script>
<!-- Page plugins -->
<script src="../assets/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
<script src="../assets/vendor/bootstrap-tagsinput/bootstrap-tagsinput.min.js"></script>
<script src="../assets/vendor/input-mask/input-mask.min.js"></script>
<script src="../assets/vendor/nouislider/js/nouislider.min.js"></script>
<script src="../assets/vendor/textarea-autosize/textarea-autosize.min.js"></script>
<!-- Theme JS -->
<script src="../assets/js/theme.js"></script>
<!-- Top code bar behavior -->
<script src="/js/layout.js"></script>
</body>
<script>
/* =========================
Intersection fade-in (pixel-precise)
and lazy loaders for floor loading
========================= */
(function($){
const io = new IntersectionObserver((entries, obs) => {
entries.forEach(e=>{
if(e.isIntersecting){
$(e.target).addClass('show');
obs.unobserve(e.target);
}
});
},{threshold:0.12});
$(function(){
$('.fade-in').each(function(){ io.observe(this); });
});
})(jQuery);
/* =========================
Lazy images and floor-load logic
========================= */
(function($){
const loaderIO = new IntersectionObserver((entries, obs) => {
entries.forEach(ent=>{
if(ent.isIntersecting){
const $el = $(ent.target);
// lazy images
if($el.hasClass('lazy-img')){
const src = $el.data('src');
if(src) $el.attr('src', src).removeAttr('data-src').removeClass('lazy-img');
obs.unobserve(ent.target);
}
// load growth stories and courses when their blocks appear
if($el.is('#storiesBlock')){ loadGrowth(); obs.unobserve(ent.target); }
if($el.is('#coursesBlock')){ loadCourses(); obs.unobserve(ent.target); }
}
});
},{root:null, threshold:0.15});
$(function(){
$('.lazy-img, #storiesBlock, #coursesBlock').each(function(){ loaderIO.observe(this); });
});
/* ========== Growth Stories ========== */
let growthLoaded=false;
function loadGrowth(){
if(growthLoaded) return;
growthLoaded = true;
}
/* ========== Courses ========== */
let coursesLoaded=false;
function loadCourses(){
if(coursesLoaded) return;
coursesLoaded=true;
const courses = [
{title:'Basics', thumb:'https://picsum.photos/id/1018/640/360', lessons:12},
{title:'Forex 101', thumb:'https://picsum.photos/id/1016/640/360', lessons:8},
{title:'Risk Management', thumb:'https://picsum.photos/id/1019/640/360', lessons:6},
{title:'Advanced Tactics', thumb:'https://picsum.photos/id/1022/640/360', lessons:10},
{title:'Live Sessions', thumb:'https://picsum.photos/id/1021/640/360', lessons:5},
{title:'Performance Review', thumb:'https://picsum.photos/id/1032/640/360', lessons:7}
];
const $grid = $('#courseGrid').empty();
courses.forEach(c=>{
const $card = $(`
<div class="course-card">
<img class="course-thumb" loading="lazy" src="${c.thumb}" alt="${c.title}">
<h5 style="margin-top:0.5rem">${c.title}</h5>
<p class="small-muted">Lessons: ${c.lessons}</p>
<div style="margin-top:0.75rem"><a class="btn btn-outline-light btn-sm" href="#">View</a></div>
</div>
`);
$grid.append($card);
});
}
window.loadGrowth = loadGrowth;
window.loadCourses = loadCourses;
})(jQuery);
/* =========================
Growth carousel: basic translateX carousel
autoplay + controls + pause on hover
========================= */
// function initGrowthCarousel(){
// const $wrap = $('#growthTrack');
// let idx = 0;
// let autoplay = true;
// let timer = null;
// function update(){
// const $items = $wrap.children();
// if(!$items.length) return;
// const w = $items.first().outerWidth(true);
// $wrap.css('transform', `translateX(${-idx * w}px)`);
// // update dots styling (if using growthDots)
// $('#growthDots button').removeClass('active');
// $('#growthDots button[data-i="'+idx+'"]').addClass('active');
// }
// function next(){
// idx = (idx + 1) % $wrap.children().length;
// update();
// }
// function prev(){
// idx = (idx - 1 + $wrap.children().length) % $wrap.children().length;
// update();
// }
// $('#growthNext').off('click').on('click', ()=>{ autoplay=false; next(); });
// $('#growthPrev').off('click').on('click', ()=>{ autoplay=false; prev(); });
// $('#growthDots').on('click','button', function(){ autoplay=false; idx = Number($(this).data('i')); update(); });
// function startLoop(){
// if(timer) clearInterval(timer);
// timer = setInterval(()=>{ if(autoplay) next(); }, 3500);
// }
// startLoop();
// $wrap.on('mouseenter touchstart', ()=> autoplay=false);
// $wrap.on('mouseleave touchend', ()=> autoplay=true);
// }
/* =========================
Video modal play: inject iframe
========================= */
(function($){
$('#playBtn').on('click', function(){
const vid = $('#videoPreview').data('video-id');
//const src = `https://www.youtube.com/embed/${vid}?autoplay=1&rel=0`;
const src = `http://192.168.1.175/Lark20251101-104552.mp4`;
$('#videoContainer').html(`<iframe src="${src}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen style="position:absolute;inset:0;width:100%;height:100%"></iframe>`);
$('#videoModal').modal('show');
});
$('#videoModal').on('hidden.bs.modal', function(){ $('#videoContainer').empty(); });
// fallback: ensure lazy imgs loaded if they still have data-src
$(function(){
$('.lazy-img').each(function(){
const $i = $(this);
if($i.attr('data-src')) $i.attr('src',$i.attr('data-src')).removeAttr('data-src');
});
});
})(jQuery);
/* =========================
initial reveal sequencing
========================= */
$(function(){
setTimeout(()=> $('#heroBlock').addClass('show'), 160);
setTimeout(()=> $('#videoPreview').addClass('show'), 420);
});
/* =========================
Smooth anchor scroll (if needed)
========================= */
$(document).on('click','a[href^="#"]', function(e){
const target = $($(this).attr('href'));
if(target.length){ e.preventDefault(); $('html,body').animate({scrollTop: target.offset().top - 24}, 600); }
});
</script>
<script>
/* ===========================================================
Reusable Carousel Class
=========================================================== */
class Carousel {
constructor(opts) {
this.container = document.querySelector(opts.container);
this.track = this.container.querySelector(".carousel-track");
this.items = [...this.track.children];
this.prevBtn = document.getElementById(opts.prev);
this.nextBtn = document.getElementById(opts.next);
this.dotsContainer = document.querySelector(opts.dots);
this.index = 0;
this.pageWidth = this.items[0].offsetWidth + 40; // including margin
this.setupDots();
this.update();
this.bindEvents();
}
setupDots() {
this.dotsContainer.innerHTML = "";
this.items.forEach((_, i) => {
const dot = document.createElement("div");
dot.className = "dot";
dot.addEventListener("click", () => this.goTo(i));
this.dotsContainer.appendChild(dot);
});
}
bindEvents() {
this.prevBtn.addEventListener("click", () => this.prev());
this.nextBtn.addEventListener("click", () => this.next());
window.addEventListener("resize", () => {
this.pageWidth = this.items[0].offsetWidth + 40;
this.update();
});
}
prev() {
this.index = Math.max(0, this.index - 1);
this.update();
}
next() {
this.index = Math.min(this.items.length - 1, this.index + 1);
this.update();
}
goTo(i) {
this.index = i;
this.update();
}
update() {
const centerOffset = (window.innerWidth / 2) - (this.pageWidth / 2);
let x = this.index * this.pageWidth * -1 + centerOffset;
if (this.index === 0) x = 0;
if (this.index === this.items.length - 1) {
x = (this.items.length - 1) * this.pageWidth * -1 + (window.innerWidth - this.pageWidth);
}
this.track.style.transform = `translateX(${x}px)`;
[...this.dotsContainer.children].forEach((dot, i) => {
dot.classList.toggle("active", i === this.index);
});
}
}
/* ===========================================================
Fade-in Observer (one-time trigger)
=========================================================== */
function setupFadeInObserver(selector = ".carousel-item") {
const items = document.querySelectorAll(selector);
const observer = new IntersectionObserver(
(entries, obs) => {
entries.forEach(entry => {
// if (entry.isIntersecting) {
entry.target.classList.add("fade-in");
entry.target.classList.add("show");
obs.unobserve(entry.target);
// }
});
},
{
root: document.querySelector(".carousel-container-1"),
threshold: 0.5
}
);
items.forEach(item => observer.observe(item));
}
/* ===========================================================
Initialization
=========================================================== */
window.addEventListener("DOMContentLoaded", () => {
// new Carousel({
// container: ".carousel-container-1",
// prev: "growthPrev",
// next: "growthNext",
// dots: ".dots"
// });
const carousel = new Carousel({
container: ".carousel-container-1",
prev: "growthPrev",
next: "growthNext",
dots: ".dots"
});
setTimeout(() => {
carousel.goTo(1);
}, 50);
setupFadeInObserver(".carousel-item");
});
</script>
<script>
$(function(){
const $track = $("#track");
const $viewport = $(".carousel-viewport");
const $indicators = $("#indicators");
const $btnPrev = $("#btnPrev");
const $btnNext = $("#btnNext");
// store original cards data (from DOM at load)
let $originalCards = $track.children(".carousel-card").toArray().map(el => $(el).clone(true));
let originalCount = $originalCards.length;
let visibleCount = getVisibleCount();
let index = 0; // Start from 0, no need to clone cards
let animating = false;
let cardW = null;
let gap = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--card-gap')) || 20;
// Swipe related variables
let isMobile = window.innerWidth <= 768;
let swipeStartTime = 0;
let swipeMinDistance = 50; // Minimum swipe distance threshold
let swipeMinVelocity = 0.3; // Minimum swipe velocity (pixels/millisecond)
function getVisibleCount(){
return window.innerWidth <= 768 ? 1 : 4;
}
function updateDeviceSettings() {
isMobile = window.innerWidth <= 768;
// Update swipe parameters
if (isMobile) {
swipeMinDistance = cardW * 0.2; // Mobile: 20% of card width
swipeMinVelocity = 0.3;
} else {
// PC doesn't use touch swipe, set threshold to maximum
swipeMinDistance = 9999; // Maximum value to ensure it won't be triggered
swipeMinVelocity = 9999;
}
}
function buildTrack(){
// empty track and indicators
$track.empty();
$indicators.empty();
visibleCount = getVisibleCount();
// No longer add cloned cards, only show original cards
$originalCards.forEach($el => $track.append($el.clone(true)));
// build indicators — one per original card
console.log(originalCount);
for(let i=0;i<originalCount-visibleCount;i++){
console.log(i);
$indicators.append(`<div class="ind" data-i="${i}"></div>`);
}
// set starting index to 0
index = 0;
// compute cardW (outerWidth including gap)
cardW = $(".carousel-card").outerWidth(true);
// Update device settings
updateDeviceSettings();
// position track at initial
$track.css({ transform: `translateX(${-index * cardW}px)` , transition: 'none' });
// small delay to ensure no animation on first paint
setTimeout(()=> $track.css('transition','transform .45s ease'), 20);
updateDots();
updateButtonState(); // Update button state
}
function updateDots(){
$indicators.find(".ind").removeClass("active");
$indicators.find(`.ind[data-i="${index}"]`).addClass("active");
}
function updateButtonState() {
// Update button state: disable prev button on first card, disable next button on last card
if (index <= 0) {
$btnPrev.addClass("disabled").prop("disabled", true);
} else {
$btnPrev.removeClass("disabled").prop("disabled", false);
}
if (index >= originalCount - visibleCount) {
$btnNext.addClass("disabled").prop("disabled", true);
} else {
$btnNext.removeClass("disabled").prop("disabled", false);
}
}
function slideTo(idx, animate=true){
if(animating) return;
// 检查边界
const maxIndex = originalCount - visibleCount;
const minIndex = 0;
// Limit index range
let targetIndex = Math.max(minIndex, Math.min(idx, maxIndex));
// If already at boundary, don't execute animation
if (targetIndex === index && animate) return;
animating = true;
$track.css('transition', animate ? 'transform .45s ease' : 'none');
$track.css('transform', `translateX(${-targetIndex * cardW}px)`);
index = targetIndex;
// Update state
setTimeout(()=>{
updateDots();
updateButtonState();
animating = false;
}, animate ? 500 : 20);
}
function next(){
// Check if reached last
if (index >= originalCount - visibleCount) return;
slideTo(index + 1, true);
}
function prev(){
// Check if reached first
if (index <= 0) return;
slideTo(index - 1, true);
}
// dots click
$indicators.on('click', '.ind', function(){
const target = Number($(this).attr('data-i')); // 0..originalCount-1
slideTo(target, true);
});
// arrows - add check
$btnNext.on('click', function(){
if ($(this).hasClass("disabled")) return;
next();
});
$btnPrev.on('click', function(){
if ($(this).hasClass("disabled")) return;
prev();
});
/* ========= 移动端触摸滑动效果 ========= */
// 只在移动端绑定触摸事件
if (window.innerWidth <= 768) {
initMobileTouchEvents();
}
function initMobileTouchEvents() {
let pointerDown = false;
let startX = 0;
let startTranslate = 0;
let moved = 0;
let swipeEndTime = 0;
let velocity = 0;
let currentExactPosition = 0;
let maxTranslate = 0;
let minTranslate = 0;
// helper get current translateX (number)
function currentTranslate(){
const m = $track.css('transform');
if(!m || m === 'none') return 0;
const arr = m.split(',');
return parseFloat(arr[arr.length-1]);
}
// pointer start (仅触摸)
$track.on('touchstart', function(e){
if(animating) return;
pointerDown = true;
startX = e.originalEvent.touches[0].clientX;
startTranslate = currentTranslate();
currentExactPosition = startTranslate;
moved = 0;
velocity = 0;
swipeStartTime = Date.now();
// 计算边界
maxTranslate = 0; // 最左边,对应第一张
minTranslate = -(originalCount - visibleCount) * cardW; // 最右边,对应最后一张
// disable transition while dragging
$track.css('transition','none');
$('.carousel-card').addClass('grabbing');
e.preventDefault();
});
// 移动事件
$(window).on('touchmove', function(e){
if(!pointerDown) return;
const clientX = e.originalEvent.touches[0].clientX;
const dx = clientX - startX;
moved = dx;
// 计算精确位置,并限制在边界内
let targetPosition = startTranslate + dx;
// 添加边界阻尼效果
if (targetPosition > maxTranslate) {
// 超出左边边界,添加阻尼效果
const overshoot = targetPosition - maxTranslate;
targetPosition = maxTranslate + overshoot * 0.3;
} else if (targetPosition < minTranslate) {
// 超出右边边界,添加阻尼效果
const overshoot = targetPosition - minTranslate;
targetPosition = minTranslate + overshoot * 0.3;
}
currentExactPosition = targetPosition;
// 应用移动效果
$track.css('transform', `translateX(${currentExactPosition}px)`);
});
// 结束事件
$(window).on('touchend touchcancel', function(e){
if(!pointerDown) return;
swipeEndTime = Date.now();
const swipeDuration = swipeEndTime - swipeStartTime;
// 计算滑动速度
if (swipeDuration > 0) {
velocity = Math.abs(moved) / swipeDuration;
}
pointerDown = false;
$('.carousel-card').removeClass('grabbing');
// 检查边界
const atLeftBoundary = currentExactPosition >= maxTranslate - 10;
const atRightBoundary = currentExactPosition <= minTranslate + 10;
if (atLeftBoundary || atRightBoundary) {
// 如果在边界附近,直接回到边界
if (atLeftBoundary) {
slideTo(0, true);
} else {
slideTo(originalCount - visibleCount, true);
}
return;
}
// 移动端滑动结束处理
handleMobileSwipeEnd();
});
}
// 移动端滑动结束处理
function handleMobileSwipeEnd() {
const absMoved = Math.abs(moved);
const swipeDirection = moved < 0 ? 1 : -1; // 1: 向左滑动, -1: 向右滑动
let shouldSwitch = false;
// 判断是否应该切换(基于距离或速度)
// 移动端:每次只滑动1张,需要明显的滑动距离
if (absMoved > swipeMinDistance) {
shouldSwitch = true;
} else if (velocity > swipeMinVelocity && absMoved > swipeMinDistance * 0.5) {
shouldSwitch = true;
}
if (shouldSwitch) {
// 移动端:每次只滑动1张图片
if (swipeDirection === 1) {
// 向左滑动,显示下一张(只滑动1张)
next();
} else if (swipeDirection === -1) {
// 向右滑动,显示上一张(只滑动1张)
prev();
}
} else {
// 滑动距离不足,停留在当前位置
slideTo(index, true);
}
}
/* ========= PC端鼠标拖动效果 ========= */
// PC端只保留鼠标点击按钮功能,不绑定拖动事件
/* ========== resize handling: rebuild if visibleCount changes ========== */
let resizeTimer = null;
$(window).on('resize', function(){
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function(){
const newVisible = getVisibleCount();
// 移除旧的触摸事件
$track.off('touchstart');
$(window).off('touchmove touchend touchcancel');
if(newVisible !== visibleCount){
// rebuild track
// restore original cards array from clones
$track.empty();
$originalCards.forEach($el => $track.append($el.clone(true)));
// reassign originalCards (fresh clones)
$originalCards = $track.children(".carousel-card").toArray().map(el => $(el).clone(true));
originalCount = $originalCards.length;
buildTrack();
} else {
// just recompute cardW and set immediate position
cardW = $(".carousel-card").outerWidth(true);
updateDeviceSettings(); // 更新设备设置
$track.css('transition','none');
$track.css('transform', `translateX(${-index * cardW}px)`);
setTimeout(()=> $track.css('transition','transform .45s ease'), 20);
}
// 根据新的屏幕大小重新绑定触摸事件
if (window.innerWidth <= 768) {
initMobileTouchEvents();
}
}, 120);
});
/**************** INIT ****************/
let $initial = $track.children(".carousel-card").toArray().map(el=>$(el).clone(true));
$originalCards = $initial.slice(); // store original clones
originalCount = $originalCards.length;
buildTrack();
});
</script>
<script>
// FAQ Accordion
$('.faq-header').on('click', function() {
var $item = $(this).closest('.faq-item');
var $body = $item.find('.faq-body');
var isActive = $item.hasClass('active');
// Close all items
$('.faq-item').removeClass('active');
$('.faq-body').css('max-height', '0').css('opacity', '0');
// Open clicked item if it wasn't active
if (!isActive) {
$item.addClass('active');
$body.css('max-height', '500px').css('opacity', '1');
}
});
</script>
</html>