Add modal

This commit is contained in:
Alex Piqueras 2024-10-11 13:29:37 +02:00
parent 8f383240ce
commit 7be76dd2f9
9 changed files with 136 additions and 114 deletions

View File

@ -8,23 +8,7 @@
<link rel="icon" href="./favicon.ico" type="image/x-icon">
</head>
<body>
<script type="module" src="src/components/app-base.js" defer></script>
<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>
<script type="module" src="src/app.js" defer></script>
<app-base></app-base>
</body>
</html>

View File

@ -1,10 +1,14 @@
import Store from '../modules/store.js';
import text from '../modules/text.js';
import './components/main-window.js';
import './components/custom-button.js';
import './components/item-list.js';
import './components/custom-modal.js';
import Store from './modules/store.js';
import text from './modules/text.js';
class AppBase extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.text = text;
this.properties = {
color: '#324BFF',
@ -23,47 +27,51 @@ class AppBase extends HTMLElement {
}
render(action = 'INIT') {
if (![Store.actions.ADD_LINE, Store.actions.REMOVE_LINE, Store.actions.UNDO, 'INIT'].includes(action)) {
if (![Store.actions.OPEN_MODAL, Store.actions.CLOSE_MODAL, Store.actions.ADD_LINE, Store.actions.REMOVE_LINE, Store.actions.UNDO, 'INIT'].includes(action)) {
return; // Only render if content changed
}
this.shadowRoot.innerHTML = `
this.innerHTML = `
<style>
* {
margin: 0;
}
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%;
font-family: "Montserrat", sans-serif;
font-weight: normal;
letter-spacing: 0px;
}
#title {
height: 49px;;
height: 49px;
margin-bottom: -12px;
text-align: center;
font-size: 40px;
font-family: "Montserrat", sans-serif;
font-weight: normal;
letter-spacing: 0px;
font-weight: inherit;
color: #333333;
opacity: 1;
}
#description {
text-align: center;
height: 74px;
text-align: center;
font-size: 18px;
font-family: "Montserrat", sans-serif;
font-weight: normal;
letter-spacing: 0px;
color: #333333;
opacity: 1;
}
#list {
padding: 13px;
}
#list > option {
height: 40px;
align-content: center;
padding-left: 15px;
font-size: 18px;
font-family: "Montserrat", sans-serif;
font-weight: normal;
}
#list > option:checked {
background: ${this.properties.color} linear-gradient(0deg, ${this.properties.color} 0%, ${this.properties.color} 100%);
@ -71,24 +79,24 @@ class AppBase extends HTMLElement {
color: #fff;
outline: none;
}
#button-bar {
.button-bar {
display: flex;
column-gap: 35px
}
#button-bar > custom-button:last-child {
.button-bar > .right-button {
margin-left: auto;
}
#undo-char {
margin-top: 3px;
}
</style>
<main-window width="900px" height="577px" gap="35px">
<main-window width="900px" gap="35px">
<h1 id="title">${this.text.title}</h1>
<p id="description">${this.text.description}</p>
<select id="list" multiple is="item-list">
<select id="list" multiple is="item-list" height="227px">
${this.renderOptions()}
</select>
<span id="button-bar">
<span class="button-bar">
<custom-button action="${Store.actions.UNDO}" outline width="81px" color="${this.properties.color}">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="undo-char" width="21" height="19" viewBox="0 0 5.556 5.027">
<path d="M.681 2.22a2.38 2.38 0 0 1 4.742.294v0a2.38 2.38 0 0 1-4.526 1.03" style="fill:none;stroke:${this.properties.color};stroke-width:.264583;stroke-linecap:round;stroke-dasharray:none"/>
@ -97,9 +105,17 @@ class AppBase extends HTMLElement {
</custom-button>
<custom-button action="${Store.actions.REMOVE_LINE}" outline width="124px" color="${this.properties.color}">Delete</custom-button>
<custom-button action="${Store.actions.ADD_LINE}" width="138px" color="${this.properties.color}">Add</custom-button>
<custom-button class="right-button" action="${Store.actions.OPEN_MODAL}" width="138px" color="${this.properties.color}">Add</custom-button>
</span>
</main-window>
<custom-modal active="${this.store.state.modalActive}">
<p>${text.modal.description}</p>
<input type="text"/>
<span class="button-bar">
<custom-button class="right-button" action="${Store.actions.ADD_LINE}" width="138px" color="${this.properties.color}">Add</custom-button>
<custom-button action="${Store.actions.CLOSE_MODAL}" outline width="124px" color="${this.properties.color}">Cancel</custom-button>
</span>
</custom-modal>
`;
}
}

View File

@ -0,0 +1,59 @@
class CustomModal extends HTMLElement {
static observedAttributes = ['active'];
#templateHtml = `
<style>
div.overlay {
position: fixed;
margin: 0;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
padding-top: 50px;
justify-content: center;
background: #0000001A 0% 0% no-repeat padding-box;
opacity: 1;
transition: all 0.35s ease-in;
}
mainWindow {
top: 25px;
transition: all 0.35s ease-in;
}
</style>
<div class="overlay">
<main-window width="700px" gap="25px">
<slot></slot>
</main-window>
</div>
`;
constructor() {
super();
this.attachShadow({ mode: 'open' });
const template = document.createElement('template')
template.innerHTML = this.#templateHtml;
this.shadowRoot.appendChild(template.content.cloneNode(true));
this.overlay = this.shadowRoot.querySelector('div.overlay');
console.log(this.overlay);
this.mainWindow = this.shadowRoot.querySelector('main-window');
}
connectedCallback() {
this.updateStyle();
}
attributeChangedCallback() {
console.log("attributeChanged");
this.updateStyle();
}
updateStyle() {
console.log(this.getAttribute('active'), typeof this.getAttribute('active'));
this.overlay.style.visibility = this.getAttribute('active') === "true" ? 'visible' : 'hidden';
}
}
customElements.define('custom-modal', CustomModal);

View File

@ -1,6 +1,7 @@
import Store from '../modules/store.js';
class ItemList extends HTMLSelectElement {
static observedAttributes = ['height'];
constructor() {
super();
this.publish = Store.publish
@ -20,16 +21,23 @@ class ItemList extends HTMLSelectElement {
this.removeEventListener('click', this.onChange.bind(this));
}
attributeChangedCallback() {
this.updateParametrizedStyle();
}
updateParametrizedStyle() {
this.style.height = this.getAttribute('height');
}
updateStyle() {
this.style.width = '100%';
this.style.height = '227px';
this.style.background = '#F7F7F7 0% 0% no-repeat padding-box';
this.style.border = '1px solid #CCCCCC';
this.style.opacity = '1';
this.style.fontSize = '18px';
this.style.fontFamily = '"Montserrat" sans-serif';
this.style.fontWeight = 'normal';
this.style.letterSpacing = '0px';
this.style.padding = '13px';
this.style.boxSizing = 'border-box';
this.updateParametrizedStyle();
}
}

View File

@ -1,5 +1,5 @@
class MainWindow extends HTMLElement {
static observedAttributes = ['width', 'height', 'gap'];
static observedAttributes = ['width', 'gap'];
constructor() {
super();
@ -20,7 +20,6 @@ class MainWindow extends HTMLElement {
<style>
div {
width: ${this.getAttribute('width')};
height: ${this.getAttribute('height')};
box-sizing: border-box;
padding: 50px;
background: #FFFFFF 0% 0% no-repeat padding-box;

View File

@ -1,57 +0,0 @@
import Store from '../modules/store.js';
class CustomModal extends HTMLElement {
static observedAttributes = ['active', 'color', 'action'];
constructor() {
super();
this.publish = Store.publish;
this.attachShadow({ mode: 'open' });
}
onClick(e) {
this.publish(this.getAttribute('action'));
}
connectedCallback() {
this.render();
this.shadowRoot.getElementById('button').addEventListener('click', this.onClick.bind(this));
}
disconnectedCallback() {
this.shadowRoot.getElementById('button').removeEventListener('click', this.onClick);
}
attributeChangedCallback() {
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
button {
border-radius: 50px;
border-width: 1px;
border-style: ${isOutline ? 'solid' : 'hidden'};
border-color: ${this.getAttribute('color')};
opacity: 1;
width: ${this.getAttribute('width')};
height: 49px;
background-color: ${isOutline ? 'white' : this.getAttribute('color')};
color: ${isOutline ? this.getAttribute('color') : 'white'};
text-align: center;
font-size: 16px;
font-family: "Montserrat", sans-serif;
font-weight: normal
letter-spacing: 0px;
text-transform: uppercase;
}
</style>
<main-window width="700px" height="276px" gap="25px">
<slot></slot>
</main-window>
`;
}
}
customElements.define('custom-modal', CustomModal);

View File

@ -1,6 +1 @@
import './components/app-base.js';
import './main-window.js';
import './components/custom-button.js';
import './components/item-list.js';
import './components/custom-modal.js';

View File

@ -4,12 +4,15 @@ export default class Store {
REMOVE_LINE: 'REMOVE_LINE',
UNDO: 'UNDO',
SELECT: 'SELECT',
OPEN_MODAL: 'OPEN_MODAL',
CLOSE_MODAL: 'CLOSE_MODAL',
}
constructor() {
this.state = {
records: [],
selected: [],
modalActive: false,
};
this.callbacks = [() => console.log(this.state)];
@ -74,6 +77,18 @@ export default class Store {
selected: event.detail,
}
break;
case this.constructor.actions.OPEN_MODAL:
this.state = {
...this.state,
modalActive: true,
}
break;
case this.constructor.actions.CLOSE_MODAL:
this.state = {
...this.state,
modalActive: false,
}
break;
default:
console.error(`Action "${event.type}" not implemented in eventHandler`);
return;

View File

@ -1,4 +1,7 @@
export default {
title: 'This is a technical proof',
description: 'Lorem ipsum dolor sit amet consectetur adipiscing, elit mus primis nec inceptos. Lacinia habitasse arcu molestie maecenas cursus quam nunc, hendrerit posuere augue fames dictumst placerat porttitor, dis mi pharetra vestibulum venenatis phasellus.',
modal: {
description: 'Add item to list',
},
}