Files
steven 4d30803b60 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>
2026-06-30 15:29:50 +08:00

958 lines
39 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>Academy_1 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">
<style id="toc-progress-style">
.toc-list::after {
transform: translateY(0px);
}
</style>
<style>
.content-columns{
display: flex;
}
.left-sidebar {
position: sticky;
top: 97px;
align-self: flex-start;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #ccc transparent;
}
.right-sidebar{
position: sticky;
top: 97px;
}
.section-sub-title{
max-width: 843px;
margin: 0 auto;
margin-top: 2.5rem !important;
}
.article-detail-section .text-center{
margin-bottom: 5rem !important;
margin-top: 5rem;
}
@media (min-width: 1200px) {
#academy-1 .academy-title-1 {
margin-top: 9.5rem;
}
}
@media (max-width: 768px) {
.right-sidebar .navbar-brand {
display: inline-block;
padding-top: .325rem;
padding-bottom: .325rem;
margin-right: 1rem;
font-size: 1.09375rem;
line-height: inherit;
white-space: nowrap;
position: unset;
-webkit-transform: translate(-50%, -50%);
transform: unset;
}
#academy-sub .breadcrumb-wrapper {
padding: 0;
margin-bottom: 12px;
}
#academy-sub .breadcrumb{
padding: 0;
}
.article-detail-section .text-center {
margin-top: 0rem;
margin-bottom: 2rem !important;
}
}
</style>
</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="academy-sub">
<!-- banner start -->
<div class="academy-block-1" id="academy-1">
<section id="acadey-section-1" class="funded-trading-hero spotlight parallax bg-cover bg-size--cover" data-spotlight="fullscreen" >
<div class="container">
<div class="row align-items-center ">
<div class="col-md-5 mb-4 academy-title-1 mb-hidden">
<a class="btn btn-page-tab section-title">02</a>
<h1><span class="text-orange">Supply & Demand</span> <br> Trading</h1>
</div>
<div class="header_img_block col-md-7 academy-title-1">
<div class="thumb">
<img src="../assets/images/backgrounds/academy/img-1.png" alt="">
<div class="video-play" id="playBtn" aria-label="Play video">
<i class="pay-btn"></i>
</div>
</div>
</div>
<div class="col-md-5 academy-title-1 mb-show">
<a class="btn btn-page-tab section-title">02</a>
<h1><span class="text-orange">Supply & Demand</span> <br> Trading</h1>
</div>
</div>
</div>
</section>
</div>
<!-- subtle grid overlay -->
<div class="bg-grid" aria-hidden="true"></div>
<!-- article detail section -->
<section class="slice slice-lg article-detail-section">
<div class="container">
<div class="mb-md text-center fade-in">
<h1 class="heading h1 fade-in">Course <span class="text-orange">Structure</span></h1>
<p class="section-sub-title lead lh-180 mt-4 fade-in">
Every successful trader begins with <span class="text-orange">a clear path</span>.
Our course guides you toward <span class="text-orange">funded success</span>.
</p>
</div>
<div class="content-columns-wrapper">
<div class="content-columns"><!-- Left Sidebar - Table of Contents (桌面端显示) -->
<div class="left-sidebar">
<div class="sticky-sidebar">
<div class="toc-card">
<div class="toc-title">
Table of Contents
</div>
<ul class="toc-list" id="generated-toc">
</ul>
</div>
</div>
</div><!-- Main Article (Center) - order: 1 on mobile -->
<div class="main-content">
<div class="breadcrumb-wrapper">
<nav class="breadcrumb">
<a href="#" class="breadcrumb-item">Course Structure</a>
<span class="breadcrumb-separator"></span>
<a href="#" class="breadcrumb-item">2.2 Technical Analysis Explained</a>
<span class="breadcrumb-separator"></span>
<span class="breadcrumb-item">2.2.5 What is the CCI3444444444434535434</span>
<!-- <span class="breadcrumb-item active">2.2.5 What is the CCI</span> -->
</nav>
</div><!-- Breadcrumb Divider (桌面端显示) -->
<div class="breadcrumb-divider">
<div class="breadcrumb-divider-line"></div>
</div>
<div class="main-article">
<div class="article-header">
<h1 class="article-title">Understanding the CCI Indicator</h1>
</div>
<div class="article-content">
<h2>What is the CCI? versatile momentum-based oscillator developed</h2>
<p>The Commodity Channel Index (CCI) is a versatile momentum-based oscillator developed by Donald Lambert in 1980. Originally designed for commodity trading, the CCI has proven equally effective across various financial markets including stocks, forex, and cryptocurrencies.</p>
<p>The CCI measures the current price level relative to an average price level over a specified period. When the CCI is high, it indicates that prices are well above their average, suggesting potential overbought conditions. Conversely, when the CCI is low, prices are well below their average, potentially indicating oversold conditions.</p>
<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td><strong>Type</strong></td><td><strong>Size</strong></td></tr><tr><td>Standard Lot</td><td>100,000 units of base currency</td></tr><tr><td>Mini Lot</td><td>10,000 units</td></tr><tr><td>Micro Lot</td><td>1,000 units</td></tr></tbody></table></figure>
<h2>Applying the CCI in Trading ers employ when using the CCI indicator</h2>
<p>There are several popular strategies traders employ when using the CCI indicator. The CCI typically oscillates between +100 and -100. Readings above +100 may signal overbought conditions, while readings below -100 may indicate oversold conditions.</p>
<p>Divergence trading involves looking for situations where price makes new highs or lows while the CCI fails to confirm, potentially signaling a reversal. Zero-line crossovers offer another approach—when CCI crosses above zero, it may suggest bullish momentum, while crossing below zero may indicate bearish momentum.</p>
<h2>CCI Formula and Calculation</h2>
<p>The CCI is calculated using the following steps: First, compute the Typical Price (TP) as the average of high, low, and close prices. Then, calculate the Simple Moving Average of the Typical Price over your chosen period. Finally, derive the Mean Deviation and apply the CCI formula.</p>
<p>The formula divides the difference between the Typical Price and its moving average by a constant multiplied by the Mean Deviation. This normalization ensures that approximately 70-80% of CCI values fall between -100 and +100.</p>
<h2 >Trading Strategies</h2>
<p>Many traders use the +100/-100 levels as entry and exit signals. When CCI moves above +100, it signals strong upward momentum, and traders might consider long positions. When it falls below -100, it indicates strong downward momentum, potentially signaling short opportunities.</p>
<p>Another effective strategy combines CCI with support and resistance levels. When price approaches a support level and CCI shows oversold readings below -100, it may present a buying opportunity. Similarly, resistance levels combined with overbought CCI readings above +100 might signal selling opportunities.</p>
<h2>Common Mistakes</h2>
<p>One of the most common mistakes traders make is relying solely on the CCI without considering other factors. The CCI, like all technical indicators, should not be used in isolation. Market context, price action, and volume should all be considered alongside CCI readings.</p>
<p>Another mistake is assuming that overbought always means "sell" and oversold always means "buy." In strong trending markets, the CCI can remain in overbought or oversold territory for extended periods. This is why confirmation from other indicators is crucial.</p>
<h2>Best Practices</h2>
<p>For optimal results, consider combining CCI with other technical indicators such as moving averages or support/resistance levels. This multi-indicator approach helps filter out false signals and provides stronger confirmation for trading decisions.</p>
<p>Always use proper risk management techniques. Set stop-loss orders to protect your capital, and never risk more than a small percentage of your trading account on a single trade. The CCI is a powerful tool, but it works best when integrated into a comprehensive trading strategy.</p>
<p>Finally, practice using the CCI on historical data before applying it to live trading. This allows you to understand its behavior in different market conditions and develop confidence in interpreting its signals.</p>
</div>
</div>
</div><!-- Right Sidebar - order: 2 on mobile (正文之后) -->
<div class="right-sidebar">
<div class="sticky-sidebar"><!-- Lessons List -->
<div class="lessons-card">
<div class="lessons-title">
Technical Analysis Lessons
</div>
<div class="lesson-item">
<div class="lesson-thumbnail">
<img src="../assets/images/backgrounds/article-demo-1.png" alt="">
</div>
<div class="lesson-text">
2.2.4 MACD indicator
</div>
</div>
<div class="lesson-item active">
<div class="lesson-thumbnail">
<img src="../assets/images/backgrounds/article-demo-1.png" alt="">
</div>
<div class="lesson-text">
2.2.5 CCI indicator
</div>
</div>
<div class="lesson-item">
<div class="lesson-thumbnail">
<img src="../assets/images/backgrounds/article-demo-1.png" alt="">
</div>
<div class="lesson-text">
2.2.6 RSI indicator
</div>
</div>
</div><!-- Challenge Banner -->
<div class="challenge-banner">
<div class="challenge-logo">
<a class="navbar-brand" href="../index.html">
<img src="../assets/images/brand/logo_1.svg" alt="" />
</a>
</div>
<h3 class="challenge-title">Ready to take the challenge?</h3>
<p class="challenge-text">Join a community of thousands of prop traders today</p>
<a href="#" class="challenge-btn">
Start your journey
<svg viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7" />
</svg>
</a>
<div class="challenge-decoration">
<div class="bar" style="height: 20px;"></div>
<div class="bar" style="height: 35px;"></div>
<div class="bar" style="height: 28px;"></div>
<div class="bar" style="height: 45px;"></div>
<div class="bar" style="height: 32px;"></div>
<div class="bar" style="height: 38px;"></div>
<div class="bar" style="height: 25px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Great Job Section -->
<section class="greate-job-section">
<div class="container">
<div class="support-card">
<div class="support-content">
<div class="support-text">
<h2 class="support-title">Excellent work!</h2>
<p class="support-subtitle">
Congratulations on completing this lesson, that's another step toward becoming a successful trader.
</p>
<br>
<p class="support-subtitle">
Dive into the next lesson and continue building your skills.
</p>
<div class="support-buttons">
<button class="support-btn btn-default support-btn-primary" id="chatBtn">
<span id="chatBtnText">Previous lesson</span> </button>
<button class="support-btn support-btn-secondary" id="chatBtn">
<span id="chatBtnText">Take exam</span> </button>
<a href="#" class="support-btn btn-default support-btn-primary" id="emailBtn">
<span id="emailBtnText">Next lesson</span>
<!-- <span class="icon iconfont icon-arrow"></span> -->
</a>
</div>
</div>
<div class="support-visual">
<div class="support-glow">
<div class="support-icon">
<img src="../assets/images/backgrounds/greate-job-icon.webp" alt="Funded Trading" class="fade-in">
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="slice slice-lg" data-delimiter="1">
<div class="container">
<div class="mb-md text-center fade-in">
<h1 class="heading h1 fade-in">Ready to Begin?</h1>
<div class="fluid-paragraph text-center mt-4 fade-in">
<p class="lead lh-180">
Have you completed all the lessons and mindset training? If you're ready, join over<span class="text-orange">50,000</span> traders and take the free challenge today.
</p>
</div>
</div>
<div class="row text-center d-flex align-items-center justify-content-center">
<div class="mt-3"><a class="btn btn-default" href="#courses">Start Challenge</a></div>
</div>
</div>
</section>
<!-- Video Modal -->
<div class="modal fade" id="videoModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content" style="background:transparent;border:none;">
<div class="modal-body p-0">
<div id="videoContainer" style="position:relative;padding-top:56.25%;"></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 show">
<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 show">
<a href="#" class="btn btn-start-challenge 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;
// const stories = [
// {name:'Tim (USA)', text:"I've been trading for years and this is the best experience I've had.", img:'https://picsum.photos/id/1005/720/420'},
// {name:'Anna (FR)', text:'The curriculum is clear and practical — I improved fast.', img:'https://picsum.photos/id/1011/720/420'},
// {name:'Liu (CN)', text:'Hands-on tasks helped me build confidence.', img:'https://picsum.photos/id/1027/720/420'},
// {name:'Carlos (BR)', text:'Great community and feedback loops.', img:'https://picsum.photos/id/1025/720/420'}
// ];
// const $track = $('#growthTrack').empty();
// stories.forEach((s,i)=>{
// const $card = $(`
// <div class="growth-card" data-i="${i}">
// <img loading="lazy" src="${s.img}" alt="${s.name}">
// <strong style="display:block;margin-bottom:0.5rem">${s.name}</strong>
// <p style="font-size:0.875rem;color:rgba(255,255,255,0.9)">${s.text}</p>
// </div>
// `);
// $track.append($card);
// });
// dots
// const $dots = $('#growthDots').empty();
// stories.forEach((_,i)=> $dots.append(`<button class="btn btn-sm" data-i="${i}" style="margin:6px;background:transparent;border:1px solid rgba(255,255,255,0.06);color:#fff">${i+1}</button>`));
// initGrowthCarousel();
}
/* ========== 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);
/* =========================
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>
/* ===========================================================
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
=========================================================== */
</script>
<script>
$(function () {
const tocDesktop = $("#generated-toc");
const tocMobile = $("#generated-toc-mobile");
const articleBox = $(".article-content"); // scrollable content area
/* ===========================
Auto-generate table of contents
============================ */
$(".article-content h1, .article-content h2").each(function (index, item) {
const tag = $(this).prop("tagName").toLowerCase();
const text = $(this).text();
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, "-");
$(this).attr("id", id);
$is_active = "";
if (index === 0) {
$is_active = "active";
}
const tocitem = `
<li class="toc-item ${$is_active}">
<a href="#${id}" class="toc-link toc-name" style="margin-left:${tag === 'h2' ? '15px' : '0'}">${text}</a>
</li>
`;
tocDesktop.append(tocitem);
tocMobile.append(tocitem);
initTableOfContents();
updateProgressIndicator(0);
});
/* ===========================
TOC click => scroll article_content only
Completely disable browser default jump
============================ */
$(document).on("click", ".toc-link", function (e) {
e.preventDefault();
e.stopPropagation();
const targetId = $(this).attr("href");
const targetElement = document.querySelector(targetId);
if (targetElement) {
// 计算滚动位置,考虑97px的导航栏
const targetPosition = targetElement.getBoundingClientRect().top;
const offsetPosition = targetPosition + window.pageYOffset - 97;
// 平滑滚动到计算后的位置
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
return false;
});
/* ===========================
Mobile TOC expand
============================ */
$(".toc-mobile-toggle").click(function () {
$(".toc-mobile").slideToggle(180);
});
});
</script>
<script>
// Default configuration
const defaultConfigContent = {
hero_tag: '2.2.5',
hero_title_line1: 'Strength',
hero_title_line2: 'indicators CCI',
section_subtitle: 'Every successful trader begins with a clear path. Our course guides you toward funded success.',
primary_color: '#F98715',
background_color: '#0B0B0B',
text_color: '#F9F9F9',
surface_color: '#141414',
font_family: 'Inter'
};
// 检测移动端并禁用固定工作台
function detectMobileAndDisableLock() {
const isMobile = window.innerWidth < 992;
if (isMobile) {
document.body.classList.add('mobile-mode');
// 确保body可以正常滚动
document.body.style.overflow = '';
document.body.style.height = '';
} else {
document.body.classList.remove('mobile-mode');
}
return isMobile;
}
// Generate watermark pattern
// function generateWatermark() {
// const watermark = document.getElementById('watermark');
// const text = 'CREATED BY AIFO ACADEMY';
// let html = '';
// for (let i = 0; i < 20; i++) {
// for (let j = 0; j < 10; j++) {
// const top = i * 120 - 200;
// const left = j * 350 - 200;
// html += `<span class="watermark-text" style="top: ${top}px; left: ${left}px;">${text}</span>`;
// }
// }
// watermark.innerHTML = html;
// }
// Smooth scroll to sections - 在锁定状态下滚动中间正文
function initTableOfContents() {
const tocItems = document.querySelectorAll('.toc-item');
const mainContent = document.querySelector('.main-content');
const tocList = document.getElementById('#generated-toc');
tocItems.forEach((item, index) => {
item.addEventListener('click', function() {
tocItems.forEach(i => i.classList.remove('active'));
this.classList.add('active');
// 更新橘色高亮段位置
// updateProgressIndicator(index);
// const targetId = `section-${index + 1}`;
// const target = document.getElementById(targetId);
// if (target && mainContent) {
// // 如果在锁定状态,滚动中间正文容器
// const courseStructure = document.querySelector('.course-structure');
// if (courseStructure && courseStructure.classList.contains('cs-fixed')) {
// const targetPosition = target.offsetTop - 20;
// mainContent.scrollTo({
// top: targetPosition,
// behavior: 'smooth'
// });
// } else {
// // 否则正常页面滚动
// const offset = 160;
// const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - offset;
// window.scrollTo({
// top: targetPosition,
// behavior: 'smooth'
// });
// }
// }
});
});
// 监听中间正文滚动,更新左侧目录高亮
if (mainContent) {
mainContent.addEventListener('scroll', function() {
updateTocHighlight();
});
}
}
// 更新橘色进度指示器位置
function updateProgressIndicator(activeIndex) {
const tocList = document.getElementById('generated-toc');
if (!tocList) return;
const itemHeight = 44;
const translateY = activeIndex * itemHeight;
const style = document.createElement('style');
style.textContent = `
.toc-list::after {
transform: translateY(${translateY}px);
}
`;
const oldStyle = document.getElementById('toc-progress-style');
if (oldStyle) oldStyle.remove();
style.id = 'toc-progress-style';
document.head.appendChild(style);
}
// 更新目录高亮
function updateTocHighlight() {
const courseStructure = document.querySelector('.course-structure');
if (!courseStructure || !courseStructure.classList.contains('cs-fixed')) {
return;
}
const mainContent = document.querySelector('.main-content');
const tocItems = document.querySelectorAll('.toc-item');
const sections = document.querySelectorAll('.article-content h2[id]');
let currentSectionIndex = 0;
sections.forEach((section, index) => {
const rect = section.getBoundingClientRect();
const mainRect = mainContent.getBoundingClientRect();
if (rect.top >= mainRect.top && rect.top <= mainRect.top + 200) {
currentSectionIndex = index;
}
});
tocItems.forEach((item, index) => {
if (index === currentSectionIndex) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
updateProgressIndicator(currentSectionIndex);
}
// Tab functionality
document.addEventListener('DOMContentLoaded', function() {
const lessonItems = document.querySelectorAll('.lesson-item');
lessonItems.forEach(lesson => {
lesson.addEventListener('click', function() {
lessonItems.forEach(l => l.classList.remove('active'));
this.classList.add('active');
});
});
// generateWatermark();
// 检测是否为移动端
const isMobile = detectMobileAndDisableLock();
// 只在桌面端初始化固定工作台
// if (!isMobile) {
// initCourseStructureLock();
// }
// 监听窗口大小变化
// window.addEventListener('resize', function() {
// detectMobileAndDisableLock();
// });
// updateProgressIndicator(0);
});
// Course Structure 区域滚动锁定(仅桌面端)
let isLocked = false;
function initCourseStructureLock() {
const courseStructure = document.querySelector('.course-structure');
const mainContent = document.querySelector('.main-content');
const body = document.body;
let triggerPoint = 0;
function updateTriggerPoint() {
if (courseStructure) {
triggerPoint = courseStructure.offsetTop;
}
}
updateTriggerPoint();
window.addEventListener('scroll', function() {
// 只在桌面端执行锁定逻辑
if (window.innerWidth < 992) return;
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop >= triggerPoint && !isLocked) {
lockCourseStructure();
}
});
if (mainContent) {
mainContent.addEventListener('scroll', function() {
checkUnlock();
});
}
function lockCourseStructure() {
isLocked = true;
courseStructure.classList.add('cs-fixed');
body.style.overflow = 'hidden';
body.style.height = '100vh';
mainContent.scrollTop = 0;
}
function checkUnlock() {
if (!isLocked) return;
const scrollTop = mainContent.scrollTop;
const scrollHeight = mainContent.scrollHeight;
const clientHeight = mainContent.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10) {
unlockCourseStructure();
}
}
window.unlockCourseStructure = function() {
isLocked = false;
courseStructure.classList.remove('cs-fixed');
body.style.overflow = '';
body.style.height = '';
};
}
// Element SDK Integration
async function onConfigChange(config) {
const heroTag = document.getElementById('heroTag');
const heroTitleLine1 = document.getElementById('heroTitleLine1');
const heroTitleLine2 = document.getElementById('heroTitleLine2');
const sectionSubtitle = document.getElementById('sectionSubtitle');
if (heroTag) heroTag.textContent = config.hero_tag || defaultConfigContent.hero_tag;
if (heroTitleLine1) heroTitleLine1.textContent = config.hero_title_line1 || defaultConfigContent.hero_title_line1;
if (heroTitleLine2) heroTitleLine2.textContent = config.hero_title_line2 || defaultConfigContent.hero_title_line2;
if (sectionSubtitle) sectionSubtitle.textContent = config.section_subtitle || defaultConfigContent.section_subtitle;
const primaryColor = config.primary_color || defaultConfigContent.primary_color;
document.documentElement.style.setProperty('--primary-orange', primaryColor);
const fontFamily = config.font_family || defaultConfigContent.font_family;
document.body.style.fontFamily = `${fontFamily}, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, "Helvetica Neue", sans-serif`;
}
function mapToCapabilities(config) {
return {
recolorables: [
{
get: () => config.primary_color || defaultConfigContent.primary_color,
set: (value) => {
config.primary_color = value;
window.elementSdk.setConfig({ primary_color: value });
}
}
],
borderables: [],
fontEditable: {
get: () => config.font_family || defaultConfigContent.font_family,
set: (value) => {
config.font_family = value;
window.elementSdk.setConfig({ font_family: value });
}
},
fontSizeable: undefined
};
}
function mapToEditPanelValues(config) {
return new Map([
['hero_tag', config.hero_tag || defaultConfigContent.hero_tag],
['hero_title_line1', config.hero_title_line1 || defaultConfigContent.hero_title_line1],
['hero_title_line2', config.hero_title_line2 || defaultConfigContent.hero_title_line2],
['section_subtitle', config.section_subtitle || defaultConfigContent.section_subtitle]
]);
}
if (window.elementSdk) {
window.elementSdk.init({
defaultConfigContent,
onConfigChange,
mapToCapabilities,
mapToEditPanelValues
});
}
</script>
</html>