diff --git a/app.css b/app.css index 37d54e6..b1ed244 100644 --- a/app.css +++ b/app.css @@ -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; } -} \ No newline at end of file +} diff --git a/index.html b/index.html index 69c26bd..eef467a 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@
- mode + mode
diff --git a/src/app.ts b/src/app.ts index c9ad9a3..c199ceb 100644 --- a/src/app.ts +++ b/src/app.ts @@ -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; +} diff --git a/src/components/base-component.ts b/src/components/base-component.ts index 921615f..a7e4ef3 100644 --- a/src/components/base-component.ts +++ b/src/components/base-component.ts @@ -1,15 +1,15 @@ export abstract class Component { - 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); + } } -} \ No newline at end of file + } +} diff --git a/src/components/item-removal.ts b/src/components/item-removal.ts index 5033091..4ab327b 100644 --- a/src/components/item-removal.ts +++ b/src/components/item-removal.ts @@ -1,13 +1,12 @@ import { Component } from "./base-component"; -export class ItemRemoval extends Component{ - - 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); - } -} \ No newline at end of file +export class ItemRemoval extends Component { + 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); + } +} diff --git a/src/components/menu-item.ts b/src/components/menu-item.ts index c32d969..dd7aec3 100644 --- a/src/components/menu-item.ts +++ b/src/components/menu-item.ts @@ -2,28 +2,27 @@ import { Component } from "./base-component"; import { ItemRemoval } from "./item-removal"; export class MenuItem extends Component { + 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, - } - ); - } -} \ No newline at end of file + appearAnimation() { + this.el.animate( + [{ transform: "scale(1.25)" }, { transform: "scale(1.00)" }], + { + duration: 500, + } + ); + } +} diff --git a/src/model/item-list.ts b/src/model/item-list.ts index 2e21338..e384287 100644 --- a/src/model/item-list.ts +++ b/src/model/item-list.ts @@ -2,31 +2,30 @@ import { Item } from "./item"; import { List } from "./list"; export class ItemList implements List { - 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 = []; - } -} \ No newline at end of file + clear() { + this.items = []; + } +} diff --git a/src/model/list.ts b/src/model/list.ts index c74bdc9..706ea9a 100644 --- a/src/model/list.ts +++ b/src/model/list.ts @@ -1,5 +1,5 @@ export interface List { - items: T[]; - - add(item: T): void; -} \ No newline at end of file + items: T[]; + + add(item: T): void; +} diff --git a/src/utils/item-id-pool.ts b/src/utils/item-id-pool.ts index 7de4747..04815a5 100644 --- a/src/utils/item-id-pool.ts +++ b/src/utils/item-id-pool.ts @@ -16,7 +16,7 @@ export abstract class IdPool { return id; } - static addId(id: number){ + static addId(id: number) { this.avaliableIds.push(id); } } diff --git a/src/utils/light-dark-mode.ts b/src/utils/light-dark-mode.ts index 5fe5db2..eda73bb 100644 --- a/src/utils/light-dark-mode.ts +++ b/src/utils/light-dark-mode.ts @@ -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; }