From c712cb5d8bdeaadd41f035a91f1319fb724808d5 Mon Sep 17 00:00:00 2001 From: Naman Sood Date: Fri, 23 Feb 2024 23:09:57 -0500 Subject: [PATCH] index, css, js: convert to LF line endings Signed-off-by: Naman Sood --- css/style.scss | 914 ++++++++++++++++++++++++------------------------- index.html | 138 ++++---- js/script.js | 398 ++++++++++----------- 3 files changed, 725 insertions(+), 725 deletions(-) diff --git a/css/style.scss b/css/style.scss index f31a1aa..e64aee9 100644 --- a/css/style.scss +++ b/css/style.scss @@ -1,457 +1,457 @@ -*, *:before, *:after { - box-sizing: border-box; -} - -html { - overflow-x: hidden; - scroll-behavior: smooth; -} - -body { - margin: 0; - font-family: 'Nunito', sans-serif; - background: var(--bgColor); - - @media(prefers-color-scheme: light) { - --bgColor: white; - --textColor: #777; - --iconColor: black; - --boldColor: black; - } - - @media(prefers-color-scheme: dark) { - --bgColor: black; - --iconColor: white; - --textColor: #aaa; - --boldColor: white; - } - - --liteColor: white; - --liteText: #777; - &.lite-mode { - --bgColor: white; - --textColor: #777; - --iconColor: black; - --boldColor: black; - } - - --darkColor: black; - --darkText: #aaa; - &.dark-mode { - --bgColor: black; - --iconColor: white; - --textColor: #aaa; - --boldColor: white; - } - - --mintColor: #c7fcee; - --mintText: #5f8c80; - &.mint-mode { - --bgColor: #c7fcee; - --iconColor: #486b61; - --textColor: #5f8c80; - --boldColor: #10352b; - } - - --purpColor: #cfc7fc; - --purpText: #7166af; - &.purp-mode { - --bgColor: #cfc7fc; - --iconColor: #5a518c; - --textColor: #7166af; - --boldColor: #312c4c; - } - - --yellColor: #fcfcbf; - --yellText: #8c8c5f; - &.yell-mode { - --bgColor: #fcfcbf; - --iconColor: #54543f; - --textColor: #8c8c5f; - --boldColor: #353528; - } - - --blueColor: #ade3ff; - --blueText: #46748c; - &.blue-mode { - --bgColor: #ade3ff; - --iconColor: #394b54; - --textColor: #46748c; - --boldColor: #242f35; - } -} - -.main { - min-height: 100vh; - position: relative; - z-index: 10; - display: flex; - justify-content: center; - align-items: flex-start; - flex-direction: column; - overflow-y: hidden; - - > * { - position: relative; - } - - - > canvas#bg { - position: absolute; - top: 0; - left: 0; - } - - .text-container { - text-align: left; - max-width: 50rem; - margin: auto auto auto 13vw; - } - - h1 { - font-size: 4rem; - font-weight: 600; - margin: 0 0 2rem; - color: var(--boldColor); - } - - h3 { - margin: 1rem 0 0; - font-size: 1.7rem; - line-height: 1.4; - font-weight: normal; - color: var(--textColor); - } - - em { - color: var(--boldColor); - font: inherit; - } - - h3 a { - color: var(--boldColor); - text-decoration: none; - border-bottom: 0.2rem solid transparent; - white-space: nowrap; - position: relative; - - &:before, &:after { - content: ''; - bottom: 0.4rem; - left: 0; - width: 100%; - height: 0.1rem; - background: var(--boldColor); - position: absolute; - opacity: 0.04; - transition: all 0.2s ease; - } - - &:before { - transform: scaleX(0); - transform-origin: center left; - } - - &:after { - opacity: 0.1; - } - - &:hover:before { - transform: scaleX(1); - opacity: 0.2; - } - } - - h3 button { - color: inherit; - font: inherit; - margin: 0; - padding: 0; - border: 0; - background: none; - } - - .contact-methods { - display: flex; - margin-left: -1.5rem; - margin-top: 1rem; - - a.contact-method { - color: inherit; - text-decoration: none; - position: relative; - overflow: visible; - width: 4rem; - height: 4rem; - - i { - color: var(--iconColor); - } - - p { - position: absolute; - top: 90%; - left: -100rem; - right: -100rem; - margin: 0 auto; - width: max-content; - opacity: 0; - transition: all 0.2s ease; - color: #333; - font-size: 0.85rem; - } - - &:hover p { - opacity: 1; - } - - &:last-child { - p { - left: auto; - right: 1.5rem; - margin: 0; - } - } - - &:first-child { - p { - left: 1.5rem; - right: auto; - margin: 0; - } - } - } - - i { - width: 4rem; - height: 4rem; - line-height: 4rem; - text-align: center; - position: relative; - - &:before { - position: relative; - z-index: 10; - } - - &:after { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - width: 60%; - height: 60%; - border-radius: 50%; - opacity: 0; - transform: scale(0.7); - content: ''; - transition: all 0.2s ease; - background: #333; - } - } - - i.email { - position: relative; - width: 4rem; - height: 4rem; - display: block; - - &:before { - content: '@'; - font-style: normal; - font-weight: bold; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 100%; - height: 100%; - position: absolute; - text-align: center; - } - } - } - - button.change-color-button { - position: absolute; - top: 0; - right: 0; - margin: 1rem; - font: inherit; - color: inherit; - border: none; - border-radius: 100rem; - height: 3rem; - width: 3rem; - text-align: center; - line-height: 3rem; - padding: 0; - background: var(--textColor); - color: var(--bgColor); - cursor: pointer; - - &:hover { - background: var(--boldColor); - } - } - - dialog.change-color-dialog { - position: fixed; - top: 0; - left: 0; - right: 0; - margin: auto; - color: var(--bgColor); - background: var(--textColor); - padding: 2rem; - border: 0; - border-radius: 0 0 0.25rem 0.25rem; - width: 100%; - max-height: calc(100vh - 2rem); - overflow: scroll; - box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.3), - 0 0.15rem 1rem rgba(0, 0, 0, 0.1); - - font-size: 1.33rem; - opacity: 0; - transform: translateY(-10%); - pointer-events: none; - transition: all 0.2s ease; - display: block; - - &[open] { - opacity: 1; - transform: translateY(0%); - pointer-events: all; - } - - h4 { - margin: 0 0 1rem; - text-align: center; - font-size: 1.9rem; - font-weight: 400; - } - - form { - display: flex; - flex-wrap: wrap; - justify-content: center; - - input[type='button'], input[type='submit'] { - font: inherit; - color: inherit; - padding: 0.5rem 1rem; - border: 0; - margin: 1rem 0.5rem 0; - color: var(--textColor); - background: var(--bgColor); - border-radius: 0.25rem; - cursor: pointer; - - &:hover { - color: var(--boldColor); - } - } - } - - .radio-buttons { - display: flex; - flex-wrap: wrap; - justify-content: center; - width: 100%; - - > div { - margin: 0.5rem 0; - - input { - display: none; - } - - label div { - display: inline-block; - height: 2rem; - width: 2rem; - border-radius: 50%; - margin: 0 0.25rem 0 0.75rem; - line-height: 2rem; - text-align: center; - border: 0.5rem solid var(--textColor); - background-clip: padding-box; - } - - input:checked + label div { - border: 0; - } - } - } - } - - dialog.change-color-dialog[open] + button.change-color-button { - transition: all 0.2s ease; - opacity: 0; - pointer-events: none; - } -} - -@media(max-width: 69rem), (orientation: portrait) { - .main > .text-container { - margin: auto; - padding: 2rem; - } -} - -@media(max-width: 30rem) { - dialog.change-color-dialog br { - display: none; - } - - .main { - > .text-container { - h1 { - font-size: 3rem; - } - - h3 { - font-size: 1.5rem; - } - } - .contact-methods { - justify-content: center; - margin-top: 2rem; - } - } -} - -.clapper { - position: fixed; - bottom: 0; - left: 0; - width: 100%; - height: 10rem; - line-height: 10rem; - text-align: center; - z-index: 100000; - font-size: 5rem; - pointer-events: none; - transition: none; - opacity: 0; - color: var(--boldColor); -} - -.clapper.clapping { - animation: clap 1s ease-in-out; -} - -@keyframes clap { - 0% { opacity: 1; } - 49% { opacity: 0; } - 51% { opacity: 1; } - 100% { opacity: 0; } -} - -@media (prefers-reduced-motion) { - canvas#bg { - display: none; - } -} +*, *:before, *:after { + box-sizing: border-box; +} + +html { + overflow-x: hidden; + scroll-behavior: smooth; +} + +body { + margin: 0; + font-family: 'Nunito', sans-serif; + background: var(--bgColor); + + @media(prefers-color-scheme: light) { + --bgColor: white; + --textColor: #777; + --iconColor: black; + --boldColor: black; + } + + @media(prefers-color-scheme: dark) { + --bgColor: black; + --iconColor: white; + --textColor: #aaa; + --boldColor: white; + } + + --liteColor: white; + --liteText: #777; + &.lite-mode { + --bgColor: white; + --textColor: #777; + --iconColor: black; + --boldColor: black; + } + + --darkColor: black; + --darkText: #aaa; + &.dark-mode { + --bgColor: black; + --iconColor: white; + --textColor: #aaa; + --boldColor: white; + } + + --mintColor: #c7fcee; + --mintText: #5f8c80; + &.mint-mode { + --bgColor: #c7fcee; + --iconColor: #486b61; + --textColor: #5f8c80; + --boldColor: #10352b; + } + + --purpColor: #cfc7fc; + --purpText: #7166af; + &.purp-mode { + --bgColor: #cfc7fc; + --iconColor: #5a518c; + --textColor: #7166af; + --boldColor: #312c4c; + } + + --yellColor: #fcfcbf; + --yellText: #8c8c5f; + &.yell-mode { + --bgColor: #fcfcbf; + --iconColor: #54543f; + --textColor: #8c8c5f; + --boldColor: #353528; + } + + --blueColor: #ade3ff; + --blueText: #46748c; + &.blue-mode { + --bgColor: #ade3ff; + --iconColor: #394b54; + --textColor: #46748c; + --boldColor: #242f35; + } +} + +.main { + min-height: 100vh; + position: relative; + z-index: 10; + display: flex; + justify-content: center; + align-items: flex-start; + flex-direction: column; + overflow-y: hidden; + + > * { + position: relative; + } + + + > canvas#bg { + position: absolute; + top: 0; + left: 0; + } + + .text-container { + text-align: left; + max-width: 50rem; + margin: auto auto auto 13vw; + } + + h1 { + font-size: 4rem; + font-weight: 600; + margin: 0 0 2rem; + color: var(--boldColor); + } + + h3 { + margin: 1rem 0 0; + font-size: 1.7rem; + line-height: 1.4; + font-weight: normal; + color: var(--textColor); + } + + em { + color: var(--boldColor); + font: inherit; + } + + h3 a { + color: var(--boldColor); + text-decoration: none; + border-bottom: 0.2rem solid transparent; + white-space: nowrap; + position: relative; + + &:before, &:after { + content: ''; + bottom: 0.4rem; + left: 0; + width: 100%; + height: 0.1rem; + background: var(--boldColor); + position: absolute; + opacity: 0.04; + transition: all 0.2s ease; + } + + &:before { + transform: scaleX(0); + transform-origin: center left; + } + + &:after { + opacity: 0.1; + } + + &:hover:before { + transform: scaleX(1); + opacity: 0.2; + } + } + + h3 button { + color: inherit; + font: inherit; + margin: 0; + padding: 0; + border: 0; + background: none; + } + + .contact-methods { + display: flex; + margin-left: -1.5rem; + margin-top: 1rem; + + a.contact-method { + color: inherit; + text-decoration: none; + position: relative; + overflow: visible; + width: 4rem; + height: 4rem; + + i { + color: var(--iconColor); + } + + p { + position: absolute; + top: 90%; + left: -100rem; + right: -100rem; + margin: 0 auto; + width: max-content; + opacity: 0; + transition: all 0.2s ease; + color: #333; + font-size: 0.85rem; + } + + &:hover p { + opacity: 1; + } + + &:last-child { + p { + left: auto; + right: 1.5rem; + margin: 0; + } + } + + &:first-child { + p { + left: 1.5rem; + right: auto; + margin: 0; + } + } + } + + i { + width: 4rem; + height: 4rem; + line-height: 4rem; + text-align: center; + position: relative; + + &:before { + position: relative; + z-index: 10; + } + + &:after { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 60%; + height: 60%; + border-radius: 50%; + opacity: 0; + transform: scale(0.7); + content: ''; + transition: all 0.2s ease; + background: #333; + } + } + + i.email { + position: relative; + width: 4rem; + height: 4rem; + display: block; + + &:before { + content: '@'; + font-style: normal; + font-weight: bold; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100%; + height: 100%; + position: absolute; + text-align: center; + } + } + } + + button.change-color-button { + position: absolute; + top: 0; + right: 0; + margin: 1rem; + font: inherit; + color: inherit; + border: none; + border-radius: 100rem; + height: 3rem; + width: 3rem; + text-align: center; + line-height: 3rem; + padding: 0; + background: var(--textColor); + color: var(--bgColor); + cursor: pointer; + + &:hover { + background: var(--boldColor); + } + } + + dialog.change-color-dialog { + position: fixed; + top: 0; + left: 0; + right: 0; + margin: auto; + color: var(--bgColor); + background: var(--textColor); + padding: 2rem; + border: 0; + border-radius: 0 0 0.25rem 0.25rem; + width: 100%; + max-height: calc(100vh - 2rem); + overflow: scroll; + box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.3), + 0 0.15rem 1rem rgba(0, 0, 0, 0.1); + + font-size: 1.33rem; + opacity: 0; + transform: translateY(-10%); + pointer-events: none; + transition: all 0.2s ease; + display: block; + + &[open] { + opacity: 1; + transform: translateY(0%); + pointer-events: all; + } + + h4 { + margin: 0 0 1rem; + text-align: center; + font-size: 1.9rem; + font-weight: 400; + } + + form { + display: flex; + flex-wrap: wrap; + justify-content: center; + + input[type='button'], input[type='submit'] { + font: inherit; + color: inherit; + padding: 0.5rem 1rem; + border: 0; + margin: 1rem 0.5rem 0; + color: var(--textColor); + background: var(--bgColor); + border-radius: 0.25rem; + cursor: pointer; + + &:hover { + color: var(--boldColor); + } + } + } + + .radio-buttons { + display: flex; + flex-wrap: wrap; + justify-content: center; + width: 100%; + + > div { + margin: 0.5rem 0; + + input { + display: none; + } + + label div { + display: inline-block; + height: 2rem; + width: 2rem; + border-radius: 50%; + margin: 0 0.25rem 0 0.75rem; + line-height: 2rem; + text-align: center; + border: 0.5rem solid var(--textColor); + background-clip: padding-box; + } + + input:checked + label div { + border: 0; + } + } + } + } + + dialog.change-color-dialog[open] + button.change-color-button { + transition: all 0.2s ease; + opacity: 0; + pointer-events: none; + } +} + +@media(max-width: 69rem), (orientation: portrait) { + .main > .text-container { + margin: auto; + padding: 2rem; + } +} + +@media(max-width: 30rem) { + dialog.change-color-dialog br { + display: none; + } + + .main { + > .text-container { + h1 { + font-size: 3rem; + } + + h3 { + font-size: 1.5rem; + } + } + .contact-methods { + justify-content: center; + margin-top: 2rem; + } + } +} + +.clapper { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 10rem; + line-height: 10rem; + text-align: center; + z-index: 100000; + font-size: 5rem; + pointer-events: none; + transition: none; + opacity: 0; + color: var(--boldColor); +} + +.clapper.clapping { + animation: clap 1s ease-in-out; +} + +@keyframes clap { + 0% { opacity: 1; } + 49% { opacity: 0; } + 51% { opacity: 1; } + 100% { opacity: 0; } +} + +@media (prefers-reduced-motion) { + canvas#bg { + display: none; + } +} diff --git a/index.html b/index.html index a8bdadd..fbe2351 100644 --- a/index.html +++ b/index.html @@ -1,69 +1,69 @@ - - - - - - Naman Sood - - - - - - - - - - - - -
- - -
-

Hi, I’m Naman.

-

I’m a twenty one year-old who's fond of coffee, math, writing, cars, other things. I also enjoy programming enough to do that for a living. I’m currently studying computer science at the University of Waterloo.

-

You can click to see my resume, visit my blog, or check out ways to contact me below.

- -
- -

If you could pick any color,
what color would you pick?

-
-
- - -
-
- - -
- - - - - - - - + + + + + + Naman Sood + + + + + + + + + + + + +
+ + +
+

Hi, I’m Naman.

+

I’m a twenty one year-old who's fond of coffee, math, writing, cars, other things. I also enjoy programming enough to do that for a living. I’m currently studying computer science at the University of Waterloo.

+

You can click to see my resume, visit my blog, or check out ways to contact me below.

+ +
+ +

If you could pick any color,
what color would you pick?

+
+
+ + +
+
+ + +
+ + + + + + + + diff --git a/js/script.js b/js/script.js index 1cd8d16..8592cf5 100644 --- a/js/script.js +++ b/js/script.js @@ -1,199 +1,199 @@ -const canvas = document.querySelector('canvas#bg'); - -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; - -const ctx = canvas.getContext('2d'); -const FILL_STYLES = { - light: 'rgba(0,0,0,0.05)', - dark: 'rgba(255,255,255,0.15)' -}; - -const colorMode = localStorage.getItem('color-mode'); - -if(colorMode) { - document.body.setAttribute('class', colorMode); -} - -addEventListener('resize', () => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; -}); - -function isDarkMode() { - return document.body.classList.contains('dark-mode') || - (document.body.classList.length === 0 && matchMedia('(prefers-color-scheme: dark)').matches); -} - -function Point() { - const r = 8; - - // progress below 0 is neglected, negative initial - // progress serves to introduce random delays - - // at 0.05 progress points per second, for example - // a dot with initial progress -0.15 will run 2 frames - // after a dot with initial progress -0.05 - const initialProgress = -4 * Math.random(); - - // moves point to a random location and - // resets its progress - this.init = function() { - this.progress = initialProgress; - this.x = Math.random() * canvas.width; - this.y = Math.random() * canvas.height; - this.r = 0; - this.rng = Math.random(); - } - - this.draw = function() { - if(this.progress >= 0) { - ctx.fillStyle = isDarkMode() ? FILL_STYLES.dark : FILL_STYLES.light; - ctx.beginPath(); - // radius calculation: maps progress from [0, 1] to [0, pi], - // then takes sine of that to get an increase, then decrease - // in radius. absolute value to prevent floating point errors - // accidentally causing negative sine values which cause ctx.arc - // to throw errors - ctx.arc(this.x, this.y, Math.abs(Math.sin(Math.PI*this.progress)*r), 0, 2*Math.PI); - ctx.fill(); - } - }; - this.render = function() { - // stars come faster than they go - // so user can look at them longer - // i guess? idk this just looked pretty - if(this.progress > 0.5) this.progress += 0.005; - else this.progress += 0.05; - this.draw(); - if(this.progress >= 1) this.init(); - } -} - -const dots = []; - -const n = 20; - -for(let i = 0; i < n; i++) { - dots[i] = new Point(); - dots[i].init(); -} - -function loop() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - for(let i = 0; i < n; i++) { - dots[i].render(); - } - - requestAnimationFrame(loop); -} - -loop(); - -// slight convenience: fix the header section with my correct age automatically - -const birthday = { - date: 19, - month: 0, - year: 2001, -} -const today = new Date(); -let age = today.getFullYear() - birthday.year; -if(today.getMonth() < birthday.month || (today.getMonth() == birthday.month && today.getDate() < birthday.date)) { - --age; -} -const tens = ['', ' ten plus', ' twenty', ' thirty', ' forty', ' fifty', ' sixty', ' seventy', 'n eighty', ' ninety']; -const ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']; -document.querySelector('.age').textContent = `${tens[Math.floor(age / 10)]} ${ones[age % 10]}`; - -// easter egg - -const sequences = [ - 'DARK', - 'LITE', - 'PURP', - 'MINT', - 'YELL', - 'BLUE', - 'SAVE' -].map(seq => ({ - word: seq, - combo: seq.split('').map(c => 'Key' + c) -})); - -const lastFourKeys = []; - -function changeColor(word) { - const clapper = document.querySelector('.clapper'); - clapper.classList.toggle('clapping'); - setTimeout(() => { - document.body.setAttribute('class', `${word.toLowerCase()}-mode`); - document.querySelector(`#change-color-to-${word}`).checked = true; - setTimeout(() => clapper.classList.toggle('clapping'), 500); - }, 500); -} - -addEventListener('keypress', e => { - lastFourKeys.push(e.code); - while(lastFourKeys.length > 4) lastFourKeys.shift(); - sequences.forEach(({word, combo}) => { - if(combo.every((v, i) => v === lastFourKeys[i])) { - if(word === 'SAVE') { - if(confirm('Would you like to save the current color mode to local browser storage?')) { - localStorage.setItem('color-mode', document.body.getAttribute('class')); - } - return; - } - - changeColor(word); - } - }); -}); - -document.querySelector('button.change-color-button').addEventListener('click', () => { - document.querySelector('dialog.change-color-dialog').show(); -}); - -sequences.forEach(({word}) => { - if(word !== 'SAVE') { - const container = document.createElement('div'); - - const radio = document.createElement('input'); - radio.type = 'radio'; - radio.name = 'change-color-radio'; - radio.id = `change-color-to-${word}`; - radio.checked = document.body.classList.contains(`${word.toLowerCase()}-mode`) || - (document.body.classList.length === 0 && - ((isDarkMode() && word === 'DARK') || (!isDarkMode() && word === 'LITE'))); - radio.addEventListener('click', () => { - changeColor(word); - }); - - const label = document.createElement('label'); - label.setAttribute('for', radio.id); - const color = document.createElement('div'); - color.setAttribute('style', - `background-color: var(--${word.toLowerCase()}Color); color: var(--${word.toLowerCase()}Text)`); - label.appendChild(color); - label.setAttribute('aria-label', word.toLowerCase()); - - container.appendChild(radio); - container.appendChild(label); - - document.querySelector('.change-color-dialog .radio-buttons').appendChild(container); - } -}); - -document.querySelector('#color-change-save').addEventListener('click', () => { - localStorage.setItem('color-mode', document.body.getAttribute('class')); - alert('Saved!'); -}); - -function among() { - alert('haha among us'); -} - -document.querySelector('.among').addEventListener('click', e => { - e.preventDefault(); - among(); -}); +const canvas = document.querySelector('canvas#bg'); + +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + +const ctx = canvas.getContext('2d'); +const FILL_STYLES = { + light: 'rgba(0,0,0,0.05)', + dark: 'rgba(255,255,255,0.15)' +}; + +const colorMode = localStorage.getItem('color-mode'); + +if(colorMode) { + document.body.setAttribute('class', colorMode); +} + +addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +}); + +function isDarkMode() { + return document.body.classList.contains('dark-mode') || + (document.body.classList.length === 0 && matchMedia('(prefers-color-scheme: dark)').matches); +} + +function Point() { + const r = 8; + + // progress below 0 is neglected, negative initial + // progress serves to introduce random delays - + // at 0.05 progress points per second, for example + // a dot with initial progress -0.15 will run 2 frames + // after a dot with initial progress -0.05 + const initialProgress = -4 * Math.random(); + + // moves point to a random location and + // resets its progress + this.init = function() { + this.progress = initialProgress; + this.x = Math.random() * canvas.width; + this.y = Math.random() * canvas.height; + this.r = 0; + this.rng = Math.random(); + } + + this.draw = function() { + if(this.progress >= 0) { + ctx.fillStyle = isDarkMode() ? FILL_STYLES.dark : FILL_STYLES.light; + ctx.beginPath(); + // radius calculation: maps progress from [0, 1] to [0, pi], + // then takes sine of that to get an increase, then decrease + // in radius. absolute value to prevent floating point errors + // accidentally causing negative sine values which cause ctx.arc + // to throw errors + ctx.arc(this.x, this.y, Math.abs(Math.sin(Math.PI*this.progress)*r), 0, 2*Math.PI); + ctx.fill(); + } + }; + this.render = function() { + // stars come faster than they go + // so user can look at them longer + // i guess? idk this just looked pretty + if(this.progress > 0.5) this.progress += 0.005; + else this.progress += 0.05; + this.draw(); + if(this.progress >= 1) this.init(); + } +} + +const dots = []; + +const n = 20; + +for(let i = 0; i < n; i++) { + dots[i] = new Point(); + dots[i].init(); +} + +function loop() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + for(let i = 0; i < n; i++) { + dots[i].render(); + } + + requestAnimationFrame(loop); +} + +loop(); + +// slight convenience: fix the header section with my correct age automatically + +const birthday = { + date: 19, + month: 0, + year: 2001, +} +const today = new Date(); +let age = today.getFullYear() - birthday.year; +if(today.getMonth() < birthday.month || (today.getMonth() == birthday.month && today.getDate() < birthday.date)) { + --age; +} +const tens = ['', ' ten plus', ' twenty', ' thirty', ' forty', ' fifty', ' sixty', ' seventy', 'n eighty', ' ninety']; +const ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']; +document.querySelector('.age').textContent = `${tens[Math.floor(age / 10)]} ${ones[age % 10]}`; + +// easter egg + +const sequences = [ + 'DARK', + 'LITE', + 'PURP', + 'MINT', + 'YELL', + 'BLUE', + 'SAVE' +].map(seq => ({ + word: seq, + combo: seq.split('').map(c => 'Key' + c) +})); + +const lastFourKeys = []; + +function changeColor(word) { + const clapper = document.querySelector('.clapper'); + clapper.classList.toggle('clapping'); + setTimeout(() => { + document.body.setAttribute('class', `${word.toLowerCase()}-mode`); + document.querySelector(`#change-color-to-${word}`).checked = true; + setTimeout(() => clapper.classList.toggle('clapping'), 500); + }, 500); +} + +addEventListener('keypress', e => { + lastFourKeys.push(e.code); + while(lastFourKeys.length > 4) lastFourKeys.shift(); + sequences.forEach(({word, combo}) => { + if(combo.every((v, i) => v === lastFourKeys[i])) { + if(word === 'SAVE') { + if(confirm('Would you like to save the current color mode to local browser storage?')) { + localStorage.setItem('color-mode', document.body.getAttribute('class')); + } + return; + } + + changeColor(word); + } + }); +}); + +document.querySelector('button.change-color-button').addEventListener('click', () => { + document.querySelector('dialog.change-color-dialog').show(); +}); + +sequences.forEach(({word}) => { + if(word !== 'SAVE') { + const container = document.createElement('div'); + + const radio = document.createElement('input'); + radio.type = 'radio'; + radio.name = 'change-color-radio'; + radio.id = `change-color-to-${word}`; + radio.checked = document.body.classList.contains(`${word.toLowerCase()}-mode`) || + (document.body.classList.length === 0 && + ((isDarkMode() && word === 'DARK') || (!isDarkMode() && word === 'LITE'))); + radio.addEventListener('click', () => { + changeColor(word); + }); + + const label = document.createElement('label'); + label.setAttribute('for', radio.id); + const color = document.createElement('div'); + color.setAttribute('style', + `background-color: var(--${word.toLowerCase()}Color); color: var(--${word.toLowerCase()}Text)`); + label.appendChild(color); + label.setAttribute('aria-label', word.toLowerCase()); + + container.appendChild(radio); + container.appendChild(label); + + document.querySelector('.change-color-dialog .radio-buttons').appendChild(container); + } +}); + +document.querySelector('#color-change-save').addEventListener('click', () => { + localStorage.setItem('color-mode', document.body.getAttribute('class')); + alert('Saved!'); +}); + +function among() { + alert('haha among us'); +} + +document.querySelector('.among').addEventListener('click', e => { + e.preventDefault(); + among(); +});