{"mappings":"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","sources":["node_modules/@babel/runtime/helpers/interopRequireDefault.js","node_modules/@babel/runtime/helpers/classCallCheck.js","node_modules/@babel/runtime/helpers/createClass.js","src/index.js"],"names":["$beac7a8bc05e3108fe09f48d4fc35ffb$exports","obj","__esModule","default","instance","Constructor","TypeError","_defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","key","phrases","el","fx","counter","protoProps","staticProps","prototype","TextScrambler","$b350cd9db4549ae05bfb23b905ede80$var$_classCallCheck2","this","chars","update","bind","newText","_this","oldText","innerText","Math","max","promise","Promise","resolve","queue","from","to","start","floor","random","end","push","cancelAnimationFrame","frameRequest","frame","output","complete","n","_this$queue$i","char","randomChar","concat","innerHTML","requestAnimationFrame","Nav","func","limit","lastFunc","lastRan","navHeight","document","querySelector","getBoundingClientRect","height","mainNavLinks","querySelectorAll","window","addEventListener","fromTop","scrollY","prevSectionEnd","hash","offsetTop","link","section","sectionEnd","offsetHeight","classList","add","remove","context","args","arguments","clearTimeout","setTimeout","Date","now","apply","next","setText","then","ContactForm","contactForm","span","createElement","appendChild","charWidth","width","_i","_lineviews","Array","lineview","addLineViewListeners","lineviewContent","contentEditable","cursorPos","offset","range","createRange","sel","getSelection","setStart","childNodes","collapse","removeAllRanges","addRange","focus","parentNode","style","setProperty","_this2","e","handleLineViewKeyDown","handleLineViewClick","handleLineViewFocusIn","handleLineViewFocusOut","newCursorOffset","stepDiv","currentCursorOffset","parseFloat","getPropertyValue","inputWidth","min","prevLineviewContent","preventDefault","previousSibling","contains","round","previousStepDiv","closest","prevStepLineviews","activateLineView","nextLineviewContent","nextSibling","createLineView","after","nextStep","display","offsetX","editableDiv","caretPos","rangeCount","getRangeAt","commonAncestorContainer","endOffset","selection","parentElement","tempEl","insertBefore","firstChild","tempRange","duplicate","moveToElementText","setEndPoint","text","getCaretPosition","getElementById"],"version":3,"file":"repo.1259948f.js.map","sourcesContent":["function _interopRequireDefault(obj) {\n return obj && obj.__esModule ? obj : {\n \"default\": obj\n };\n}\n\nmodule.exports = _interopRequireDefault;","function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\nmodule.exports = _classCallCheck;","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\n\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\nmodule.exports = _createClass;","class TextScrambler {\n constructor(el) {\n this.el = el\n this.chars = '!<>-_\\\\/[]{}—=+*^?#________'\n this.update = this.update.bind(this)\n }\n\n setText(newText) {\n const oldText = this.el.innerText\n const length = Math.max(oldText.length, newText.length)\n const promise = new Promise((resolve) => this.resolve = resolve)\n this.queue = []\n for (let i = 0; i < length; i++) {\n const from = oldText[i] || ''\n const to = newText[i] || ''\n const start = Math.floor(Math.random() * 40)\n const end = start + Math.floor(Math.random() * 40)\n this.queue.push({ from, to, start, end })\n }\n cancelAnimationFrame(this.frameRequest)\n this.frame = 0\n this.update()\n return promise\n }\n\n update() {\n let output = ''\n let complete = 0\n for (let i = 0, n = this.queue.length; i < n; i++) {\n let { from, to, start, end, char } = this.queue[i]\n if (this.frame >= end) {\n complete++\n output += to\n } else if (this.frame >= start) {\n if (!char || Math.random() < 0.28) {\n char = this.randomChar()\n this.queue[i].char = char\n }\n output += `${char}`\n } else {\n output += from\n }\n }\n this.el.innerHTML = output\n if (complete === this.queue.length) {\n this.resolve()\n } else {\n this.frameRequest = requestAnimationFrame(this.update)\n this.frame++\n }\n }\n\n randomChar() {\n return this.chars[Math.floor(Math.random() * this.chars.length)]\n }\n}\n\nconst throttle = (func, limit) => {\n let lastFunc;\n let lastRan;\n return function() {\n const context = this;\n const args = arguments;\n if (!lastRan) {\n func.apply(context, args);\n lastRan = Date.now();\n } else {\n clearTimeout(lastFunc);\n lastFunc = setTimeout(function() {\n if ((Date.now() - lastRan) >= limit) {\n func.apply(context, args);\n lastRan = Date.now();\n }\n }, limit - (Date.now() - lastRan));\n }\n }\n}\n\nclass Nav {\n constructor() {\n const navHeight = document.querySelector(\".nav\").getBoundingClientRect().height;\n const mainNavLinks = document.querySelectorAll(\".nav .sections a\");\n\n window.addEventListener(\"scroll\", throttle(() => {\n\n const fromTop = window.scrollY;\n\n let prevSectionEnd = document.querySelector(mainNavLinks[0].hash).offsetTop - navHeight\n for (let i = 0; i < mainNavLinks.length; i++) {\n const link = mainNavLinks[i];\n \n const section = document.querySelector(link.hash);\n const sectionEnd = section.offsetTop - navHeight + section.offsetHeight\n\n if (\n prevSectionEnd <= fromTop &&\n sectionEnd > fromTop\n ) {\n link.classList.add(\"active\");\n } else {\n link.classList.remove(\"active\");\n }\n\n prevSectionEnd = sectionEnd\n }\n }, 100));\n }\n}\n\n(function() {\n const phrases = [\n \"I'm a Software Engineer.\",\n \"I love solving problems \",\n \"and learning new things!\",\n ]\n\n const el = document.querySelector('.text')\n const fx = new TextScrambler(el)\n\n let counter = 0\n const next = () => {\n fx.setText(phrases[counter]).then(() => {\n setTimeout(next, 800)\n })\n counter = (counter + 1) % phrases.length\n }\n \n next()\n\n new Nav()\n})();\n\nclass ContactForm {\n constructor(contactForm) {\n this.contactForm = contactForm\n\n // Figure out letter width\n const span = document.createElement('span')\n span.innerText = 'a'\n contactForm.appendChild(span)\n\n this.charWidth = span.getBoundingClientRect().width\n span.remove()\n\n // Attach listeners to lineviews\n const lineviews = Array.from(contactForm.querySelectorAll('.input-lineview-content'))\n for (const lineview of lineviews) {\n this.addLineViewListeners(lineview)\n }\n }\n\n createLineView() {\n const lineview = document.createElement('div')\n lineview.classList.add('input-lineview')\n\n const lineviewContent = document.createElement('div')\n lineviewContent.classList.add('input-lineview-content')\n lineviewContent.classList.add('empty')\n lineviewContent.contentEditable = true\n\n this.addLineViewListeners(lineviewContent)\n\n lineview.appendChild(lineviewContent)\n\n return lineview\n }\n\n activateLineView(lineview, cursorPos) {\n if (cursorPos > lineview.innerText.length) {\n cursorPos = lineview.innerText.length\n } else if (cursorPos < 0) {\n cursorPos = 0\n }\n\n const offset = this.charWidth * (lineview.innerText.length - cursorPos)\n \n if (lineview.innerText.length > 0) {\n const range = document.createRange();\n const sel = window.getSelection();\n range.setStart(lineview.childNodes[0], cursorPos);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n\n lineview.focus()\n lineview.parentNode.classList.add('active')\n\n lineview.parentNode.style.setProperty('--cursor-offset', offset + \"px\")\n }\n\n addLineViewListeners(lineview) {\n lineview.addEventListener('keydown', e => {this.handleLineViewKeyDown(e)})\n lineview.addEventListener('click', e => {this.handleLineViewClick(e)})\n lineview.addEventListener('focusin', e => {this.handleLineViewFocusIn(e)})\n lineview.addEventListener('focusout', e => {this.handleLineViewFocusOut(e)})\n }\n\n handleLineViewKeyDown(e) {\n const currentCursorOffset = parseFloat(e.target.parentNode.style.getPropertyValue('--cursor-offset')) || 0\n let newCursorOffset, stepDiv, cursorPos\n\n if (e.target.innerText.length == 0) {\n e.target.classList.add('empty')\n } else {\n e.target.classList.remove('empty')\n }\n\n switch (e.key) {\n case \"ArrowLeft\":\n const inputWidth = e.target.getBoundingClientRect().width\n newCursorOffset = Math.min(inputWidth, currentCursorOffset + this.charWidth)\n e.target.parentNode.style.setProperty('--cursor-offset', newCursorOffset + 'px')\n break\n\n case \"ArrowRight\":\n newCursorOffset = Math.max(0, currentCursorOffset - this.charWidth)\n e.target.parentNode.style.setProperty('--cursor-offset', newCursorOffset + 'px')\n break\n\n case \"ArrowUp\":\n e.preventDefault()\n let prevLineviewContent\n\n if (e.target.parentNode.previousSibling && e.target.parentNode.previousSibling.classList.contains('input-lineview')) {\n prevLineviewContent = e.target.parentNode.previousSibling.querySelector('.input-lineview-content')\n cursorPos = e.target.innerText.length - Math.round(currentCursorOffset / this.charWidth)\n } else {\n stepDiv = e.target.closest(\".step\")\n const previousStepDiv = stepDiv.previousSibling\n const prevStepLineviews = Array.from(previousStepDiv.querySelectorAll('.input-lineview-content'))\n prevLineviewContent = prevStepLineviews[prevStepLineviews.length - 1]\n cursorPos = prevLineviewContent.innerText.length\n }\n\n this.activateLineView(prevLineviewContent, cursorPos)\n break\n\n case \"ArrowDown\":\n e.preventDefault()\n let nextLineviewContent\n\n if (e.target.parentNode.nextSibling && e.target.parentNode.nextSibling.classList.contains('input-lineview')) {\n nextLineviewContent = e.target.parentNode.nextSibling.querySelector('.input-lineview-content')\n cursorPos = e.target.innerText.length - Math.round(currentCursorOffset / this.charWidth)\n } else {\n stepDiv = e.target.closest(\".step\")\n const nextStepDiv = stepDiv.nextSibling\n nextLineviewContent = nextStepDiv.querySelector('.input-lineview-content')\n cursorPos = nextLineviewContent.innerText.length\n }\n\n this.activateLineView(nextLineviewContent, cursorPos)\n break\n \n case \"Backspace\":\n if (\n e.target.innerText.length == 0 && \n e.target.previousSibling && \n e.target.previousSibling.classList.contains('input-lineview')\n ) {\n this.activateLineView(e.target.previousSibling)\n e.target.remove()\n }\n\n break\n\n case \"Delete\":\n // TODO: Handle\n break\n\n case \"Insert\":\n // TODO: Handle\n break\n\n case \"Enter\":\n e.preventDefault()\n\n stepDiv = e.target.closest(\".step\")\n if (stepDiv.classList.contains('message-step')) {\n // Add new line to message textarea\n const lineview = this.createLineView()\n\n e.target.parentNode.after(lineview)\n const lineviewContent = lineview.querySelector(`.input-lineview-content`)\n this.activateLineView(lineviewContent)\n } else {\n // Go to next step\n const nextStep = stepDiv.nextSibling\n nextStep.style.display = 'block'\n\n const lineviewContent = nextStep.querySelector(`.input-lineview-content`)\n this.activateLineView(lineviewContent)\n }\n\n break\n \n default:\n break\n }\n }\n\n handleLineViewClick(e) {\n const offset = e.offsetX\n\n const newCursorOffset = (e.target.innerText.length - getCaretPosition(e.target)) * this.charWidth\n e.target.parentNode.style.setProperty('--cursor-offset', newCursorOffset + 'px')\n\n e.target.parentNode.classList.add('active')\n }\n\n handleLineViewFocusIn(e) {\n if (e.target.innerText.length == 0) {\n e.target.parentNode.classList.add('active')\n }\n }\n\n handleLineViewFocusOut(e) {\n e.target.parentNode.classList.remove('active')\n }\n\n}\n\nfunction getCaretPosition(editableDiv) {\n var caretPos = 0,\n sel, range;\n if (window.getSelection) {\n sel = window.getSelection();\n if (sel.rangeCount) {\n range = sel.getRangeAt(0);\n if (range.commonAncestorContainer.parentNode == editableDiv) {\n caretPos = range.endOffset;\n }\n }\n } else if (document.selection && document.selection.createRange) {\n range = document.selection.createRange();\n if (range.parentElement() == editableDiv) {\n var tempEl = document.createElement(\"span\");\n editableDiv.insertBefore(tempEl, editableDiv.firstChild);\n var tempRange = range.duplicate();\n tempRange.moveToElementText(tempEl);\n tempRange.setEndPoint(\"EndToEnd\", range);\n caretPos = tempRange.text.length;\n }\n }\n return caretPos;\n}\n\n// Contact form\n(function() {\n new ContactForm(document.getElementById('contact-form'))\n\n let step = 1\n \n // let handlingKeyPresses = false\n // const handleKeyPress = e => {\n // console.log(e)\n // const text = document.querySelector(`.step-${step} .input-text`)\n // text.textContent += e.key\n // }\n\n // contactForm.addEventListener('click', e => {\n // // console.log(\"CLICKED!\")\n // contactForm.querySelector(`.step-${step} .input-lineview`).focus()\n // // if (!handlingKeyPresses) {\n // // document.addEventListener('keypress', handleKeyPress)\n // // handlingKeyPresses = true\n // // }\n // });\n\n let disabled = false\n\n // console.log(\"RUNNING!\")\n\n // contactForm.addEventListener('submit', e => {\n // e.preventDefault()\n\n // if (disabled) {\n // return\n // }\n\n // disabled = true\n // contactForm.classList.add('disabled')\n\n // contactForm.querySelector('button[type=\"submit\"]').innerText = \"Sending...\"\n\n // fetch('/contact', {\n // method: 'POST',\n // body: JSON.stringify({\n // name: contactForm.querySelector('input[name=\"name\"]').value,\n // email: contactForm.querySelector('input[name=\"email\"]').value,\n // message: contactForm.querySelector('textarea[name=\"message\"]').value,\n // })\n // })\n // .then((response) => {\n // if (response.ok) {\n // contactForm.querySelector('button[type=\"submit\"]').innerText = \"Sent\"\n // } else {\n // disabled = false\n // contactForm.classList.remove('disabled')\n // contactForm.querySelector('button[type=\"submit\"]').innerText = \"Failed\"\n // setTimeout(() => {\n // contactForm.querySelector('button[type=\"submit\"]').innerText = \"Send Message\"\n // }, 1000)\n // }\n // })\n // })\n})();"]}