Add/remove/clear items

This commit is contained in:
p-wojt 2021-12-30 18:19:00 +01:00
parent 078eb30b21
commit 656e157f14
11 changed files with 272 additions and 7 deletions

62
app.css Normal file
View File

@ -0,0 +1,62 @@
html {
font-family: 'Courier New', Courier, monospace;
}
canvas {
margin: 0;
position: absolute;
width: 500px;
height: 500px;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}
input {
height: 1.5rem;
width: 15rem;
}
ul {
list-style-type: none;
padding: 0;
text-align: center;
}
li {
padding: 0.75rem;
}
.openCloseMenu {
width: 1rem;
height: 1rem;
}
.item-delete {
width: 1rem;
height: 1rem;
float: right;
}
#menu {
height: 100vh;
width: 20rem;
}
#newItemButton {
height: 2rem;
width: 10rem;
margin-top: 0.5rem;
}
#menu-item {
text-align: center;
}
#counter {
font-size: 24px;
text-align: center;
}

View File

@ -5,8 +5,21 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Roulette wheel</title>
<script type="module" src="dist/bundle.js"></script>
<link rel="stylesheet" href="app.css">
</head>
<body>
Test!
<div id="menu">
<img src="static/right-arrow.png" alt="open-close-arrow" class="openCloseMenu">
<p id="counter">0/16</p>
<div id="newItem">
<label for="newItem">Item name</label>
<input name="newItem" minlength="1" maxlength="32">
<button id="newItemButton">Add</button>
<button id="removeAllItemsButton">Remove all</button>
</div>
</div>
<canvas></canvas>
<footer><div>Icons made by <a href="https://www.flaticon.com/authors/roundicons" title="Roundicons">Roundicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div></footer>
</body>
</html>

View File

@ -0,0 +1,99 @@
import { ItemEl } from "./components/menu-item";
import { ItemElList } from "./components/menu-item-list";
const canvas = document.querySelector("canvas")! as HTMLCanvasElement;
const ctx = canvas.getContext("2d")!;
const centreX = canvas.width / 2;
const centreY = canvas.height / 2;
ctx.beginPath();
ctx.moveTo(centreX, centreY);
ctx.stroke();
console.log("Works!");
const maxItems = 16;
const items: ItemElList = new ItemElList();
const menuEl = document.getElementById("menu")! as HTMLDivElement;
const counterEl = document.getElementById("counter")!;
const itemNameInput = document.querySelector("input")! as HTMLInputElement;
const newItemButtonEl = document.getElementById(
"newItemButton"
)! as HTMLButtonElement;
const removeAllItemsButtonEl = document.getElementById(
"removeAllItemsButton"
)! as HTMLButtonElement;
menuEl.appendChild(items.el);
const avaliableRGBs = ["255, 0, 0", "0, 255, 0", "0, 0, 255"];
const bgOpacity = 0.5;
let nextColor = avaliableRGBs[0];
let counter = 0;
const idsPool: number[] = [];
initalizeIdsPool();
function addNewItem() {
if (itemNameInput.value.length > 0 && itemNameInput.value.length <= 32) {
if (counter < maxItems && idsPool.length > 0) {
const item = new ItemEl(
idsPool.pop()!,
itemNameInput.value,
`rgba(${nextColor}, ${bgOpacity})`
);
item.deleteItem.el.addEventListener("click", () => {
const itemElId = calculateItemElId(item);
idsPool.push(itemElId);
setNextColor();
items.removeItem(item);
counter--;
updateCounter();
});
items.addItem(item);
counter++;
updateCounter();
setNextColor();
} else {
alert("Maximum number of items!");
}
}
}
function removeAllItems() {
if (items.itemsLength > 0) {
items.clear();
counter = 0;
initalizeIdsPool();
nextColor = avaliableRGBs[0];
updateCounter();
} else {
alert("Nothing to clear!");
}
}
function updateCounter() {
counterEl.textContent = `${counter}/${maxItems}`;
}
function setNextColor() {
nextColor = avaliableRGBs[counter % avaliableRGBs.length];
}
function calculateItemElId(item: ItemEl) {
return +item.el.id.slice(0, item.el.id.indexOf("-"));
}
function initalizeIdsPool() {
idsPool.length = 0;
for (let i = 0; i < maxItems; i++) {
idsPool.push(i);
}
}
newItemButtonEl.addEventListener("click", addNewItem);
removeAllItemsButtonEl.addEventListener("click", removeAllItems);

View File

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

View File

@ -0,0 +1,17 @@
import { Component } from "./base-component";
export class DeleteItemEl 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);
}
configure(){
// TODO: make icon rotation after mouse over event
}
}

View File

@ -0,0 +1,40 @@
import { Component } from "./base-component";
import { ItemEl } from "./menu-item";
export class ItemElList extends Component<HTMLUListElement> {
private items: ItemEl[];
constructor(){
const UList = document.createElement('ul');
UList.className = 'item-list';
super(UList);
this.items = [];
}
get itemsLength() {
return this.items.length;
}
addItem(item: ItemEl){
this.items.push(item);
this.el.appendChild(item.el);
}
clear(){
this.removeChildren();
this.items = [];
}
removeItem(item: ItemEl){
item.el.remove();
const indexToRemove = this.items.indexOf(item);
this.items.splice(indexToRemove, 1);
}
findLastItem(){
if(this.items.length > 0){
return this.items[this.items.length - 1];
}
return null;
}
}

View File

@ -0,0 +1,19 @@
import { Component } from "./base-component";
import { DeleteItemEl } from "./menu-delete-item";
export class ItemEl extends Component<HTMLLIElement> {
deleteItem: DeleteItemEl;
constructor(id: number, value: string, color: string){
const deleteItem = new DeleteItemEl(id);
const el = document.createElement('li');
el.className = 'menu-item';
el.id = `${id}-item`;
el.textContent = value;
el.style.backgroundColor = color;
el.appendChild(deleteItem.el);
super(el);
this.deleteItem = deleteItem;
}
}

BIN
static/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
static/right-arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,18 +1,18 @@
const path = require('path');
module.exports = {
mode: "development",
mode: 'development',
entry: './src/app.ts',
output: {
path:path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: 'dist'
path:path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/dist/'
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.ts?$/,
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}

View File

@ -11,7 +11,7 @@ module.exports = {
module: {
rules: [
{
test: /\.ts?$/,
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}