1- // Initialize Animate On Scroll
2- AOS . init ( {
3- once : true ,
4- offset : 50 ,
5- duration : 1000 ,
6- easing : 'ease-out-cubic' ,
7- } ) ;
8-
9- // Theme System
10- const themeToggle = document . getElementById ( 'themeToggle' ) ;
11- const html = document . documentElement ;
12- const icon = themeToggle ? themeToggle . querySelector ( 'span' ) : null ;
13-
14- // Check saved preference or default to dark
15- const savedTheme = localStorage . getItem ( 'theme' ) || 'dark' ;
16- html . setAttribute ( 'data-theme' , savedTheme ) ;
17- updateThemeIcon ( savedTheme ) ;
18-
19- if ( themeToggle ) {
20- themeToggle . addEventListener ( 'click' , ( ) => {
21- const currentTheme = html . getAttribute ( 'data-theme' ) ;
22- const newTheme = currentTheme === 'light' ? 'dark' : 'light' ;
23-
24- html . setAttribute ( 'data-theme' , newTheme ) ;
25- localStorage . setItem ( 'theme' , newTheme ) ;
26- updateThemeIcon ( newTheme ) ;
1+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
2+ // Initialize Animate On Scroll
3+ AOS . init ( {
4+ once : true ,
5+ offset : 50 ,
6+ duration : 1000 ,
7+ easing : 'ease-out-cubic' ,
278 } ) ;
28- }
29-
30- function updateThemeIcon ( theme ) {
31- if ( ! icon ) return ;
32- icon . textContent = theme === 'light' ? '🌙' : '☀️' ;
33- }
349
35- // Gravity Cursor Logic
36- const cursorDot = document . querySelector ( '.cursor-dot' ) ;
37- const cursorOutline = document . querySelector ( '.cursor-outline' ) ;
38-
39- let mouseX = 0 ;
40- let mouseY = 0 ;
41- let cursorX = 0 ;
42- let cursorY = 0 ;
43-
44- document . addEventListener ( 'mousemove' , ( e ) => {
45- mouseX = e . clientX ;
46- mouseY = e . clientY ;
47-
48- // Instant follow for dot
49- cursorDot . style . left = mouseX + 'px' ;
50- cursorDot . style . top = mouseY + 'px' ;
51- } ) ;
52-
53- function animateCursor ( ) {
54- // Heavy Lerp for "Gravity" feel
55- const speed = 0.1 ;
56- cursorX += ( mouseX - cursorX ) * speed ;
57- cursorY += ( mouseY - cursorY ) * speed ;
58-
59- cursorOutline . style . left = cursorX + 'px' ;
60- cursorOutline . style . top = cursorY + 'px' ;
61-
62- requestAnimationFrame ( animateCursor ) ;
63- }
64-
65- animateCursor ( ) ;
66-
67- // Magnetic Pull Effect
68- const magnets = document . querySelectorAll ( 'a, button, .feature-card, .config-input' ) ;
69-
70- magnets . forEach ( magnet => {
71- magnet . addEventListener ( 'mousemove' , ( e ) => {
72- const rect = magnet . getBoundingClientRect ( ) ;
73- const centerX = rect . left + rect . width / 2 ;
74- const centerY = rect . top + rect . height / 2 ;
10+ // Theme System
11+ const themeToggle = document . getElementById ( 'themeToggle' ) ;
12+ const html = document . documentElement ;
13+ const icon = themeToggle ? themeToggle . querySelector ( 'span' ) : null ;
14+
15+ // Check saved preference or default to dark
16+ let savedTheme = 'dark' ;
17+ try {
18+ savedTheme = localStorage . getItem ( 'theme' ) || 'dark' ;
19+ } catch ( e ) {
20+ console . warn ( 'LocalStorage access denied' , e ) ;
21+ }
7522
76- // Calculate distance from center
77- const distX = e . clientX - centerX ;
78- const distY = e . clientY - centerY ;
23+ html . setAttribute ( 'data-theme' , savedTheme ) ;
24+ updateThemeIcon ( savedTheme ) ;
7925
80- // Pull the element towards the mouse (Magnetic effect)
81- // Divide by a factor to control strength (higher = weaker)
82- magnet . style . transform = `translate(${ distX / 5 } px, ${ distY / 5 } px)` ;
26+ if ( themeToggle ) {
27+ themeToggle . addEventListener ( 'click' , ( ) => {
28+ const currentTheme = html . getAttribute ( 'data-theme' ) ;
29+ const newTheme = currentTheme === 'light' ? 'dark' : 'light' ;
8330
84- // Expand cursor
85- cursorOutline . style . width = '60px' ;
86- cursorOutline . style . height = '60px' ;
87- cursorOutline . style . backgroundColor = 'rgba(255, 255, 255, 0.05)' ;
88- } ) ;
31+ html . setAttribute ( 'data-theme' , newTheme ) ;
32+ try {
33+ localStorage . setItem ( 'theme' , newTheme ) ;
34+ } catch ( e ) { }
35+ updateThemeIcon ( newTheme ) ;
36+ } ) ;
37+ }
8938
90- magnet . addEventListener ( 'mouseleave' , ( ) => {
91- // Reset position
92- magnet . style . transform = 'translate(0, 0)' ;
39+ function updateThemeIcon ( theme ) {
40+ if ( ! icon ) return ;
41+ icon . textContent = theme === 'light' ? '🌙' : '☀️' ;
42+ }
9343
94- // Reset cursor
95- cursorOutline . style . width = '40px' ;
96- cursorOutline . style . height = '40px' ;
97- cursorOutline . style . backgroundColor = 'transparent' ;
98- } ) ;
99- } ) ;
44+ // Fluid Cursor Logic (Reverted to Phase 12 - Lighter, No Magnet)
45+ const cursorDot = document . querySelector ( '.cursor-dot' ) ;
46+ const cursorOutline = document . querySelector ( '.cursor-outline' ) ;
47+
48+ if ( cursorDot && cursorOutline ) {
49+ let mouseX = 0 ;
50+ let mouseY = 0 ;
51+ let cursorX = 0 ;
52+ let cursorY = 0 ;
53+
54+ document . addEventListener ( 'mousemove' , ( e ) => {
55+ mouseX = e . clientX ;
56+ mouseY = e . clientY ;
57+
58+ // Instant follow for dot
59+ cursorDot . style . left = mouseX + 'px' ;
60+ cursorDot . style . top = mouseY + 'px' ;
61+ } ) ;
62+
63+ function animateCursor ( ) {
64+ // Lighter Lerp (Phase 12 feel)
65+ const speed = 0.2 ;
66+ cursorX += ( mouseX - cursorX ) * speed ;
67+ cursorY += ( mouseY - cursorY ) * speed ;
68+
69+ cursorOutline . style . left = cursorX + 'px' ;
70+ cursorOutline . style . top = cursorY + 'px' ;
71+
72+ requestAnimationFrame ( animateCursor ) ;
73+ }
74+
75+ animateCursor ( ) ;
76+
77+ // Simple Hover Effect (No Magnetic Pull)
78+ const interactiveElements = document . querySelectorAll ( 'a, button, .feature-card, .config-input, select, label' ) ;
79+
80+ interactiveElements . forEach ( el => {
81+ el . addEventListener ( 'mouseenter' , ( ) => {
82+ cursorOutline . style . width = '60px' ;
83+ cursorOutline . style . height = '60px' ;
84+ cursorOutline . style . backgroundColor = 'rgba(255, 255, 255, 0.1)' ;
85+ } ) ;
86+
87+ el . addEventListener ( 'mouseleave' , ( ) => {
88+ cursorOutline . style . width = '40px' ;
89+ cursorOutline . style . height = '40px' ;
90+ cursorOutline . style . backgroundColor = 'transparent' ;
91+ } ) ;
92+ } ) ;
93+ }
10094
101- // Interactive Configurator
102- const configName = document . getElementById ( 'configName' ) ;
103- const configSecurity = document . getElementById ( 'configSecurity' ) ;
104- const configLogging = document . getElementById ( 'configLogging' ) ;
105- const codeBlock = document . getElementById ( 'generatedCode' ) ;
95+ // Interactive Configurator
96+ const configName = document . getElementById ( 'configName' ) ;
97+ const configSecurity = document . getElementById ( 'configSecurity' ) ;
98+ const configLogging = document . getElementById ( 'configLogging' ) ;
99+ const codeBlock = document . getElementById ( 'generatedCode' ) ;
106100
107- if ( configName && configSecurity && configLogging && codeBlock ) {
108- function updateCode ( ) {
109- const name = configName . value || 'My-ESP32' ;
110- const security = configSecurity . value ;
111- const logging = configLogging . checked ;
101+ if ( configName && configSecurity && configLogging && codeBlock ) {
102+ function updateCode ( ) {
103+ const name = configName . value || 'My-ESP32' ;
104+ const security = configSecurity . value ;
105+ const logging = configLogging . checked ;
112106
113- const code = `#include <WiBLE.h>
107+ const code = `#include <WiBLE.h>
114108
115109WiBLE provisioner;
116110
@@ -128,10 +122,14 @@ void setup() {
128122void loop() {
129123 provisioner.loop();
130124}` ;
131- codeBlock . textContent = code ;
132- }
125+ codeBlock . textContent = code ;
126+ }
133127
134- configName . addEventListener ( 'input' , updateCode ) ;
135- configSecurity . addEventListener ( 'change' , updateCode ) ;
136- configLogging . addEventListener ( 'change' , updateCode ) ;
137- }
128+ configName . addEventListener ( 'input' , updateCode ) ;
129+ configSecurity . addEventListener ( 'change' , updateCode ) ;
130+ configLogging . addEventListener ( 'change' , updateCode ) ;
131+
132+ // Run once to set initial state
133+ updateCode ( ) ;
134+ }
135+ } ) ;
0 commit comments