light and darkmode change logic & disable buttons after start spin & format

This commit is contained in:
p-wojt 2022-01-12 23:33:44 +01:00
parent 3707a32c94
commit 6811b6d771
10 changed files with 208 additions and 191 deletions

33
app.css
View File

@ -1,14 +1,14 @@
body {
background-color: #121212;
color: #FAF9F6;
color: #faf9f6;
transition-duration: 3s;
}
button{
button {
cursor: pointer;
}
canvas{
canvas {
height: 50rem;
cursor: pointer;
}
@ -45,25 +45,24 @@ ul {
text-align: center;
}
.add-item-button {
height: 2rem;
width: 15.5rem;
margin-top: 0.5rem;
background-color: #6495ED;
background-color: #6495ed;
border: 0.05rem solid black;
box-shadow: 0 0.7rem 0 -0.1rem #6082B6, 0 0.75rem 0 -0.05rem black;
box-shadow: 0 0.7rem 0 -0.1rem #6082b6, 0 0.75rem 0 -0.05rem black;
border-radius: 0.5rem;
}
.add-item-button:hover {
transform: translate(0, 0.25rem);
box-shadow: 0 0.5rem 0 -0.1rem #6082B6, 0 0.55rem 0 -0.05rem black;
box-shadow: 0 0.5rem 0 -0.1rem #6082b6, 0 0.55rem 0 -0.05rem black;
}
.add-item-button:active {
transform: translate(0, 0.5rem);
box-shadow: 0 0.1rem 0 -0.1rem #6082B6, 0 0.15rem 0 -0.05rem black;
box-shadow: 0 0.1rem 0 -0.1rem #6082b6, 0 0.15rem 0 -0.05rem black;
}
.counter {
@ -87,7 +86,7 @@ ul {
}
.menu-item-list {
text-align: center;
text-align: center;
}
.moon-sun {
@ -98,20 +97,20 @@ ul {
.remove-all-items-button {
width: 5.4rem;
height: 2rem;
background-color: #6495ED;
background-color: #6495ed;
border: 0.05rem solid black;
box-shadow: 0 0.7rem 0 -0.1rem #6082B6, 0 0.75rem 0 -0.05rem black;
box-shadow: 0 0.7rem 0 -0.1rem #6082b6, 0 0.75rem 0 -0.05rem black;
border-radius: 0.5rem;
}
.remove-all-items-button:hover {
transform: translate(0, 0.25rem);
box-shadow: 0 0.5rem 0 -0.1rem #6082B6, 0 0.55rem 0 -0.05rem black;
box-shadow: 0 0.5rem 0 -0.1rem #6082b6, 0 0.55rem 0 -0.05rem black;
}
.remove-all-items-button:active {
transform: translate(0, 0.5rem);
box-shadow: 0 0.1rem 0 -0.1rem #6082B6, 0 0.15rem 0 -0.05rem black;
box-shadow: 0 0.1rem 0 -0.1rem #6082b6, 0 0.15rem 0 -0.05rem black;
}
.roulette-wheel {
@ -129,19 +128,19 @@ ul {
}
.winner {
font-size: 32;
font-size: 32px;
margin-bottom: 1rem;
height: 28px;
}
@media screen and (max-width: 940px) {
canvas{
canvas {
margin-top: 5rem;
height: 20rem;
margin: auto;
}
.menu{
.menu {
width: 23.5rem;
}
@ -157,4 +156,4 @@ ul {
footer {
position: relative;
}
}
}

View File

@ -10,7 +10,7 @@
</head>
<body>
<div class="light-dark-mode">
<img class="moon-sun" src='static/moon.png' alt="mode">
<img class="moon-sun" src="static/moon.png" alt="mode" />
</div>
<div class="menu">
<p class="counter"></p>
@ -26,7 +26,12 @@
</div>
<footer>
<div hidden="true" class="icons-authors">
<img class="moon-sun" src='static/moon.png' alt="mode"> <img class="moon-sun" src='static/sun.png' alt="mode"> Made by made by <a href="https://www.freepik.com" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
<img class="moon-sun" src="static/moon.png" alt="mode" />
<img class="moon-sun" src="static/sun.png" alt="mode" /> Made by made by
<a href="https://www.freepik.com" title="Freepik">Freepik</a> from
<a href="https://www.flaticon.com/" title="Flaticon"
>www.flaticon.com</a
>
</div>
<p>Icons</p>
</footer>

View File

@ -22,15 +22,20 @@ const lightDarkModeEl = document.getElementsByClassName(
"light-dark-mode"
)[0]! as HTMLDivElement;
const canvasEl = document.querySelector("canvas")! as HTMLCanvasElement;
const ctx = canvasEl.getContext("2d")!;
const bodyEl = document.querySelector("body")! as HTMLBodyElement;
const modeEl = lightDarkModeEl.querySelector("img")! as HTMLImageElement;
const canvasWrapper = document.getElementsByClassName(
"roulette-wheel"
)[0]! as HTMLDivElement;
const winnerEl = document.getElementsByClassName(
"winner"
)[0]! as HTMLDivElement;
const footerEl = document.querySelector("footer")!;
const authorsEl = document.getElementsByClassName(
"icons-authors"
)[0]! as HTMLDivElement;
const canvasWrapper = document.getElementsByClassName(
"roulette-wheel"
)[0]! as HTMLDivElement;
const ctx = canvasEl.getContext("2d")!;
canvasEl.width = canvasWrapper.offsetWidth;
canvasEl.height = canvasWrapper.offsetHeight;
@ -47,12 +52,12 @@ const itemsList = new ItemList(MAXIMUM_SIZE);
const items: MenuItem[] = [];
let rotate_by = 50;
let totalTime = 0;
configure();
function configure() {
counterEl.textContent = `0/${MAXIMUM_SIZE}`;
winnerEl.style.fontSize = "32px";
LightDarkMode.currentMode = "dark";
IdPool.initializeIdsPool(MAXIMUM_SIZE);
@ -63,37 +68,47 @@ function configure() {
drawRouletteWheel(0);
canvasEl.addEventListener("click", startRoulette);
footerEl.addEventListener("click", () => {
authorsEl.hidden = !authorsEl.hidden;
});
}
function addRemoveItem() {
addButtonEl.addEventListener("click", () => {
const name = inputEl.value;
if (name) {
const id = IdPool.getAnId();
if (id) {
const color = avaliableRGBs[id % avaliableRGBs.length];
const item = new Item(id, name, color);
const menuItem = new MenuItem(id, name, color);
if (!animationId) {
clearWinner();
const name = inputEl.value;
if (name) {
const id = IdPool.getAnId();
if (id) {
const color = avaliableRGBs[id % avaliableRGBs.length];
const item = new Item(id, name, color);
const menuItem = new MenuItem(id, name, color);
menuItem.deleteItem.el.addEventListener("click", () => {
menuItem.el.remove();
items.splice(items.indexOf(menuItem), 1);
itemsList.remove(item);
IdPool.addId(item.id);
menuItem.deleteItem.el.addEventListener("click", () => {
if (!animationId) {
clearWinner();
menuItem.el.remove();
items.splice(items.indexOf(menuItem), 1);
itemsList.remove(item);
IdPool.addId(item.id);
updateCounter();
drawRouletteWheel(0);
}
});
registerChangeColorByClick(item, menuItem);
itemsList.add(item);
items.push(menuItem);
itemListEl.appendChild(menuItem.el);
updateCounter();
guessItemIndex = Math.floor(Math.random() * items.length);
segmentAngle = 360 / items.length;
maxAngle = 360 * ROTATIONS + segmentAngle * guessItemIndex;
drawRouletteWheel(0);
});
registerChangeColorByClick(item, menuItem);
itemsList.add(item);
items.push(menuItem);
itemListEl.appendChild(menuItem.el);
updateCounter();
guessItemIndex = Math.floor(Math.random() * items.length);
segmentAngle = 360 / items.length;
maxAngle = 360 * ROTATIONS + segmentAngle * guessItemIndex;
drawRouletteWheel(0);
}
}
}
});
@ -108,32 +123,59 @@ function addItemByEnter() {
function registerChangeColorByClick(item: Item, menuItem: MenuItem) {
menuItem.el.addEventListener("click", () => {
const actualColorIndex = avaliableRGBs.indexOf(
menuItem.el.style.backgroundColor
);
if (actualColorIndex !== -1) {
const color =
avaliableRGBs[(actualColorIndex + 1) % avaliableRGBs.length];
menuItem.el.style.backgroundColor = color;
item.color = color;
if (!animationId) drawRouletteWheel(0);
if (!animationId) {
const actualColorIndex = avaliableRGBs.indexOf(
menuItem.el.style.backgroundColor
);
if (actualColorIndex !== -1) {
const color =
avaliableRGBs[(actualColorIndex + 1) % avaliableRGBs.length];
menuItem.el.style.backgroundColor = color;
item.color = color;
drawRouletteWheel(0);
}
}
});
}
function removeAllItems() {
removeAllItemsButtonEl.addEventListener("click", () => {
if (items.length > 0) {
items.forEach((menuItem) => menuItem.el.remove());
items.length = 0;
itemsList.clear();
IdPool.initializeIdsPool(MAXIMUM_SIZE);
updateCounter();
drawRouletteWheel(0);
if (!animationId) {
clearWinner();
if (items.length > 0) {
items.forEach((menuItem) => menuItem.el.remove());
items.length = 0;
itemsList.clear();
IdPool.initializeIdsPool(MAXIMUM_SIZE);
updateCounter();
drawRouletteWheel(0);
}
}
});
}
function lightDarkMode() {
lightDarkModeEl.addEventListener("click", () => {
modeEl.animate([{ transform: "rotate(360deg)" }], {
duration: 500,
});
if (LightDarkMode.currentMode == "dark") {
modeEl.src = "static/sun.png";
bodyEl.style.backgroundColor = "#FAF9F6";
bodyEl.style.color = "black";
LightDarkMode.currentMode = "light";
} else {
modeEl.src = "static/moon.png";
bodyEl.style.backgroundColor = "#121212";
bodyEl.style.color = "white";
LightDarkMode.currentMode = "dark";
}
});
}
function updateCounter() {
counterEl.textContent = `${itemsList.items.length}/${MAXIMUM_SIZE}`;
animateCounter();
@ -141,11 +183,7 @@ function updateCounter() {
function animateCounter() {
counterEl.animate(
[
{ transform: "scale(1.5)" },
{ transform: "scale(1.00)" },
{ transform: "" },
],
[{ transform: "scale(1.5)" }, { transform: "scale(1.00)" }],
{
duration: 500,
}
@ -162,25 +200,6 @@ function animateWinner() {
);
}
function lightDarkMode() {
lightDarkModeEl.addEventListener("click", () => {
modeEl.animate([{ transform: "rotate(360deg)" }], {
duration: 500,
});
if (LightDarkMode.currentMode == "dark") {
modeEl.src = "static/sun.png";
bodyEl.style.backgroundColor = "#FAF9F6";
bodyEl.style.color = "black";
} else {
modeEl.src = "static/moon.png";
bodyEl.style.backgroundColor = "#121212";
bodyEl.style.color = "white";
}
LightDarkMode.changeMode();
});
}
function drawRouletteWheel(angle: number) {
const segmentWidth = 360 / items.length;
let startAngle = angle;
@ -242,24 +261,14 @@ let animationId: number | null;
let winner: string;
let endTime: number;
function easeOut(
time: number,
beginningVal: number,
toChange: number,
duration: number
) {
return time == duration
? beginningVal + toChange
: toChange * (-Math.pow(2, (-10 * time) / duration) + 1) + beginningVal;
}
function startRoulette() {
if (!animationId) {
if (winner) {
winner = "";
winnerEl.textContent = "";
const winnerCleared = clearWinner();
if (winnerCleared) {
drawRouletteWheel(0);
} else {
addButtonEl.style.background = "#C0C0C0";
removeAllItemsButtonEl.style.background = "#C0C0C0";
guessItemIndex = Math.floor(Math.random() * items.length);
winner = itemsList.items[guessItemIndex].name;
segmentAngle = 360 / items.length;
@ -274,8 +283,15 @@ function startRoulette() {
}
}
function clearWinner() {
if (winner) {
winner = "";
winnerEl.textContent = "";
return true;
}
return false;
}
let totalTime = 0;
function beginAnimateRoulette() {
const angle = easeOut(totalTime, 0, maxAngle, endTime);
if (totalTime < endTime || maxAngle - angle > 0.1) {
@ -288,12 +304,20 @@ function beginAnimateRoulette() {
window.cancelAnimationFrame(animationId!);
animationId = null;
winnerEl.textContent = `Winner: ${winner}`;
addButtonEl.style.background = "#6082B6";
removeAllItemsButtonEl.style.background = "#6082B6";
animateWinner();
}
}
const footerEl = document.querySelector('footer')!;
const authorsEl = document.getElementsByClassName('icons-authors')[0]! as HTMLDivElement;
footerEl.addEventListener('click', () => {
authorsEl.hidden = !authorsEl.hidden;
});
function easeOut(
time: number,
beginningVal: number,
toChange: number,
duration: number
) {
return time == duration
? beginningVal + toChange
: toChange * (-Math.pow(2, (-10 * time) / duration) + 1) + beginningVal;
}

View File

@ -1,15 +1,15 @@
export abstract class Component<T extends HTMLElement> {
el: T;
el: T;
constructor(el: T){
this.el = el;
}
constructor(el: T) {
this.el = el;
}
removeChildren() {
if(this.el.childNodes.length > 0){
while(this.el.firstChild){
this.el.removeChild(this.el.firstChild);
}
}
removeChildren() {
if (this.el.childNodes.length > 0) {
while (this.el.firstChild) {
this.el.removeChild(this.el.firstChild);
}
}
}
}
}

View File

@ -1,13 +1,12 @@
import { Component } from "./base-component";
export class ItemRemoval extends Component<HTMLImageElement>{
constructor(id: number){
const el = document.createElement('img');
el.src = 'static/close.png';
el.alt = 'delete';
el.className = `item-delete`;
el.id = `${id}-delete`
super(el);
}
}
export class ItemRemoval extends Component<HTMLImageElement> {
constructor(id: number) {
const el = document.createElement("img");
el.src = "static/close.png";
el.alt = "delete";
el.className = `item-delete`;
el.id = `${id}-delete`;
super(el);
}
}

View File

@ -2,28 +2,27 @@ import { Component } from "./base-component";
import { ItemRemoval } from "./item-removal";
export class MenuItem extends Component<HTMLLIElement> {
deleteItem: ItemRemoval;
deleteItem: ItemRemoval;
constructor(id: number, name: string, color: string) {
const deleteItem = new ItemRemoval(id);
const el = document.createElement("li");
el.className = "menu-item";
el.id = `${id}-item`;
el.textContent = name;
el.style.backgroundColor = color;
el.appendChild(deleteItem.el);
super(el);
this.deleteItem = deleteItem;
this.appearAnimation();
}
constructor(id: number, name: string, color: string){
const deleteItem = new ItemRemoval(id);
const el = document.createElement('li');
el.className = 'menu-item';
el.id = `${id}-item`;
el.textContent = name;
el.style.backgroundColor = color;
el.appendChild(deleteItem.el);
super(el);
this.deleteItem = deleteItem;
this.appearAnimation();
}
appearAnimation(){
this.el.animate(
[{ transform: "scale(1.25)" }, { transform: "scale(1.00)" }],
{
duration: 500,
}
);
}
}
appearAnimation() {
this.el.animate(
[{ transform: "scale(1.25)" }, { transform: "scale(1.00)" }],
{
duration: 500,
}
);
}
}

View File

@ -2,31 +2,30 @@ import { Item } from "./item";
import { List } from "./list";
export class ItemList implements List<Item> {
items: Item[];
maximumSize: number;
items: Item[];
maximumSize: number;
constructor(maxSize: number){
this.items = [];
this.maximumSize = maxSize;
}
constructor(maxSize: number) {
this.items = [];
this.maximumSize = maxSize;
}
add(item: Item){
if(this.items.length < this.maximumSize)
this.items.push(item);
}
add(item: Item) {
if (this.items.length < this.maximumSize) this.items.push(item);
}
removeById(id: number){
const toRemove = this.items.find(e => e.id === id);
if(toRemove){
this.remove(toRemove);
}
removeById(id: number) {
const toRemove = this.items.find((e) => e.id === id);
if (toRemove) {
this.remove(toRemove);
}
}
remove(item: Item){
this.items.splice(this.items.indexOf(item), 1);
}
remove(item: Item) {
this.items.splice(this.items.indexOf(item), 1);
}
clear(){
this.items = [];
}
}
clear() {
this.items = [];
}
}

View File

@ -1,5 +1,5 @@
export interface List<T> {
items: T[];
add(item: T): void;
}
items: T[];
add(item: T): void;
}

View File

@ -16,7 +16,7 @@ export abstract class IdPool {
return id;
}
static addId(id: number){
static addId(id: number) {
this.avaliableIds.push(id);
}
}

View File

@ -1,13 +1,5 @@
type mode = 'dark' | 'light';
type mode = "dark" | "light";
export abstract class LightDarkMode{
static currentMode: mode;
static changeMode(){
if(this.currentMode == 'light'){
this.currentMode = 'dark';
}else{
this.currentMode = 'light';
}
}
export abstract class LightDarkMode {
static currentMode: mode;
}