Rewritten in less, new floating menu, separated js

This commit is contained in:
DarkCat09 2022-10-11 13:28:46 +04:00
parent e0629a750a
commit e9f60236a4
16 changed files with 1663 additions and 535 deletions

View file

@ -1,10 +0,0 @@
// Computing My Age
// Вычисление моего возраста
var birthday = new Date(2009, 7, 13, 13);
try {
// https://ru.stackoverflow.com/questions/576478/javascript-Вычисление-возраста-по-дате-рождения
document.getElementById('age-js').innerHTML = Math.floor((Date.now() - birthday.getTime()) / (24 * 3600 * 365.25 * 1000));
}
catch (ex) {
console.log('Произошла ошибка при попытке рендеринга моего возраста! Подробнее:\n' + ex.message);
}

22
js/anim.js Normal file
View file

@ -0,0 +1,22 @@
const fadeAnimIn = [
'show',
'animated',
'tdFadeIn',
]
const fadeAnimOut = [
'animated',
'tdFadeOut',
]
const bounceAnimIn = [
'show',
'animated',
'tdExpandInBounce',
]
const bounceAnimOut = [
'animated',
'tdShrinkOutBounce',
]

19
js/control.js Normal file
View file

@ -0,0 +1,19 @@
/** @type {HTMLImageElement} */
const spaceObj = document.querySelector('#space-obj')
/** @type {HTMLDivElement} */
const space = document.querySelector('.space')
function changePicture(/** @type {Event} */ ev) {
spaceObj.src = ev.target.dataset.img || 'img/earth.gif'
hideContextMenu()
}
function changeSpeed(/** @type {Event} */ ev) {
spaceObj.style.animationDuration = `${1200 - ev.target.value}s`
}
function landToEarth() {
hideContextMenu()
}

24
js/handlers.js Normal file
View file

@ -0,0 +1,24 @@
context.addEventListener('mousedown', ev => ev.stopPropagation())
space.addEventListener('mousedown', ev => ev.preventDefault())
space.addEventListener('contextmenu', contextMenu)
document.querySelectorAll('.copylink>.profile-link').forEach(
elem => elem.addEventListener('click', copyLink)
)
document.querySelectorAll('li.change-img>a').forEach(
elem => elem.addEventListener('click', changePicture)
)
document.querySelector('li.change-speed a').addEventListener('mousedown', ev => ev.preventDefault())
document.querySelector('li.change-speed input').addEventListener('input', changeSpeed)
document.querySelector('li.change-speed input').addEventListener('mousedown', ev => ev.stopPropagation())
document.querySelector('li.land-to').addEventListener('click', landToEarth)
move.addEventListener('mousedown', moveMenu)
move.addEventListener('mouseup', moveMenu)
move.addEventListener('mousemove', moveMenu)
body.addEventListener('mousemove', moveMenu)
body.addEventListener('mouseup', moveMenu)
body.addEventListener('mousedown', hideContextMenu)

69
js/init.js Normal file
View file

@ -0,0 +1,69 @@
function init() {
initStars()
computeAge()
}
function initStars() {
const colors = [
'#999','#9999ac','#ac9999','#acac99',
'#bbb','#bbbbcf','#cfbbbb','#cfcfbb',
'#eee','#e5e5ff','#ffe5e5','#ffffe5',
'#fff'
]
const len = colors.length
const canvas = document.querySelector('canvas#stars')
const css = getComputedStyle(canvas)
const w = canvas.width = styleValue(css.getPropertyValue('width' ))
const h = canvas.height = styleValue(css.getPropertyValue('height'))
// if CSS hasn't been loaded yet
// (w and h contains NaN)
const err = [w,h].some(n => isNaN(n))
if (err) {
setTimeout(init, 200)
return
}
const ctx = canvas.getContext('2d')
const radius = 3
const circle = 2 * Math.PI
ctx.clearRect(0, 0, w, h)
for (let star = 0; star < 200; star++) {
let color = Math.floor(Math.random() * len)
ctx.fillStyle = colors[color]
ctx.beginPath()
ctx.arc(
Math.round(Math.random() * w),
Math.round(Math.random() * h),
radius, 0, circle, false
)
ctx.fill()
}
}
function computeAge() {
const birthday = new Date(2009, 7, 13, 12, 30)
const timedelta = Date.now() - birthday.getTime()
/*
The line below is equivalent to:
const age = timedelta / 1000 / 60 / 60 / 24 / 365.25
where:
1000: convert milliseconds -> seconds
60: secs -> minutes
60: minutes -> hours
24: hours -> days
365.25: average count of days in a year:
(366 + (365 * 3)) / 4 = 365.25
*/
const age = timedelta / (1000 * 60 * 60 * 24 * 365.25)
document.getElementById('age-js').textContent = Math.floor(age)
}

76
js/menu.js Normal file
View file

@ -0,0 +1,76 @@
/** @type {HTMLDivElement} */
const menu = document.querySelector('.about-menu')
/** @type {HTMLLIElement} */
const move = document.querySelector('.about-menu li#move')
/** @type {HTMLDivElement} */
const context = document.querySelector('.context-menu')
var contextShown = false
var contextTimeout
var menuDragging = false
var mousePos = {x: 0, y: 0}
function moveMenu(/** @type {MouseEvent} */ ev) {
switch (ev.type) {
case 'mousedown':
menuDragging = true
mousePos.y = ev.clientY - styleValue(menu.style.top)
mousePos.x = ev.clientX - styleValue(menu.style.left)
menu.classList.add('dragging')
ev.preventDefault()
break
case 'mouseup':
menuDragging = false
menu.classList.remove('dragging')
break
case 'mousemove':
if (menuDragging) {
let top = ev.clientY - mousePos.y
let left = ev.clientX - mousePos.x
menu.style.top = `${top}px`
menu.style.left = `${left}px`
}
break
}
}
function contextMenu(/** @type {MouseEvent} */ ev) {
clearTimeout(contextTimeout)
context.classList.remove(...bounceAnimOut)
context.style.top = `${ev.clientY + 5}px`
context.style.left = `${ev.clientX + 5}px`
context.classList.add(...bounceAnimIn)
contextShown = true
ev.preventDefault()
return false
}
function hideContextMenu(/** @type {MouseEvent} */ ev) {
if (!contextShown) return
if (ev && ev.button != 0) return
context.classList.remove(...bounceAnimIn)
context.classList.add('show')
context.classList.add(...bounceAnimOut)
contextShown = false
// animation-duration: 0.6s;
contextTimeout = setTimeout(() => {
context.classList.remove('show')
context.classList.remove(...bounceAnimOut)
}, 600)
}

View file

@ -1,128 +1,32 @@
function setupUi() {
// Context Menu
document.body.addEventListener('contextmenu', (e) => {
var menu = document.querySelector('.context-menu');
menu.style.top = e.pageY + 'px';
menu.style.left = e.pageX + 'px';
togglePopup(menu);
e.preventDefault();
return false;
});
// Hide Pop-ups
document.body.addEventListener('click', () => {
var popups = document.querySelectorAll('.popup');
for (var i = 0; i < popups.length; i++) {
togglePopup(popups[i], 0);
}
});
// Initialize Hints
var itemswh = document.querySelectorAll('.withhint');
for (var j = 0; j < itemswh.length; j++) {
itemswh[j].addEventListener('mouseover', showHint);
//itemswh[j].addEventListener('mousemove', showHint);
itemswh[j].addEventListener('mouseleave', hideHint);
}
};
const body = document.body
function initStars() {
var colors = ['#aaa','#ddd','#eee','#fff'];
var canvas = document.querySelector('canvas#stars');
var w = canvas.width;
var h = canvas.height;
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, w, h);
for (var star = 0; star < 200; star++) {
ctx.fillStyle = colors[Math.floor(Math.random()*colors.length)];
ctx.fillRect(Math.round(Math.random()*w), Math.round(Math.random()*h), 1, 1);
}
};
function copyLink(/** @type {Event} */ ev) {
function togglePopup(el, mode=1) {
var displaying = (el.accessKey.trim() != '' && el.accessKey != '0');
/** @type {HTMLSpanElement} */
let elem = ev.currentTarget
if (mode != 1 && !displaying)
return;
navigator.clipboard.writeText(elem.dataset.link)
if (!displaying) {
el.style.animation = 'tdExpandInBounce 0.3s ease 0s forwards';
el.style.pointerEvents = 'auto';
el.accessKey = '1';
}
else {
el.style.animation = 'tdShrinkOutBounce 0.3s ease 0s forwards';
el.style.pointerEvents = 'none';
el.accessKey = '0';
}
};
let wrapper = elem.parentElement.parentElement.parentElement
let msg = wrapper.querySelector('.copied')
function showDiscordSubmenu(e) {
var submenu = document.querySelector('li#item-discord').querySelector('nav.submenu');
togglePopup(submenu);
e.stopPropagation();
};
msg.classList.add(...fadeAnimIn)
function showAboutCard(e) {
var about = document.querySelector('div.about-card-wrapper');
togglePopup(about);
e.stopPropagation();
};
function copyDiscordTag(e) {
var dtag = e.target.innerText;
var text = document.createElement('textarea');
text.style.position = 'absolute';
text.style.left = '-9999px';
text.style.top = '0';
text.innerHTML = dtag;
text.classList.add('copyarea');
e.target.append(text);
text.select();
document.execCommand('copy');
setTimeout(() => {
document.querySelector('textarea.copyarea').remove();
togglePopup(document.querySelector('li#item-discord').querySelector('nav.submenu'));
}, 100);
togglePopup(document.querySelector('.msg-wrapper'));
setTimeout(() => {
togglePopup(document.querySelector('.msg-wrapper'), 0);
}, 1500);
e.stopPropagation();
};
msg.classList.remove(...fadeAnimIn)
function changePicture(e, num) {
var img = document.querySelector('.space-obj > img');
switch (num) {
case 0:
img.src = 'img/earth.gif';
break;
case 1:
img.src = 'img/moon.gif';
break;
case 2:
img.src = 'img/sun.gif';
break;
}
togglePopup(document.querySelector('.context-menu'));
};
msg.classList.add('show')
msg.classList.add(...fadeAnimOut)
function spaceObjSpeed(spd) {
document.querySelector('.space-obj>img').style.animationDuration = `${spd}s`;
};
setTimeout(() => {
msg.classList.remove(...fadeAnimOut)
msg.classList.remove(...fadeAnimIn)
}, 600)
function showHint(e) {
var elid = e.target.id;
var hintid = 'hint-' + (elid.startsWith('item-') ? elid.slice(5) : 'elem');
var hintel = document.getElementById(hintid);
if (hintel)
hintel.style.opacity = '1';
};
}, 1500)
}
function hideHint(e) {
var elid = e.target.id;
var hintid = 'hint-' + (elid.startsWith('item-') ? elid.slice(5) : 'elem');
var hintel = document.getElementById(hintid);
if (hintel)
hintel.style.opacity = '0';
};
function styleValue(/** @type {string} */ prop) {
return prop.replace('px', '') * 1
}