1/** 2 * åºç¨å ¥å£ï¼åç ES Moduleï¼ 3 * 4 * å代åå ç <script src="main.js" defer>ã 5 * è´è´£ï¼çå¾ DOM â å è½½è§å¾ç段 â æåå§é¡ºåºåå§åååè½æ¨¡å â éèå è½½å¨ç»ã 6 * 7 * åå§å顺åºä¸å main.js ä¸ ErisPulseApp.init() ä¸¥æ ¼ä¸è´ï¼ä»¥ä¿è¯è¡ä¸ºä¸åã 8 */ 9 10import { I18n } from "./i18n.js"; 11import { loadUserSettings } from "./core/state.js"; 12import { loadViews } from "./core/views.js"; 13import * as settings from "./modules/settings.js"; 14import * as nav from "./modules/nav.js"; 15import * as market from "./modules/marketplace.js"; 16import * as docs from "./modules/docs.js"; 17import { renderFriendLinks, renderDependencies } from "./modules/about.js"; 18import * as home from "./modules/home.js"; 19import { SubmitModuleManager } from "./modules/submit.js"; 20import { CommunityManager } from "./modules/community.js"; 21import { AuthManager } from "./core/auth.js"; 22 23/** 24 * GitHub 飿 ¼ .md æ·±é¾å½ä¸åï¼ 25 * - https://www.erisdev.com/?md=api-reference/xxx.md 26 * ï¼Worker / 404.html éå®åè½ç¹ï¼æµè§å¨ä¼èªå¨ä¿çåå§ fragmentï¼ 27 * - https://www.erisdev.com/api-reference/xxx.md#ç« è 28 * ï¼SPA ç´æ¥æå¡è¯¥è·¯å¾æ¶çå åºï¼ 29 * ç»ä¸è½¬æ¢ä¸ºç«å è·¯ç± #docs/<path>#<section>ã 30 */ 31(function normalizeDocDeepLink() { 32 try { 33 let mdPath = null; 34 const params = new URLSearchParams(window.location.search); 35 36 if (params.has("md")) { 37 mdPath = (params.get("md") || "").replace(/^\/+/, ""); 38 params.delete("md"); 39 } else if (/\.md$/i.test(window.location.pathname)) { 40 mdPath = window.location.pathname.replace(/^\/+/, ""); 41 } 42 43 if (!mdPath) return; 44 45 const query = params.toString(); 46 const frag = window.location.hash.replace(/^#+/, ""); 47 let target = "/#docs/" + mdPath; 48 if (frag && !frag.startsWith("docs")) { 49 target += "#" + frag; 50 } 51 history.replaceState(null, "", "/" + (query ? "?" + query : "") + target); 52 } catch (e) { 53 console.warn("ææ¡£æ·±é¾å½ä¸å失败:", e); 54 } 55})(); 56 57/** 58 * Logo å¾çå è½½æ£æµï¼å è½½å®æåæ·¡å ¥ï¼å è½½ä¸æ¾ç¤ºæåå ä½ 59 */ 60(function setupLoaderLogo() { 61 const img = document.querySelector(".loader-icon"); 62 if (!img) return; 63 const reveal = () => img.classList.add("loaded"); 64 if (img.complete && img.naturalWidth > 0) reveal(); 65 else img.addEventListener("load", reveal, { once: true }); 66})(); 67 68/** 69 * çä»·äºå ErisPulseApp.init() 70 * 注æï¼setupStorage() ä¸ loadUserSettings() å¨åå®ç°ä¸åè½å®å ¨éå¤ï¼ 71 * æ¤å¤ä» è°ç¨ loadUserSettings() 䏿¬¡å³å¯è¾¾å°ç¸åææã 72 */ 73function runInit() { 74 I18n.init(); 75 loadUserSettings(); 76 settings.applyUserSettings(); 77 nav.registerServiceWorker(); 78 settings.setupThemeToggle(); 79 nav.setupHamburgerMenu(); 80 // è´¦æ·ä¸ç¤¾åºæ¨¡åå äºè§å¾åæ¢åå§åï¼ 81 // setupViewSwitching 伿 __INITIAL_VIEW__ 触å community è§å¾çæ°æ®å è½½ 82 AuthManager.init(); 83 SubmitModuleManager.init(); 84 CommunityManager.init(); 85 nav.setupViewSwitching(); 86 settings.setupGlobalLangSwitcher(); 87 market.setupMarketplace(); 88 docs.setupDocumentation(); 89 market.setupModals(); 90 settings.setupSettings(); 91 renderFriendLinks(); 92 renderDependencies(); 93 home.setupHomeAnimations(); 94 home.initBannerCarousel(); 95 home.initInstallOverlay(); 96 home.initHeroStats(); 97 home.initCommunityTeaser(); 98 nav.setupOnlineOffline(); 99} 100 101/** 102 * æ°æ³¡æ¡å¸¦æå¹ï¼æµ·ç»µå®å®é£æ ¼ï¼ï¼ 103 * 䏿¡æ°æ³¡å¸¦ä»åºé¨æ«åé¡¶é¨ï¼å¸¦ä¸æ¹ç页é¢éæ¥æç¤ºã 104 * æ°æ³¡å¸¦æå¯è§è½®å» + é«å ï¼æ¶æåæ¶å¤±ã 105 */ 106function hideLoader() { 107 const loader = document.getElementById("page-loader"); 108 if (!loader) return; 109 const reduceMotion = 110 document.body.classList.contains("no-animations") || 111 window.matchMedia("(prefers-reduced-motion: reduce)").matches; 112 if (reduceMotion) { 113 loader.style.display = "none"; 114 return; 115 } 116 117 const W = window.innerWidth; 118 const H = window.innerHeight; 119 120 const canvas = document.createElement("canvas"); 121 canvas.className = "reveal-bubble"; 122 canvas.width = W; 123 canvas.height = H; 124 const ctx = canvas.getContext("2d"); 125 document.body.appendChild(canvas); 126 127 const css = getComputedStyle(document.documentElement); 128 const bgRGB = css.getPropertyValue("--bg-rgb").trim(); 129 const pRGB = css.getPropertyValue("--primary-rgb").trim(); 130 131 loader.style.display = "none"; 132 133 // æ°æ³¡æ¡å¸¦é ç½® 134 const bandH = 120; 135 const softEdge = 45; 136 const bubbles = []; 137 for (let i = 0; i < 70; i++) { 138 bubbles.push({ 139 x: Math.random() * W, 140 yOff: (Math.random() - 0.5) * bandH, 141 r: 2 + Math.random() * 16, 142 wobble: Math.random() * Math.PI * 2, 143 wSpeed: 0.001 + Math.random() * 0.002, 144 alpha: 0.5 + Math.random() * 0.5, 145 }); 146 } 147 148 const duration = 750; 149 const startT = performance.now(); 150 151 function frame(now) { 152 const t = Math.min(1, (now - startT) / duration); 153 // easeInOutCubic 154 const eased = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; 155 156 // æ¡å¸¦ä¸å¿ä»åºé¨æ«åé¡¶é¨ 157 const sweepY = H + bandH - eased * (H + bandH * 2); 158
159 // æ¶æï¼æå 30% æ°æ³¡åä¸å¿æ±èãç¼©å° 160 const converge = Math.max(0, (t - 0.7) / 0.3); 161 162 ctx.clearRect(0, 0, W, H); 163 164 // å®å¿å¡«å ï¼æ¡å¸¦ä¸æ¹è¦ç页é¢ï¼ 165 const opaqueEnd = sweepY - softEdge; 166 if (opaqueEnd > 0) { 167 ctx.fillStyle = `rgb(${bgRGB})`; 168 ctx.fillRect(0, 0, W, Math.min(H, opaqueEnd)); 169 } 170 171 // è½¯è¾¹ç¼æ¸åï¼æ¡å¸¦ä¸æ²¿ï¼ 172 if (sweepY > -softEdge && opaqueEnd < H) { 173 const gTop = Math.max(0, sweepY - softEdge); 174 const gBot = Math.min(H, sweepY + softEdge); 175 if (gBot > gTop) { 176 const grad = ctx.createLinearGradient(0, sweepY - softEdge, 0, sweepY + softEdge); 177 grad.addColorStop(0, `rgba(${bgRGB}, 1)`); 178 grad.addColorStop(1, `rgba(${bgRGB}, 0)`); 179 ctx.fillStyle = grad; 180 ctx.fillRect(0, gTop, W, gBot - gTop); 181 } 182 } 183 184 // æ°æ³¡ï¼æ²¿æ¡å¸¦åå¸ï¼å¯è§è½®å» + é«å ï¼ 185 for (const b of bubbles) { 186 const yOff = b.yOff * (1 - converge * 0.7); 187 const r = b.r * (1 - converge * 0.5); 188 if (r < 2) continue; 189 const bx = b.x + Math.sin(now * b.wSpeed + b.wobble) * 6; 190 const by = sweepY + yOff + Math.cos(now * b.wSpeed + b.wobble) * 4; 191 if (by + r < 0 || by - r > H) continue; 192 193 // å¡«å ï¼ææ·¡è¥çèï¼ 194 ctx.fillStyle = `rgba(255, 255, 255, ${0.03 * b.alpha})`; 195 ctx.beginPath(); 196 ctx.arc(bx, by, r, 0, Math.PI * 2); 197 ctx.fill(); 198 199 // è½®å»ï¼ç»çº¿ï¼ 200 ctx.strokeStyle = `rgba(${pRGB}, ${0.12 * b.alpha})`; 201 ctx.lineWidth = 0.8; 202 ctx.stroke(); 203 204 // é«å ï¼ä» è¾å¤§æ°æ³¡æ³¡ï¼ 205 if (r > 4) { 206 ctx.fillStyle = `rgba(255, 255, 255, ${0.2 * b.alpha})`; 207 ctx.beginPath(); 208 ctx.arc(bx - r * 0.3, by - r * 0.3, Math.max(1, r * 0.15), 0, Math.PI * 2); 209 ctx.fill(); 210 } 211 } 212 213 if (t < 1) { 214 requestAnimationFrame(frame); 215 } else { 216 canvas.remove(); 217 } 218 } 219 requestAnimationFrame(frame); 220} 221 222/** 223 * å¯å¨æµç¨ï¼å è½½è§å¾ â åå§å模å â éèå è½½å¨ç» 224 */ 225async function bootstrap() { 226 try { 227 await loadViews(); 228 runInit(); 229 } catch (err) { 230 console.error("Failed to bootstrap application:", err); 231 } finally { 232 // å³ä½¿åå§å失败ä¹è¦éèå è½½å±ï¼é¿å å¡å¨ç©ºç½é®ç½© 233 // çå¾ ä¸¤å¸§ç¡®ä¿ DOM å·²ç»å¶ï¼åå¼å§æ³¢æµªéæ½® 234 requestAnimationFrame(() => requestAnimationFrame(hideLoader)); 235 } 236} 237 238/** 239 * module script é»è®¤ deferï¼æ§è¡æ¶ DOM 已解æå®æï¼ 240 * ä½ç¨³å¦¥èµ·è§ä»æ£æ¥ readyStateã 241 */ 242function start() { 243 bootstrap(); 244} 245 246if (document.readyState === "loading") { 247 document.addEventListener("DOMContentLoaded", start); 248} else { 249 start(); 250}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.