Refactor codebase. Functioning item list

This commit is contained in:
Alex Piqueras 2024-10-10 20:04:31 +02:00
parent a9eaa5dbde
commit 37401a85c8
7 changed files with 46 additions and 82 deletions

View File

@ -8,8 +8,24 @@
<link rel="icon" href="./favicon.ico" type="image/x-icon"> <link rel="icon" href="./favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<script type="module" src="src/main.js" defer></script> <script type="module" src="src/components/app-base.js" defer></script>
<main id="root"></main> <script type="module" src="src/components/main-window.js" defer></script>
<script type="module" src="src/components/custom-button.js" defer></script>
<script type="module" src="src/components/item-list.js" defer></script>
<style>
html {
height: 100%;
}
body {
background: transparent linear-gradient(135deg, #A1C4FD 0%, #C2E9FB 100%) 0% 0% no-repeat padding-box;
opacity: 1;
display: flex;
justify-content: center;
align-items: center;
min-height: 100%;
}
</style>
<app-base></app-base>
</body> </body>
</html> </html>

View File

@ -2,8 +2,6 @@ import Store from '../modules/store.js';
import text from '../modules/text.js'; import text from '../modules/text.js';
class AppBase extends HTMLElement { class AppBase extends HTMLElement {
static observedAttributes = ['title', 'description'];
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: 'open' });
@ -14,25 +12,18 @@ class AppBase extends HTMLElement {
connectedCallback() { connectedCallback() {
this.store.subscribe(this.render.bind(this)); this.store.subscribe(this.render.bind(this));
this.render(); this.render();
console.log('Component constructed', this);
}
disconnectedCallback() {
console.log('Component disconnected', this);
}
attributeChangedCallback() {
this.render();
} }
renderText() { renderText() {
const textList = this.store.getRecords(); const textList = this.store.getRecords();
const selected = this.store.getSelected(); return textList.map((item) => `<option value=${item.id}>${item.text}</option>`).join('\n');
return textList.map((item) => `<option value=${item.id} ${selected.includes(item.id) && "selected"}>${item.text}</option>`).join('\n');
} }
render() { render(action = 'INITIAL') {
if (![Store.actions.ADD_LINE, Store.actions.REMOVE_LINE, Store.actions.UNDO, 'INITIAL'].includes(action)) {
return; // Only render if content changed
}
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<main-window title="${this.text.title}" description="${this.text.description}"> <main-window title="${this.text.title}" description="${this.text.description}">
<select multiple is="item-list"> <select multiple is="item-list">

View File

@ -16,14 +16,10 @@ class CustomButton extends HTMLElement {
connectedCallback() { connectedCallback() {
this.render(); this.render();
this.shadowRoot.getElementById('button').addEventListener('click', this.onClick.bind(this)); this.shadowRoot.getElementById('button').addEventListener('click', this.onClick.bind(this));
console.log('Component constructed', this);
} }
disconnectedCallback() { disconnectedCallback() {
this.shadowRoot.getElementById('button').removeEventListener('click', this.onClick); this.shadowRoot.getElementById('button').removeEventListener('click', this.onClick);
console.log('Component disconnected', this);
} }
attributeChangedCallback() { attributeChangedCallback() {
@ -52,7 +48,9 @@ class CustomButton extends HTMLElement {
text-transform: uppercase; text-transform: uppercase;
} }
</style> </style>
<button id="button"><slot></slot></button> <button id="button">
<slot></slot>
</button>
`; `;
} }
} }

View File

@ -9,23 +9,15 @@ class ItemList extends HTMLSelectElement {
connectedCallback() { connectedCallback() {
this.addEventListener('click', this.onChange.bind(this)); this.addEventListener('click', this.onChange.bind(this));
this.updateStyle(); this.updateStyle();
console.log('Component constructed', this);
} }
onChange() { onChange() {
const selectedIds = Array.from(this.selectedOptions).map((option) => option.value); const selectedIds = Array.from(this.selectedOptions).map((option) => +option.value);
this.publish(Store.actions.SELECT, selectedIds); this.publish(Store.actions.SELECT, selectedIds);
} }
disconnectedCallback() { disconnectedCallback() {
this.removeEventListener('change', this.onChange.bind(this)); this.removeEventListener('click', this.onChange.bind(this));
console.log('Component disconnected', this);
}
attributeChangedCallback() {
this.updateStyle();
} }
updateStyle() { updateStyle() {

View File

@ -8,11 +8,6 @@ class MainWindow extends HTMLElement {
connectedCallback() { connectedCallback() {
this.render(); this.render();
console.log('Component constructed', this);
}
disconnectedCallback() {
console.log('Component disconnected', this);
} }
attributeChangedCallback() { attributeChangedCallback() {
@ -25,7 +20,7 @@ class MainWindow extends HTMLElement {
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
div { #window {
width: 900px; width: 900px;
height: 577px; height: 577px;
background: #FFFFFF 0% 0% no-repeat padding-box; background: #FFFFFF 0% 0% no-repeat padding-box;
@ -33,12 +28,10 @@ class MainWindow extends HTMLElement {
border-radius: 20px; border-radius: 20px;
opacity: 1; opacity: 1;
} }
#content {
span {
width: 800px; width: 800px;
margin: 0 50px 13px 50px; margin: 0 50px 13px 50px;
} }
h1 { h1 {
top: 221px; top: 221px;
margin: 50px 50px 13px 50px; margin: 50px 50px 13px 50px;
@ -66,14 +59,13 @@ class MainWindow extends HTMLElement {
color: #333333; color: #333333;
opacity: 1; opacity: 1;
} }
slot {
margin: 0 50px 0 50px;
}
</style> </style>
<div> <div id="window">
<h1>${title}</h1> <h1>${title}</h1>
<p>${description}</p> <p>${description}</p>
<span><slot></slot></span> <div id="content" >
<slot></slot>
<div/>
</div> </div>
`; `;
} }

View File

@ -3,32 +3,3 @@ import './components/main-window.js';
import './components/custom-button.js'; import './components/custom-button.js';
import './components/item-list.js'; import './components/item-list.js';
class App {
constructor(root, text, store) {
this.root = root;
}
start() {
this.root.innerHTML = `
<style>
html {
height: 100%;
}
body {
background: transparent linear-gradient(135deg, #A1C4FD 0%, #C2E9FB 100%) 0% 0% no-repeat padding-box;
opacity: 1;
display: flex;
justify-content: center;
align-items: center;
min-height: 100%;
}
</style>
<app-base></app-base>
`;
}
}
const app = new App(document.getElementById('root'));
app.start();

View File

@ -11,7 +11,7 @@ export default class Store {
records: [], records: [],
selected: [], selected: [],
}; };
this.callbacks = []; this.callbacks = [() => console.log(this.state)];
Object.values(this.constructor.actions).forEach(action => document.addEventListener(action, this.eventHandler.bind(this), false)); Object.values(this.constructor.actions).forEach(action => document.addEventListener(action, this.eventHandler.bind(this), false));
} }
@ -48,12 +48,15 @@ export default class Store {
}; };
break; break;
case this.constructor.actions.REMOVE_LINE: case this.constructor.actions.REMOVE_LINE:
const linesToRemove = this.state.selected.map((id, index) => ({
id: this.state.records.length + index,
targetId: id,
action: 'remove',
}));
this.state = { this.state = {
...this.state, ...this.state,
records: this.records.concat({ records: [ ...this.state.records, ...linesToRemove],
id: this.state.records.length, selected: [],
action: 'remove',
}),
}; };
break; break;
case this.constructor.actions.UNDO: case this.constructor.actions.UNDO:
@ -73,11 +76,11 @@ export default class Store {
return; return;
} }
this.callbacks.forEach((cb) => cb()); this.callbacks.forEach((cb) => cb(event.type));
} }
getRecords() { getRecords() {
return this.state.records.reduce((acc, current) => { const result = this.state.records.reduce((acc, current) => {
if (current.action === "add") { if (current.action === "add") {
return acc.concat({id: current.id, text: current.text}); return acc.concat({id: current.id, text: current.text});
} }
@ -86,6 +89,7 @@ export default class Store {
} }
console.error(`Action ${current.action} not valid`); console.error(`Action ${current.action} not valid`);
}, []); }, []);
return result;
} }
getSelected() { getSelected() {