1// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails 2import "@hotwired/turbo-rails" 3import "controllers" 4import "add_jquery" 5import "@barba/core" 6 7document.addEventListener("turbo:load", () => { 8 9 barba.init({ 10 debug: false, 11 preventRunning: true, 12 13 transitions: [ 14 { 15 name: 'slide', 16 17 leave(data) { 18 // console.log('leave') 19 20 return new Promise(resolve => { 21 const timeline = gsap.timeline({ 22 onComplete() { 23 resolve() 24 } 25 }) 26 27 timeline 28 .fromTo($('section.dark'), {opacity: '0'}, {opacity: '1', duration: 0.5, ease: "power3", delay: 0}, 0) 29 }) 30 }, 31 32 after(data) { 33 // console.log('enter') 34 projectPanelHeight() 35 36 // reset page positioning 37 window.scrollTo({ 38 top: 0, 39 behavior: "auto" 40 }); 41 42 // Load animation on background image 43 listenImageLoad() 44 45 data.current.container.remove(); 46 const timeline = gsap.timeline() 47 48 timeline 49 .fromTo($('section.dark'), {opacity: '1'}, {opacity: '0', duration: 2, ease: "power3", delay: 0}, 0) 50 .to($('header'), {color: 'white', duration: 2, ease: "power3", delay: 0}, 0) 51 .to($('header .tag'), {borderColor: 'white', duration: 2, ease: "power3", delay: 0}, 0) 52 53 } 54 }, 55 56 // When leaving home, force close the menu 57 { 58 name: "toHome", 59 60 leave(data) { 61 62 return new Promise(resolve => { 63 const timeline = gsap.timeline({ 64 onComplete() { 65 resolve() 66 } 67 }) 68 69 timeline 70 .to($('.landing .white-bar'), {display: 'block'}) 71 .to($('header'), {mixBlendMode: 'difference'}, 0) 72 .to($('section.landing'), {zIndex: '2', duration: 0, ease: "power3", delay: 0}, 0) 73 .fromTo($('section.landing'), {y: '100vh'}, {y: '0vh', duration: 0.4, ease: "power3", delay: 0}, 0) 74 // .to($('header'), {color: 'blue', duration: 0.4, ease: "power3", delay: 0}, 0) 75 // .to($('header .tag'), {borderColor: 'blue', duration: 0.4, ease: "power3", delay: 0}, 0) 76 }) 77 }, 78 79 beforeEnter(data) { 80 // console.log('enter') 81 projectPanelHeight() 82 83 // reset page positioning 84 window.scrollTo({ 85 top: 0, 86 behavior: "auto" 87 }); 88 89 data.current.container.remove(); 90 const timeline = gsap.timeline() 91 92 timeline 93 .to($('section.landing'), {zIndex: '-1', duration: 0, ease: "power3", delay: 0}, 0) 94 .fromTo($('section.about'), {y: '4rem'}, {y: '0', duration: 0.4, ease: "back", delay: 0}, 0) 95 .fromTo($('section.websites'), {y: '4rem'}, {y: '0', duration: 0.4, ease: "back", delay: 0.1}, 0) 96 .fromTo($('section.projects'), {y: '4rem'}, {y: '0', duration: 0.4, ease: "back", delay: 0.2}, 0) 97 .to($('.landing .white-bar'), {display: 'none'}, 0) 98 }, 99 100 to: { 101 namespace: [ 102 'home' 103 ] 104 } 105 106 } 107 108 ], 109 110 views: [ 111 112 { 113 namespace: "home", 114 115 afterEnter() { 116 117 // Scroll to sections 118 $('#about').click(function() { 119 $('html, body').animate({ 120 scrollTop: $('#about').offset().top 121 }, 700); 122 }) 123 124 $('#websites').click(function() { 125 $('html, body').animate({ 126 scrollTop: $('#websites').offset().top + $('section.about').height() 127 }, 700); 128 }) 129 130 $('#projects').click(function() { 131 if (($('#projects').offset().top - $('#about').offset().top) < 100) { 132 $('html, body').animate({ 133 scrollTop: $('#projects').offset().top + $('section.about').height() - $('#projects').height() 134 }, 1000); 135 } else { 136 $('html, body').animate({ 137 scrollTop: $('#projects').offset().top 138 }, 1000); 139 } 140 }) 141 142 } 143 }, 144 145 { 146 namespace: "project", 147 148 afterEnter() { 149 150 $('header').css({'color': 'white', 'mixBlendMode': 'difference'}) 151 $('header .tag').css('borderColor', 'white') 152 153 listenImageLoad() 154 155 document.querySelectorAll('video').forEach(video => { 156 video.play() 157 }) 158 159 } 160 } 161 162 ] 163 }) 164 165 function projectPanelHeight() { 166 // Set bottom value of project panel depending on it's height 167 let projectPanel = $('section.projects')
168 let projectHeight = projectPanel.innerHeight() 169 projectHeight = -Math.abs(projectHeight) 170 171 172 // Set bottom value of project panel depending on it's height 173 let websitesPanel = $('section.websites') 174 let websitesHeight = websitesPanel.innerHeight() 175 websitesHeight = -Math.abs(websitesHeight) 176 // websitesHeight = websitesHeight + projectHeight 177 178 websitesPanel.css('bottom', 'calc(5.5rem + ' + websitesHeight + 'px)') 179 projectPanel.css('bottom', 'calc(2.75rem + ' + projectHeight + 'px)') 180 181 } 182 183 projectPanelHeight() 184 window.addEventListener('resize', function(event) { 185 projectPanelHeight() 186 }, true); 187 188 function listenImageLoad() { 189 var background = document.querySelector('.background'); 190 var image 191 var type 192 if (background.querySelector('img')) { 193 image = background.querySelector('img'); 194 type = 'image' 195 } else if (background.querySelector('video')) { 196 image = background.querySelector('video'); 197 type = 'video' 198 } 199 200 $(image).css('opacity', '0') 201 202 function handleImageLoad() { 203 // console.log('Image loaded!'); 204 $(image).css('opacity', '1') 205 } 206 207 if (type === 'image') { 208 if (image.complete) { 209 // Image has already loaded 210 handleImageLoad(); 211 } else { 212 // Add event listener for the "load" event 213 image.addEventListener('load', handleImageLoad); 214 } 215 } else if (type === 'video') { 216 if ( image.readyState === 4 ) { 217 // it's loaded 218 handleImageLoad(); 219 } else { 220 image.addEventListener('loadeddata', handleImageLoad); 221 } 222 223 } 224 225 } 226 227 // randomizeImages() 228 function randomizeImages() { 229 const landingArea = document.querySelector('.landing'); 230 const images = Array.from(document.querySelectorAll('.project-image')); 231 232 let currentIndex = images.length; 233 const clonedImages = []; 234 235 const intervalId = setInterval(() => { 236 if (currentIndex <= 0) { 237 clearInterval(intervalId); 238 return; 239 } 240 241 currentIndex--; 242 243 const randomIndex = Math.floor(Math.random() * (currentIndex + 1)); 244 const image = images[randomIndex]; 245 246 const randomX = Math.floor(Math.random() * (landingArea.offsetWidth - (window.innerWidth * 0.2))); 247 const randomY = Math.floor(Math.random() * (landingArea.offsetHeight - 180 - (((window.innerWidth * 0.2)*9) / 16))); 248 249 const clonedImage = image.cloneNode(); 250 clonedImage.style.position = 'absolute'; 251 clonedImage.style.left = `${randomX}px`; 252 clonedImage.style.top = `${randomY}px`; 253 254 clonedImage.addEventListener('click', () => { 255 clonedImage.style.display = 'none'; 256 }); 257 258 clonedImages.push(clonedImage); 259 260 document.querySelector('.landing-images').appendChild(clonedImage); 261 262 if (randomIndex !== currentIndex) { 263 images[randomIndex] = images[currentIndex]; 264 images[currentIndex] = image; 265 } 266 }, 10000); 267 } 268 269});
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.