index, css, js: convert to LF line endings

Signed-off-by: Naman Sood <mail@nsood.in>
This commit is contained in:
Naman Sood 2024-02-23 23:09:57 -05:00
parent 04b11c541a
commit c712cb5d8b
3 changed files with 725 additions and 725 deletions

View file

@ -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;
}
}

View file

@ -1,69 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Naman Sood</title>
<meta name="description" content="Developer and technology enthusiast who's never gonna give you up.">
<meta name="keywords" content="nsood, nfool, naman sood, nachloride, nsdcars5, namansood, namandoesnotpanic, tendstofortytwo">
<meta property="og:url" content="https://nsood.in">
<meta property="og:type" content="website">
<meta property="og:title" content="Naman Sood">
<meta property="og:description" content="Developer and technology enthusiast who's never gonna give you up.">
<meta property="og:image" content="https://nsood.in/screenshot.php">
<link rel="stylesheet" type="text/css" href="fonts/css/nunito.css">
<link rel="stylesheet" type="text/css" href="fonts/css/fontawesome.min.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<section id="home" class="main">
<!-- empty alt attribute informs screen readers that background graphic is purely decorative and should be ignored -->
<canvas id="bg" alt=""></canvas>
<div class="text-container">
<h1>Hi, I&rsquo;m Naman.</h1>
<h3>I&rsquo;m a<span class="age"> twenty one</span> year-old who's fond of <em>coffee</em>, <em>math</em>, <em>writing</em>, <em>cars</em>, <button class="among">among</button> other things. I also enjoy <em>programming</em> enough to do that for a living. I&rsquo;m currently studying <em>computer science</em> at the <em>University of Waterloo</em>.</h3>
<h3>You can click to see my <a href="/resume.pdf">resume</a>, visit my <a href="https://prose.nsood.in">blog</a>, or check out ways to contact me below.</h3>
<div class="contact-methods">
<a href="mailto:mail@nsood.in" class="contact-method" aria-label="Email">
<i class="email"></i>
<p class="detail">mail@nsood.in</p>
</a>
<a href="https://social.treehouse.systems/@tendstofortytwo" class="contact-method" aria-label="Mastodon" rel="me">
<i class="fab fa-mastodon"></i>
<p class="detail">@tendstofortytwo@treehouse.systems</p>
</a>
<a href="https://linkedin.com/in/namansood" class="contact-method" aria-label="LinkedIn">
<i class="fab fa-linkedin-in"></i>
<p class="detail">Naman Sood</p>
</a>
<a href="https://github.com/tendstofortytwo" class="contact-method" aria-label="GitHub">
<i class="fab fa-github"></i>
<p class="detail">tendstofortytwo</p>
</a>
</div>
</div>
<dialog class="change-color-dialog">
<h4>If you could pick any color,<br> what color would you pick?</h4>
<form method="dialog">
<div class="radio-buttons"></div>
<input type="button" value="save" id="color-change-save">
<input type="submit" value="exit">
</form>
</dialog>
<button class="change-color-button" aria-label="change color">
<i class="fas fa-paint-brush"></i>
</button>
<noscript>
<style>
button.change-color-button { display: none; }
</style>
</noscript>
</section>
<!-- I guess it doesn't make sense for a purely visual easter egg to be visible to screen readers..? -->
<div class="clapper" aria-hidden="true">👏👏👏</div>
<script src="js/script.js"></script>
<script src="fonts/attribution.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Naman Sood</title>
<meta name="description" content="Developer and technology enthusiast who's never gonna give you up.">
<meta name="keywords" content="nsood, nfool, naman sood, nachloride, nsdcars5, namansood, namandoesnotpanic, tendstofortytwo">
<meta property="og:url" content="https://nsood.in">
<meta property="og:type" content="website">
<meta property="og:title" content="Naman Sood">
<meta property="og:description" content="Developer and technology enthusiast who's never gonna give you up.">
<meta property="og:image" content="https://nsood.in/screenshot.php">
<link rel="stylesheet" type="text/css" href="fonts/css/nunito.css">
<link rel="stylesheet" type="text/css" href="fonts/css/fontawesome.min.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<section id="home" class="main">
<!-- empty alt attribute informs screen readers that background graphic is purely decorative and should be ignored -->
<canvas id="bg" alt=""></canvas>
<div class="text-container">
<h1>Hi, I&rsquo;m Naman.</h1>
<h3>I&rsquo;m a<span class="age"> twenty one</span> year-old who's fond of <em>coffee</em>, <em>math</em>, <em>writing</em>, <em>cars</em>, <button class="among">among</button> other things. I also enjoy <em>programming</em> enough to do that for a living. I&rsquo;m currently studying <em>computer science</em> at the <em>University of Waterloo</em>.</h3>
<h3>You can click to see my <a href="/resume.pdf">resume</a>, visit my <a href="https://prose.nsood.in">blog</a>, or check out ways to contact me below.</h3>
<div class="contact-methods">
<a href="mailto:mail@nsood.in" class="contact-method" aria-label="Email">
<i class="email"></i>
<p class="detail">mail@nsood.in</p>
</a>
<a href="https://social.treehouse.systems/@tendstofortytwo" class="contact-method" aria-label="Mastodon" rel="me">
<i class="fab fa-mastodon"></i>
<p class="detail">@tendstofortytwo@treehouse.systems</p>
</a>
<a href="https://linkedin.com/in/namansood" class="contact-method" aria-label="LinkedIn">
<i class="fab fa-linkedin-in"></i>
<p class="detail">Naman Sood</p>
</a>
<a href="https://github.com/tendstofortytwo" class="contact-method" aria-label="GitHub">
<i class="fab fa-github"></i>
<p class="detail">tendstofortytwo</p>
</a>
</div>
</div>
<dialog class="change-color-dialog">
<h4>If you could pick any color,<br> what color would you pick?</h4>
<form method="dialog">
<div class="radio-buttons"></div>
<input type="button" value="save" id="color-change-save">
<input type="submit" value="exit">
</form>
</dialog>
<button class="change-color-button" aria-label="change color">
<i class="fas fa-paint-brush"></i>
</button>
<noscript>
<style>
button.change-color-button { display: none; }
</style>
</noscript>
</section>
<!-- I guess it doesn't make sense for a purely visual easter egg to be visible to screen readers..? -->
<div class="clapper" aria-hidden="true">👏👏👏</div>
<script src="js/script.js"></script>
<script src="fonts/attribution.js"></script>
</body>
</html>

View file

@ -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();
});