Add items, choose user type
This commit is contained in:
parent
277aae9341
commit
4a21ba9a18
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
|
node_modules
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
* {
|
* {
|
||||||
--hover-color: #f18902;
|
--hover-color: #f18902;
|
||||||
--border-slim-color: #495057;
|
--border-slim-color: #495057;
|
||||||
|
--border-light-gray-color: #e5e5e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
705
assets/js/app.js
705
assets/js/app.js
@ -1,705 +0,0 @@
|
|||||||
const S = Symbol();
|
|
||||||
|
|
||||||
customElements.define('ow-nav', class extends HTMLElement {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
section {
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
align-content: stretch;
|
|
||||||
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: #2b2727;
|
|
||||||
font-family: Raleway, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 32px;
|
|
||||||
}
|
|
||||||
section::after {
|
|
||||||
display: block;
|
|
||||||
content: ' ';
|
|
||||||
border: none;
|
|
||||||
padding: 10px 18px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #2b2727;
|
|
||||||
text-transform: uppercase;
|
|
||||||
align-self: stretch;
|
|
||||||
flex-shrink: 20;
|
|
||||||
flex-grow: 20;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section>
|
|
||||||
<slot></slot>
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('ow-path', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['selected', 'path'];
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
a {
|
|
||||||
display: block;
|
|
||||||
padding: 10px 18px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #495057;
|
|
||||||
text-transform: uppercase;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid var(--border-slim-color);
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: var(--hover-color);
|
|
||||||
}
|
|
||||||
:host(:not([selected])) a {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<a><slot></slot></a>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.selected = this.getAttribute('selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
case 'selected':
|
|
||||||
return this.selected = newV;
|
|
||||||
case 'path':
|
|
||||||
return this.path = newV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get selected() {
|
|
||||||
return this.getAttribute('selected') === 'selected';
|
|
||||||
}
|
|
||||||
|
|
||||||
set selected(value) {
|
|
||||||
if (value === 'selected') this.setAttribute('selected', 'selected');
|
|
||||||
else this.removeAttribute('selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
get path() {
|
|
||||||
return this.getAttribute('path') || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
set path(value) {
|
|
||||||
if (!value || value === '') {
|
|
||||||
this.removeAttribute('path');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setAttribute('path', value);
|
|
||||||
this[S].querySelector('a').setAttribute('href', value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('local-services', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['filter']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
::slotted(local-service[local-services-visible="invisible"]) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
font-size: 20pt;
|
|
||||||
line-height: 2.6em;
|
|
||||||
height: 2.6em;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
border:none;
|
|
||||||
outline:none;
|
|
||||||
display: block;
|
|
||||||
background: transparent;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
text-indent: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section>
|
|
||||||
<input type="text" id="filter" placeholder="Filtruj" />
|
|
||||||
</section>
|
|
||||||
<section id="items">
|
|
||||||
<slot name="services"></slot>
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
{
|
|
||||||
const filter = shadow.querySelector('#filter');
|
|
||||||
let t = null;
|
|
||||||
filter.addEventListener('change', ev => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.filter = ev.target.value;
|
|
||||||
});
|
|
||||||
filter.addEventListener('keyup', ev => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
const value = ev.target.value;
|
|
||||||
|
|
||||||
if (t) clearTimeout(t);
|
|
||||||
t = setTimeout(() => {
|
|
||||||
this.filter = value;
|
|
||||||
t = null;
|
|
||||||
}, 1000 / 3);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.filter = this.getAttribute('filter');
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
case 'filter':
|
|
||||||
return this.filter = newV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get filter() {
|
|
||||||
return this.getAttribute('filter');
|
|
||||||
}
|
|
||||||
|
|
||||||
set filter(value) {
|
|
||||||
if (!value || value === '') {
|
|
||||||
this.removeAttribute('filter');
|
|
||||||
for (const el of this.querySelectorAll('local-service')) {
|
|
||||||
el.removeAttribute('local-services-visible');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setAttribute('filter', value);
|
|
||||||
for (const el of this.querySelectorAll('local-service')) {
|
|
||||||
if (!el.name) continue;
|
|
||||||
if (el.name.includes(value)) {
|
|
||||||
el.setAttribute('local-services-visible', 'visible');
|
|
||||||
} else {
|
|
||||||
el.setAttribute('local-services-visible', 'invisible');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('local-service', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['name', 'service-id', 'state']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
#items {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<h2 id="name"></h2>
|
|
||||||
<slot name="description"></slot>
|
|
||||||
<section id="items">
|
|
||||||
<slot name="item"></slot>
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this[S].querySelector('#name').textContent = this.getAttribute('name');
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
case 'name':
|
|
||||||
return this[S].querySelector('#name').textContent = newV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
|
||||||
return this.getAttribute('name') || ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
customElements.define('local-service-item', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['name', 'price']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
#item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
#price {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section id="item">
|
|
||||||
<h3 id="name"></h3>
|
|
||||||
<ow-price id="price" />
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this[S].querySelector('#name').textContent = this.getAttribute('name');
|
|
||||||
this[S].querySelector('#price').value = this.price();
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
case 'name':
|
|
||||||
return this[S].querySelector('#name').textContent = newV;
|
|
||||||
case 'price':
|
|
||||||
return this[S].querySelector('#price').value = newV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
price(s) {
|
|
||||||
const n = parseInt(s || this.getAttribute('price'));
|
|
||||||
return isNaN(n) ? 0 : n;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('ow-price', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['value', 'currency']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
#price {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<span id="price"></span>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this[S].querySelector('#price').textContent = this.formatted;
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
case 'price': {
|
|
||||||
this.value = newV;
|
|
||||||
this[S].querySelector('#price').textContent = this.formatted;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get formatted() {
|
|
||||||
let v = this.value;
|
|
||||||
let major = Math.ceil(v / 100);
|
|
||||||
let minor = v % 100;
|
|
||||||
let formatted = `${ major },${ minor < 10 ? `0${ minor }` : minor }`;
|
|
||||||
return `${ formatted }${ this.currency }`
|
|
||||||
}
|
|
||||||
|
|
||||||
get value() {
|
|
||||||
const n = parseInt(this.getAttribute('value'));
|
|
||||||
return isNaN(n) ? 0 : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(v) {
|
|
||||||
this.setAttribute('value', v)
|
|
||||||
}
|
|
||||||
|
|
||||||
get currency() {
|
|
||||||
return this.getAttribute('currency') || 'PLN'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('ow-account', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['mode']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
article > * {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
:host([mode="login"]) login-form, :host([mode="login"]) #switch-register {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
:host([mode="register"]) register-form, :host([mode="register"]) #switch-login {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
a{
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: var(--hover-color);
|
|
||||||
border-bottom-color: var(--hover-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<article>
|
|
||||||
<login-form></login-form>
|
|
||||||
<register-form></register-form>
|
|
||||||
<section id="switch-login">
|
|
||||||
<a>Nie masz konta? Utwórz nowe</a>
|
|
||||||
</section>
|
|
||||||
<section id="switch-register">
|
|
||||||
<a>Masz konta? Zaloguj się</a>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
`;
|
|
||||||
shadow.querySelector('#switch-login > a').addEventListener('click', ev => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
this.mode = 'login';
|
|
||||||
});
|
|
||||||
shadow.querySelector('#switch-register > a').addEventListener('click', ev => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
this.mode = 'register';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.mode = 'login';
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get mode() {
|
|
||||||
return this.getAttribute('mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
set mode(value) {
|
|
||||||
value = value === 'login' || value === 'register' ? value : 'login';
|
|
||||||
this.setAttribute('mode', value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const FORM_STYLE = `
|
|
||||||
form {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
form > div {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
form > div > input, form > div > textarea {
|
|
||||||
font-size: 16px;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
border-bottom-style: none;
|
|
||||||
border-bottom-width: medium;
|
|
||||||
border-bottom: 1px solid rgba(0,0,0,.1);
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
height: 36px;
|
|
||||||
background: #fff;
|
|
||||||
color: rgba(0,0,0,.8);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
box-shadow: none !important;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(1.5em + 0.75rem + 2px);
|
|
||||||
padding: .375rem .75rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #495057;
|
|
||||||
background-clip: padding-box;
|
|
||||||
transition: border-color .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
|
||||||
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out;
|
|
||||||
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
|
||||||
}
|
|
||||||
form > div > input[type="text"],
|
|
||||||
form > div > input[type="number"],
|
|
||||||
form > div > input[type="email"],
|
|
||||||
form > div > input[type="password"],
|
|
||||||
form > div > textarea {
|
|
||||||
width: calc(100% - 1.5rem - 2px);
|
|
||||||
}
|
|
||||||
form > div > label {
|
|
||||||
color: #000;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
form > div > input[type="button"], form > div > input[type="submit"] {
|
|
||||||
padding: 12px 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
border-width: 1px;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
box-shadow: 0 10px 20px -6px rgba(0,0,0,.12);
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
transition: .3s;
|
|
||||||
|
|
||||||
background: #46b5d1;
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: 400;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
user-select: none;
|
|
||||||
padding: .375rem .75rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
transition: color .15s ease-in-out,
|
|
||||||
background-color .15s ease-in-out,
|
|
||||||
border-color .15s ease-in-out,
|
|
||||||
box-shadow .15s ease-in-out,
|
|
||||||
-webkit-box-shadow .15s ease-in-out;
|
|
||||||
|
|
||||||
width: auto;
|
|
||||||
height: calc(1.5em + 0.75rem + 2px);
|
|
||||||
padding: .375rem .75rem;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
customElements.define('register-form', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return ['step']
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
article > form { display: none; }
|
|
||||||
:host([step="1"]) #step-1 { display: block; }
|
|
||||||
:host([step="2"]) #step-2 { display: block; }
|
|
||||||
:host([step="3"]) #step-3 { display: block; }
|
|
||||||
|
|
||||||
${ FORM_STYLE }
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.actions > input:first-child {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
.actions > input:last-child {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<article>
|
|
||||||
<form id="step-1">
|
|
||||||
<div>
|
|
||||||
<label>Login</label>
|
|
||||||
<input id="login" name="login" placeholder="Login" type="text" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>E-Mail</label>
|
|
||||||
<input name="email" placeholder="Email" type="email" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>Hasło</label>
|
|
||||||
<input name="pass" placeholder="Hasło" type="password" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input type="submit" value="Następny" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<form id="step-2">
|
|
||||||
<div>
|
|
||||||
<input name="name" placeholder="Nazwa usługi" type="text" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>description</label>
|
|
||||||
<textarea name="description" required></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<input type="button" value="Wróć" />
|
|
||||||
<input type="submit" value="Następny" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<form id="step-3">
|
|
||||||
<input id="hidden-login" name="login" type="hidden" />
|
|
||||||
<input id="hidden-email" name="email" type="hidden" />
|
|
||||||
<input id="hidden-pass" name="pass" type="hidden" />
|
|
||||||
<input id="hidden-name" name="name" type="hidden" />
|
|
||||||
|
|
||||||
<div class="actions">
|
|
||||||
<input type="button" value="Wróć" />
|
|
||||||
<input type="submit" value="Dodaj usługi/produkty" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const copyForm = (form) => {
|
|
||||||
for (const el of form.elements) {
|
|
||||||
if (el.name === '') continue;
|
|
||||||
finalForm.querySelector(`[id="hidden-${el.name}"]`).value = el.value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const finalForm = shadow.querySelector('#step-3');
|
|
||||||
{
|
|
||||||
const el = shadow.querySelector('#step-1');
|
|
||||||
el.addEventListener('submit', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
copyForm(el);
|
|
||||||
this.step = 2;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const el = shadow.querySelector('#step-2');
|
|
||||||
el.addEventListener('submit', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
copyForm(el);
|
|
||||||
this.step = 3;
|
|
||||||
});
|
|
||||||
el.querySelector('.actions > input[type="button"]').addEventListener('click', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.step = 1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const el = finalForm;
|
|
||||||
el.addEventListener('submit', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
copyForm(el);
|
|
||||||
let content = [
|
|
||||||
...shadow.querySelector('#step-1').elements,
|
|
||||||
...shadow.querySelector('#step-2').elements,
|
|
||||||
...shadow.querySelector('#step-3').elements,
|
|
||||||
]
|
|
||||||
.filter(el => el && el.name !== '')
|
|
||||||
.reduce((mem, el) => ({ ...mem, [el.name]: el.value }), {});
|
|
||||||
console.info(content);
|
|
||||||
});
|
|
||||||
el.querySelector('.actions > input[type="button"]').addEventListener('click', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.step = 2;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.step = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get step() {
|
|
||||||
const step = parseInt(this.getAttribute('step'));
|
|
||||||
return isNaN(step) ? 1 : step;
|
|
||||||
}
|
|
||||||
|
|
||||||
set step(n) {
|
|
||||||
this.setAttribute('step', n);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
customElements.define('login-form', class extends HTMLElement {
|
|
||||||
static get observedAttributes() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
|
||||||
shadow.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host { display: block; }
|
|
||||||
* { font-family: 'Noto Sans', sans-serif; }
|
|
||||||
${ FORM_STYLE }
|
|
||||||
</style>
|
|
||||||
<form>
|
|
||||||
<div>
|
|
||||||
<label>Login</label>
|
|
||||||
<input name="login" placeholder="Login" type="text" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>Hasło</label>
|
|
||||||
<input name="pass" placeholder="Hasło" type="password" required />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input type="button" value="Zaloguj" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldV, newV) {
|
|
||||||
if (oldV === newV) return;
|
|
||||||
switch (name) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
21
client/.swcrc
Normal file
21
client/.swcrc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/swcrc",
|
||||||
|
"module": {
|
||||||
|
"type": "es6",
|
||||||
|
"strict": false,
|
||||||
|
"strictMode": true,
|
||||||
|
"lazy": false,
|
||||||
|
"noInterop": false
|
||||||
|
},
|
||||||
|
"jsc": {
|
||||||
|
"parser": {
|
||||||
|
"syntax": "ecmascript"
|
||||||
|
},
|
||||||
|
"minify": {
|
||||||
|
"compress": true,
|
||||||
|
"mangle": true
|
||||||
|
},
|
||||||
|
"target": "es2022"
|
||||||
|
},
|
||||||
|
"minify": true
|
||||||
|
}
|
8
client/package.json
Normal file
8
client/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/cli": "^0.1.57",
|
||||||
|
"@swc/core": "^1.2.209",
|
||||||
|
"@swc/helpers": "^0.4.3",
|
||||||
|
"browserslist": "^4.21.1"
|
||||||
|
}
|
||||||
|
}
|
11
client/spack.config.js
Normal file
11
client/spack.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { config } = require("@swc/core/spack");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
module.exports = config({
|
||||||
|
entry: {
|
||||||
|
app: __dirname + "/src/app.js",
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: __dirname + "/dist",
|
||||||
|
},
|
||||||
|
});
|
12
client/src/app.js
Normal file
12
client/src/app.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import "./form-navigation.js";
|
||||||
|
import "./local-service.js";
|
||||||
|
import "./local-service-item.js";
|
||||||
|
import "./local-services.js";
|
||||||
|
import "./login-form.js";
|
||||||
|
import "./ow-account.js";
|
||||||
|
import "./ow-nav.js";
|
||||||
|
import "./ow-path.js";
|
||||||
|
import "./price/price-view";
|
||||||
|
import "./price/price-input";
|
||||||
|
import "./register-form.js";
|
||||||
|
import "./shared.js";
|
65
client/src/form-navigation.js
Normal file
65
client/src/form-navigation.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { S, FORM_STYLE } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('form-navigation', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['next', 'prev']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: "closed" });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${ FORM_STYLE }
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
input.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form class="inline">
|
||||||
|
<div class="actions">
|
||||||
|
<input id="prev" type="button" value="Wróć" />
|
||||||
|
<input id="next" type="submit" value="Następny" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
shadow.querySelector('#prev').addEventListener('click', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
this.dispatchEvent(new CustomEvent('form:prev', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: this.parentElement
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
shadow.querySelector('#next').addEventListener('click', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
this.dispatchEvent(new CustomEvent('form:next', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: this.parentElement
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'next': {
|
||||||
|
this[S].querySelector('#next').className = newV === 'hidden' ? 'hidden' : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'prev': {
|
||||||
|
this[S].querySelector('#prev').className = newV === 'hidden' ? 'hidden' : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
52
client/src/local-service-item.js
Normal file
52
client/src/local-service-item.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('local-service-item', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['name', 'price']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
#item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
#price {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section id="item">
|
||||||
|
<h3 id="name"></h3>
|
||||||
|
<price-view id="price"></price-view>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this[S].querySelector('#name').textContent = this.getAttribute('name');
|
||||||
|
this[S].querySelector('#price').value = this.price();
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'name':
|
||||||
|
return this[S].querySelector('#name').textContent = newV;
|
||||||
|
case 'price':
|
||||||
|
return this[S].querySelector('#price').value = newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
price(s) {
|
||||||
|
const n = parseInt(s || this.getAttribute('price'));
|
||||||
|
return isNaN(n) ? 0 : n;
|
||||||
|
}
|
||||||
|
});
|
42
client/src/local-service.js
Normal file
42
client/src/local-service.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('local-service', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['name', 'service-id', 'state']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
#items {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h2 id="name"></h2>
|
||||||
|
<slot name="description"></slot>
|
||||||
|
<section id="items">
|
||||||
|
<slot name="item"></slot>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this[S].querySelector('#name').textContent = this.getAttribute('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'name':
|
||||||
|
return this[S].querySelector('#name').textContent = newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.getAttribute('name') || ''
|
||||||
|
}
|
||||||
|
});
|
94
client/src/local-services.js
Normal file
94
client/src/local-services.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('local-services', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['filter']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
::slotted(local-service[local-services-visible="invisible"]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
font-size: 20pt;
|
||||||
|
line-height: 2.6em;
|
||||||
|
height: 2.6em;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
border:none;
|
||||||
|
outline:none;
|
||||||
|
display: block;
|
||||||
|
background: transparent;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
text-indent: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section>
|
||||||
|
<input type="text" id="filter" placeholder="Filtruj" />
|
||||||
|
</section>
|
||||||
|
<section id="items">
|
||||||
|
<slot name="services"></slot>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
{
|
||||||
|
const filter = shadow.querySelector('#filter');
|
||||||
|
let t = null;
|
||||||
|
filter.addEventListener('change', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.filter = ev.target.value;
|
||||||
|
});
|
||||||
|
filter.addEventListener('keyup', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const value = ev.target.value;
|
||||||
|
|
||||||
|
if (t) clearTimeout(t);
|
||||||
|
t = setTimeout(() => {
|
||||||
|
this.filter = value;
|
||||||
|
t = null;
|
||||||
|
}, 1000 / 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.filter = this.getAttribute('filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'filter':
|
||||||
|
return this.filter = newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get filter() {
|
||||||
|
return this.getAttribute('filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
set filter(value) {
|
||||||
|
if (!value || value === '') {
|
||||||
|
this.removeAttribute('filter');
|
||||||
|
for (const el of this.querySelectorAll('local-service')) {
|
||||||
|
el.removeAttribute('local-services-visible');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setAttribute('filter', value);
|
||||||
|
for (const el of this.querySelectorAll('local-service')) {
|
||||||
|
if (!el.name) continue;
|
||||||
|
if (el.name.includes(value)) {
|
||||||
|
el.setAttribute('local-services-visible', 'visible');
|
||||||
|
} else {
|
||||||
|
el.setAttribute('local-services-visible', 'invisible');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
41
client/src/login-form.js
Normal file
41
client/src/login-form.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { FORM_STYLE, S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('login-form', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${ FORM_STYLE }
|
||||||
|
</style>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label>Login</label>
|
||||||
|
<input name="login" placeholder="Login" type="text" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Hasło</label>
|
||||||
|
<input name="pass" placeholder="Hasło" type="password" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="button" value="Zaloguj" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
75
client/src/ow-account.js
Normal file
75
client/src/ow-account.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('ow-account', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['mode']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
article > * {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:host([mode="login"]) login-form, :host([mode="login"]) #switch-register {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
:host([mode="register"]) register-form, :host([mode="register"]) #switch-login {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
a{
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: var(--hover-color);
|
||||||
|
border-bottom-color: var(--hover-color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<article>
|
||||||
|
<login-form></login-form>
|
||||||
|
<register-form></register-form>
|
||||||
|
<section id="switch-register">
|
||||||
|
<a>Nie masz konta? Utwórz nowe</a>
|
||||||
|
</section>
|
||||||
|
<section id="switch-login">
|
||||||
|
<a>Masz konta? Zaloguj się</a>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
`;
|
||||||
|
shadow.querySelector('#switch-login > a').addEventListener('click', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
this.mode = 'login';
|
||||||
|
});
|
||||||
|
shadow.querySelector('#switch-register > a').addEventListener('click', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
this.mode = 'register';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.mode = 'login';
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get mode() {
|
||||||
|
return this.getAttribute('mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
set mode(value) {
|
||||||
|
value = value === 'login' || value === 'register' ? value : 'login';
|
||||||
|
this.setAttribute('mode', value);
|
||||||
|
}
|
||||||
|
});
|
40
client/src/ow-nav.js
Normal file
40
client/src/ow-nav.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('ow-nav', class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #2b2727;
|
||||||
|
font-family: Raleway, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
section::after {
|
||||||
|
display: block;
|
||||||
|
content: ' ';
|
||||||
|
border: none;
|
||||||
|
padding: 10px 18px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #2b2727;
|
||||||
|
text-transform: uppercase;
|
||||||
|
align-self: stretch;
|
||||||
|
flex-shrink: 20;
|
||||||
|
flex-grow: 20;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section>
|
||||||
|
<slot></slot>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
71
client/src/ow-path.js
Normal file
71
client/src/ow-path.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { S } from "./shared";
|
||||||
|
|
||||||
|
customElements.define('ow-path', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['selected', 'path'];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 18px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #495057;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid var(--border-slim-color);
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: var(--hover-color);
|
||||||
|
}
|
||||||
|
:host(:not([selected])) a {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<a><slot></slot></a>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.selected = this.getAttribute('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'selected':
|
||||||
|
return this.selected = newV;
|
||||||
|
case 'path':
|
||||||
|
return this.path = newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get selected() {
|
||||||
|
return this.getAttribute('selected') === 'selected';
|
||||||
|
}
|
||||||
|
|
||||||
|
set selected(value) {
|
||||||
|
if (value === 'selected') this.setAttribute('selected', 'selected');
|
||||||
|
else this.removeAttribute('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
get path() {
|
||||||
|
return this.getAttribute('path') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
set path(value) {
|
||||||
|
if (!value || value === '') {
|
||||||
|
this.removeAttribute('path');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setAttribute('path', value);
|
||||||
|
this[S].querySelector('a').setAttribute('href', value);
|
||||||
|
}
|
||||||
|
});
|
98
client/src/price/price-input.js
Normal file
98
client/src/price/price-input.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { S, FORM_STYLE } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('price-input', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['value', 'currency', 'required', 'name']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
#price {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
#view {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#value {
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
${FORM_STYLE}
|
||||||
|
</style>
|
||||||
|
<div id="view">
|
||||||
|
<input id="price" type="number" min="0.00" max="10000.00" step="0.01" />
|
||||||
|
<span id="currency"></span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this[S].querySelector('#currency').textContent = this.currency;
|
||||||
|
// this[S].querySelector('#price').textContent = this.formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
const price = this[S].querySelector('#price');
|
||||||
|
switch (name) {
|
||||||
|
case 'price': {
|
||||||
|
this.value = newV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'currency': {
|
||||||
|
this.currency = newV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'required': {
|
||||||
|
newV
|
||||||
|
? price.setAttribute('required', 'required')
|
||||||
|
: price.removeAttribute('required');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'readonly': {
|
||||||
|
newV
|
||||||
|
? price.setAttribute('readonly', 'readonly')
|
||||||
|
: price.removeAttribute('readonly');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'name': {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this[S].querySelector('#price').value * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(v) {
|
||||||
|
this.setAttribute('value', v);
|
||||||
|
this[S].querySelector('#price').value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
get currency() {
|
||||||
|
return this.getAttribute('currency') || 'PLN';
|
||||||
|
}
|
||||||
|
|
||||||
|
set currency(value) {
|
||||||
|
this.setAttribute('currency', value);
|
||||||
|
this[S].querySelector('#currency').textContent = this.currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportValidity() {
|
||||||
|
return this[S].querySelector('input').reportValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.getAttribute('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(value) {
|
||||||
|
this.setAttribute('name', value);
|
||||||
|
}
|
||||||
|
});
|
58
client/src/price/price-view.js
Normal file
58
client/src/price/price-view.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { S } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('price-view', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['value', 'currency']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
#price {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<span id="price"></span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this[S].querySelector('#price').textContent = this.formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'price': {
|
||||||
|
this.value = newV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get formatted() {
|
||||||
|
let v = this.value;
|
||||||
|
let major = Math.ceil(v / 100);
|
||||||
|
let minor = v % 100;
|
||||||
|
let formatted = `${ major },${ minor < 10 ? `0${ minor }` : minor }`;
|
||||||
|
return `${ formatted }${ this.currency }`
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
const n = parseInt(this.getAttribute('value'));
|
||||||
|
return isNaN(n) ? 0 : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(v) {
|
||||||
|
this.setAttribute('value', v);
|
||||||
|
this[S].querySelector('#price').textContent = this.formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
get currency() {
|
||||||
|
return this.getAttribute('currency') || 'PLN';
|
||||||
|
}
|
||||||
|
});
|
136
client/src/register-form.js
Normal file
136
client/src/register-form.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { S, FORM_STYLE } from "./shared";
|
||||||
|
|
||||||
|
import "./register-form/register-basic-form";
|
||||||
|
import "./register-form/register-item-form-row.js";
|
||||||
|
import "./register-form/register-items-form.js";
|
||||||
|
import "./register-form/register-company-form";
|
||||||
|
import "./register-form/register-submit-form";
|
||||||
|
import "./register-form/register-user-type";
|
||||||
|
import "./register-form/register-oauth2";
|
||||||
|
|
||||||
|
const copyForm = (form, finalForm) => {
|
||||||
|
form.reportValidity();
|
||||||
|
|
||||||
|
for (const el of form.elements) {
|
||||||
|
if (el.name === '') continue;
|
||||||
|
if (!el.reportValidity()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const inputs = form.inputs;
|
||||||
|
if (inputs)
|
||||||
|
finalForm.setItems(inputs);
|
||||||
|
else
|
||||||
|
for (const el of form.elements) {
|
||||||
|
if (el.name === '') continue;
|
||||||
|
finalForm.updateField(el.name, el.value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
customElements.define('register-form', class extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['step']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
[id^="step-"] { display: none; }
|
||||||
|
:host([step="0"]) #step-0 { display: block; }
|
||||||
|
:host([step="1"]) #step-1 { display: block; }
|
||||||
|
:host([step="2"]) #step-2 { display: block; }
|
||||||
|
:host([step="3"]) #step-3 { display: block; }
|
||||||
|
:host([step="4"]) #step-4 { display: block; }
|
||||||
|
:host([step="1000"]) #step-1000 { display: block; }
|
||||||
|
|
||||||
|
${ FORM_STYLE }
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.actions > input:first-child {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.actions > input:last-child {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
#step-4 > #copied {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<article>
|
||||||
|
<register-user-type id="step-0">
|
||||||
|
</register-user-type>
|
||||||
|
|
||||||
|
<register-basic-form id="step-1">
|
||||||
|
</register-basic-form>
|
||||||
|
|
||||||
|
<register-company-form id="step-2">
|
||||||
|
</register-company-form>
|
||||||
|
|
||||||
|
<register-items-form id="step-3">
|
||||||
|
</register-items-form>
|
||||||
|
|
||||||
|
<register-submit-form id="step-4">
|
||||||
|
</register-submit-form>
|
||||||
|
|
||||||
|
<register-oauth2 id="step-1000">
|
||||||
|
</register-oauth2>
|
||||||
|
</article>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const finalForm = shadow.querySelector('#step-4');
|
||||||
|
this[S].addEventListener('account:type:user', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.step = 1000;
|
||||||
|
});
|
||||||
|
this[S].addEventListener('account:type:local-service', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.step = 1;
|
||||||
|
});
|
||||||
|
this[S].addEventListener('form:next', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const form = shadow.querySelector(`#step-${ this.step }`);
|
||||||
|
if (copyForm(form, finalForm)) {
|
||||||
|
this.step = this.step + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this[S].addEventListener('form:prev', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.step = this.step - 1;
|
||||||
|
});
|
||||||
|
{
|
||||||
|
const el = finalForm;
|
||||||
|
el.addEventListener('submit', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.step = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get step() {
|
||||||
|
const step = parseInt(this.getAttribute('step'));
|
||||||
|
return isNaN(step) ? 1 : step;
|
||||||
|
}
|
||||||
|
|
||||||
|
set step(n) {
|
||||||
|
if (n < 0) return;
|
||||||
|
this.setAttribute('step', n);
|
||||||
|
}
|
||||||
|
});
|
40
client/src/register-form/register-basic-form.js
Normal file
40
client/src/register-form/register-basic-form.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { FORM_STYLE, S, PseudoForm } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('register-basic-form', class extends PseudoForm {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: "closed" });
|
||||||
|
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
${ FORM_STYLE }
|
||||||
|
</style>
|
||||||
|
<form id="step-1">
|
||||||
|
<div>
|
||||||
|
<label>Login</label>
|
||||||
|
<input id="login" name="login" placeholder="Login" type="text" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>E-Mail</label>
|
||||||
|
<input name="email" placeholder="Email" type="email" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Hasło</label>
|
||||||
|
<input name="pass" placeholder="Hasło" type="password" required />
|
||||||
|
</div>
|
||||||
|
<form-navigation prev="hidden"></form-navigation>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const form = shadow.querySelector('form');
|
||||||
|
form.addEventListener('submit', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.dispatchEvent(new CustomEvent('form:next', { bubbles: true, composed: true, detail: form }));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
27
client/src/register-form/register-company-form.js
Normal file
27
client/src/register-form/register-company-form.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { FORM_STYLE, S, PseudoForm } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('register-company-form', class extends PseudoForm {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this[S] = this.attachShadow({mode: "closed"});
|
||||||
|
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${FORM_STYLE}
|
||||||
|
</style>
|
||||||
|
<form id="step-2">
|
||||||
|
<div>
|
||||||
|
<input name="name" placeholder="Nazwa usługi" type="text" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>description</label>
|
||||||
|
<textarea name="description" required></textarea>
|
||||||
|
</div>
|
||||||
|
<form-navigation></form-navigation>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
})
|
95
client/src/register-form/register-item-form-row.js
Normal file
95
client/src/register-form/register-item-form-row.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { S, FORM_STYLE, PseudoForm } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('register-item-form-row', class extends PseudoForm {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['idx', 'name']
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
|
||||||
|
this.addEventListener('item:removed', () => {
|
||||||
|
this.setAttribute('removed', 'removed');
|
||||||
|
const parent = this.parentElement;
|
||||||
|
this.remove();
|
||||||
|
parent.dispatchEvent(new CustomEvent('item:removed', { bubbles: true, composed: true }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
const idx = this.getAttribute('idx');
|
||||||
|
this[S].innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${ FORM_STYLE }
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form class="inline">
|
||||||
|
<div id="name" class="field">
|
||||||
|
<label>Nazwa</label>
|
||||||
|
<input class="item-name" name="items[${ idx }][name]" type="text" required>
|
||||||
|
</div>
|
||||||
|
<div id="price" class="field">
|
||||||
|
<label>Cena</label>
|
||||||
|
<price-input class="item-price" name="items[${ idx }][price]" required>
|
||||||
|
</price-input>
|
||||||
|
</div>
|
||||||
|
<div><input class="remove" type="button" value="Usuń"></div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
this[S].querySelector('form').addEventListener('submit', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.reportValidity();
|
||||||
|
});
|
||||||
|
this[S].querySelector('.remove').addEventListener('click', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
this.dispatchEvent(new CustomEvent('item:removed', { bubbles: true, composed: false }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldV, newV) {
|
||||||
|
if (oldV === newV) return;
|
||||||
|
switch (name) {
|
||||||
|
case 'idx': {
|
||||||
|
this.updateNames();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get inputs() {
|
||||||
|
return [
|
||||||
|
this[S].querySelector('input.item-name').cloneNode(true),
|
||||||
|
this[S].querySelector('input.item-price').cloneNode(true),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNames() {
|
||||||
|
const idx = this.getAttribute('idx');
|
||||||
|
for (const el of this[S].querySelectorAll('.field')) {
|
||||||
|
const id = el.id;
|
||||||
|
el.querySelector('input, price-input').setAttribute('name', `items[${ idx }][${ id }]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get idx() {
|
||||||
|
return this.getAttribute('idx');
|
||||||
|
}
|
||||||
|
|
||||||
|
set idx(idx) {
|
||||||
|
this.setAttribute('idx', idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
reportValidity() {
|
||||||
|
return super.reportValidity() && this[S].querySelector('price-input').reportValidity();
|
||||||
|
}
|
||||||
|
});
|
64
client/src/register-form/register-items-form.js
Normal file
64
client/src/register-form/register-items-form.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { FORM_STYLE, S, PseudoForm } from "../shared";
|
||||||
|
|
||||||
|
import "./register-item-form-row"
|
||||||
|
|
||||||
|
const updateItems = (form) => {
|
||||||
|
let idx = 0;
|
||||||
|
for (const el of form.querySelectorAll('register-item-form-row')) {
|
||||||
|
el.idx = idx++;
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('register-items-form', class extends PseudoForm {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: 'closed' });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${ FORM_STYLE }
|
||||||
|
|
||||||
|
::slotted(section) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form>
|
||||||
|
<article id="items">
|
||||||
|
<slot></slot>
|
||||||
|
</article>
|
||||||
|
<div>
|
||||||
|
<input type="button" id="add-item" value="Dodaj usługę/produkt" />
|
||||||
|
</div>
|
||||||
|
<form-navigation></form-navigation>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
this.addEventListener('item:removed', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
updateItems(this)
|
||||||
|
});
|
||||||
|
this.addEventListener('form:next', ev => {
|
||||||
|
for (const el of this.querySelectorAll('item-form-row')) {
|
||||||
|
if (!el.reportValidity()) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
shadow.querySelector('#add-item').addEventListener('click', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
this.appendChild(document.createElement('register-item-form-row'));
|
||||||
|
updateItems(this)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputs() {
|
||||||
|
return [...this.querySelectorAll("register-item-form-row")].map(form => form.inputs)
|
||||||
|
}
|
||||||
|
});
|
12
client/src/register-form/register-oauth2.js
Normal file
12
client/src/register-form/register-oauth2.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
customElements.define('register-oauth2', class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this.attachShadow({ mode: "closed" });
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<a id="google-button" class="btn btn-block btn-social btn-google">
|
||||||
|
<i class="fa fa-google"></i> Sign in with Google
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
75
client/src/register-form/register-submit-form.js
Normal file
75
client/src/register-form/register-submit-form.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { FORM_STYLE, S, PseudoForm } from "../shared";
|
||||||
|
|
||||||
|
customElements.define('register-submit-form', class extends PseudoForm {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this[S] = this.attachShadow({ mode: "closed" });
|
||||||
|
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host { display: block; }
|
||||||
|
* { font-family: 'Noto Sans', sans-serif; }
|
||||||
|
${ FORM_STYLE }
|
||||||
|
</style>
|
||||||
|
<form id="step-4">
|
||||||
|
<div id="copied">
|
||||||
|
<input id="hidden-login" name="login" type="hidden" />
|
||||||
|
<input id="hidden-email" name="email" type="hidden" />
|
||||||
|
<input id="hidden-pass" name="pass" type="hidden" />
|
||||||
|
<input id="hidden-name" name="name" type="hidden" />
|
||||||
|
<input id="hidden-description" name="description" type="hidden" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Login</label>
|
||||||
|
<input readonly id="preview-login">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Email</label>
|
||||||
|
<input readonly id="preview-email">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Password</label>
|
||||||
|
<input readonly id="preview-pass" type="password">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Name</label>
|
||||||
|
<input readonly id="preview-name">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Description</label>
|
||||||
|
<input readonly id="preview-description">
|
||||||
|
</div>
|
||||||
|
<div id="items">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<form-navigation next="hidden"></form-navigation>
|
||||||
|
<input type="submit" value="Dodaj usługi/produkty" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateField(name, value) {
|
||||||
|
this[S].querySelector(`[id="hidden-${ name }"]`).value = value;
|
||||||
|
this[S].querySelector(`[id="preview-${ name }"]`).value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
setItems(items) {
|
||||||
|
const host = this[S].querySelector('#items');
|
||||||
|
host.innerHTML = ``;
|
||||||
|
for (const row of items) {
|
||||||
|
const el = host.appendChild(document.createElement('div'));
|
||||||
|
const [name, price] = row;
|
||||||
|
|
||||||
|
name.setAttribute('readonly', 'readonly');
|
||||||
|
el.appendChild(name);
|
||||||
|
|
||||||
|
el.appendChild(document.createElement('price-view')).value = price.value;
|
||||||
|
price.setAttribute('readonly', 'readonly');
|
||||||
|
price.setAttribute('type', 'hidden');
|
||||||
|
el.appendChild(price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
69
client/src/register-form/register-user-type.js
Normal file
69
client/src/register-form/register-user-type.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
customElements.define('register-user-type', class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this.attachShadow({ mode: "closed" });
|
||||||
|
|
||||||
|
shadow.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
ul, li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
border: 1px solid var(--border-slim-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--border-slim-color);
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
svg, path {
|
||||||
|
fill: var(--border-slim-color) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<article>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a id="user">
|
||||||
|
<svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.5.875a3.625 3.625 0 0 0-1.006 7.109c-1.194.145-2.218.567-2.99 1.328-.982.967-1.479 2.408-1.479 4.288a.475.475 0 1 0 .95 0c0-1.72.453-2.88 1.196-3.612.744-.733 1.856-1.113 3.329-1.113s2.585.38 3.33 1.113c.742.733 1.195 1.892 1.195 3.612a.475.475 0 1 0 .95 0c0-1.88-.497-3.32-1.48-4.288-.77-.76-1.795-1.183-2.989-1.328A3.627 3.627 0 0 0 7.5.875ZM4.825 4.5a2.675 2.675 0 1 1 5.35 0 2.675 2.675 0 0 1-5.35 0Z" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
<div>Użytkownik</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a id="local-service">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 489.4 489.4" style="enable-background:new 0 0 489.4 489.4" xml:space="preserve"><path d="M347.7 263.75h-66.5c-18.2 0-33 14.8-33 33v51c0 18.2 14.8 33 33 33h66.5c18.2 0 33-14.8 33-33v-51c0-18.2-14.8-33-33-33zm9 84c0 5-4.1 9-9 9h-66.5c-5 0-9-4.1-9-9v-51c0-5 4.1-9 9-9h66.5c5 0 9 4.1 9 9v51z"/><path d="M489.4 171.05c0-2.1-.5-4.1-1.6-5.9l-72.8-128c-2.1-3.7-6.1-6.1-10.4-6.1H84.7c-4.3 0-8.3 2.3-10.4 6.1l-72.7 128c-1 1.8-1.6 3.8-1.6 5.9 0 28.7 17.3 53.3 42 64.2v211.1c0 6.6 5.4 12 12 12h381.3c6.6 0 12-5.4 12-12v-209.6c0-.5 0-.9-.1-1.3 24.8-10.9 42.2-35.6 42.2-64.4zM91.7 55.15h305.9l56.9 100.1H34.9l56.8-100.1zm256.6 124c-3.8 21.6-22.7 38-45.4 38s-41.6-16.4-45.4-38h90.8zm-116.3 0c-3.8 21.6-22.7 38-45.4 38s-41.6-16.4-45.5-38H232zm-207.2 0h90.9c-3.8 21.6-22.8 38-45.5 38-22.7.1-41.6-16.4-45.4-38zm176.8 255.2h-69v-129.5c0-9.4 7.6-17.1 17.1-17.1h34.9c9.4 0 17.1 7.6 17.1 17.1v129.5h-.1zm221.7 0H225.6v-129.5c0-22.6-18.4-41.1-41.1-41.1h-34.9c-22.6 0-41.1 18.4-41.1 41.1v129.6H66v-193.3c1.4.1 2.8.1 4.2.1 24.2 0 45.6-12.3 58.2-31 12.6 18.7 34 31 58.2 31s45.5-12.3 58.2-31c12.6 18.7 34 31 58.1 31 24.2 0 45.5-12.3 58.1-31 12.6 18.7 34 31 58.2 31 1.4 0 2.7-.1 4.1-.1v193.2zm-4.1-217.1c-22.7 0-41.6-16.4-45.4-38h90.9c-3.9 21.5-22.8 38-45.5 38z"/></svg>
|
||||||
|
<div>Usługodawca</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const user = shadow.querySelector('#user');
|
||||||
|
user.addEventListener('click', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.dispatchEvent(new CustomEvent('account:type:user', { bubbles: true, composed: true }));
|
||||||
|
});
|
||||||
|
const service = shadow.querySelector('#local-service');
|
||||||
|
service.addEventListener('click', ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.dispatchEvent(new CustomEvent('account:type:local-service', { bubbles: true, composed: true }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
107
client/src/shared.js
Normal file
107
client/src/shared.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
export const S = Symbol();
|
||||||
|
|
||||||
|
export const FORM_STYLE = `
|
||||||
|
form {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
form.inline {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
form > div {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
input, textarea {
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-bottom-style: none;
|
||||||
|
border-bottom-width: medium;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
height: 36px;
|
||||||
|
background: #fff;
|
||||||
|
color: rgba(0,0,0,.8);
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
box-shadow: none !important;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(1.5em + 0.75rem + 2px);
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #495057;
|
||||||
|
background-clip: padding-box;
|
||||||
|
transition: border-color .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
||||||
|
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out;
|
||||||
|
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
||||||
|
}
|
||||||
|
input[type="text"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="password"],
|
||||||
|
textarea {
|
||||||
|
width: calc(100% - 1.5rem - 2px);
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
color: #000;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
input[type="button"], input[type="submit"] {
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
box-shadow: 0 10px 20px -6px rgba(0,0,0,.12);
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
transition: .3s;
|
||||||
|
|
||||||
|
background: #46b5d1;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
user-select: none;
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
transition: color .15s ease-in-out,
|
||||||
|
background-color .15s ease-in-out,
|
||||||
|
border-color .15s ease-in-out,
|
||||||
|
box-shadow .15s ease-in-out,
|
||||||
|
width: auto;
|
||||||
|
height: calc(1.5em + 0.75rem + 2px);
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export class PseudoForm extends HTMLElement {
|
||||||
|
reportValidity() {
|
||||||
|
return this[S].querySelector('form').reportValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkValidity() {
|
||||||
|
return this[S].querySelector('form').checkValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
get elements() {
|
||||||
|
return this[S].querySelector('form').elements;
|
||||||
|
}
|
||||||
|
}
|
286
client/yarn.lock
Normal file
286
client/yarn.lock
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
|
version "2.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||||
|
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
|
||||||
|
dependencies:
|
||||||
|
"@nodelib/fs.stat" "2.0.5"
|
||||||
|
run-parallel "^1.1.9"
|
||||||
|
|
||||||
|
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
|
||||||
|
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||||
|
|
||||||
|
"@nodelib/fs.walk@^1.2.3":
|
||||||
|
version "1.2.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
|
||||||
|
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
|
||||||
|
dependencies:
|
||||||
|
"@nodelib/fs.scandir" "2.1.5"
|
||||||
|
fastq "^1.6.0"
|
||||||
|
|
||||||
|
"@swc/cli@^0.1.57":
|
||||||
|
version "0.1.57"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/cli/-/cli-0.1.57.tgz#a9c424de5a217ec20a4b7c2c0e5c343980537e83"
|
||||||
|
integrity sha512-HxM8TqYHhAg+zp7+RdTU69bnkl4MWdt1ygyp6BDIPjTiaJVH6Dizn2ezbgDS8mnFZI1FyhKvxU/bbaUs8XhzQg==
|
||||||
|
dependencies:
|
||||||
|
commander "^7.1.0"
|
||||||
|
fast-glob "^3.2.5"
|
||||||
|
slash "3.0.0"
|
||||||
|
source-map "^0.7.3"
|
||||||
|
|
||||||
|
"@swc/core-android-arm-eabi@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.209.tgz#cc3b5a06f73ad79367b417e174e3704aa285d5ec"
|
||||||
|
integrity sha512-87+4ffqg3f2iTYqdfiQcRvC56wZ62X8OHN7Yh8LwGqPBpt7or0Sj1ryzufrZlwdKwiM2pU86FfCS7UM8EfE5Rw==
|
||||||
|
|
||||||
|
"@swc/core-android-arm64@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.209.tgz#b01653e2183817390b353fedcc2d7750e47548d9"
|
||||||
|
integrity sha512-PfWiBrY4guq6zpTREeaqsjSrbZKFB+B4ZvFGbHlyZDwckNJf+9mBEVoJc5xsUs/INIH/Zz0g2GMdR/Lxp4IDig==
|
||||||
|
|
||||||
|
"@swc/core-darwin-arm64@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.209.tgz#37cb3469d1140fa9c40ebbbc76d13931acd7cb69"
|
||||||
|
integrity sha512-RT4bOKKEAfUXFY2thNe5y/htQl5Pg9zoZF+QRQrehBeB2L66dT5k1cG51ipKbOYtdICp7nLLeF2KW3CCxdlPbQ==
|
||||||
|
|
||||||
|
"@swc/core-darwin-x64@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.209.tgz#d473f11e912f867a79c586d399e4678cd1a53641"
|
||||||
|
integrity sha512-SC312em15Dy5Na/8xgOGxXFcdpxBcSMwORc2sdrkiiWKTJ+fWJAmDnG82TWRfi3V/Q6oXBdTEKWuJudHrlcYSA==
|
||||||
|
|
||||||
|
"@swc/core-freebsd-x64@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.209.tgz#d54d504dd8e3f5a8e4446ee9c4ba01e97af80c77"
|
||||||
|
integrity sha512-ta88pSLq0MpqznnwnCa0201kHUBHzAHrSpeAqlBLIR0Tste18myGXp58dGAN3U0n0hPDWPIj+Y26/qCqNZAnpA==
|
||||||
|
|
||||||
|
"@swc/core-linux-arm-gnueabihf@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.209.tgz#3a91d441351deba6169b07ba31d445248f516c75"
|
||||||
|
integrity sha512-E7rvzd5OK5idheZrbqdgWHyJ2anrgTYVcfRPvt95pk+Eu/RqMcn9qpLbkI1Olttih/7omzrLfGo00Hju+WmzEg==
|
||||||
|
|
||||||
|
"@swc/core-linux-arm64-gnu@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.209.tgz#d07a4a7dbfa4cefda9914994d8d3ac634b5cfca6"
|
||||||
|
integrity sha512-Ejb9eTiFJgACp+JT/Q/bqZptX61GSAPlA6ilOeezp7zgdHzcD3iRZh/AttirA4DQgTr10i3gGBKNxvIwTyxj1g==
|
||||||
|
|
||||||
|
"@swc/core-linux-arm64-musl@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.209.tgz#d1cf0a24642e8c90ff875149ce64c4d6237d806f"
|
||||||
|
integrity sha512-k9L70GpjVljAZLiClSE5R70pfFXDKcDXhn1Rj2miQC/luQjzmWQQLyjACAZmvE//GrWRAV8v+xTTZVhZT1PIbQ==
|
||||||
|
|
||||||
|
"@swc/core-linux-x64-gnu@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.209.tgz#62788183ba176af45bb48bfa4410194ac71eb481"
|
||||||
|
integrity sha512-Fkh5NS/SRbqVsM7URhMHJ3r0piI+iU7BNSLMvQZN8jzWEdxBb26j+DZuEX/4eKBwQ5P6ycCpYYbMBrxfmHfxlA==
|
||||||
|
|
||||||
|
"@swc/core-linux-x64-musl@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.209.tgz#ed1d64e335e1160ca6d23c279593f6848f680fab"
|
||||||
|
integrity sha512-9YaOGD5ODMfkMxCF9iRxlAcENUhzGSZ752r6oedymPWU/FnjIiw2AGdNKL+jCgplh+/5Q/P1NthSciBlChzzgQ==
|
||||||
|
|
||||||
|
"@swc/core-win32-arm64-msvc@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.209.tgz#369e861fd22f089c944bb3a4fcaf1fceb9c45978"
|
||||||
|
integrity sha512-TMljLtDO7DlLGZI2DIw6cAdvedADFKB/d7NK/1pZYYGD8QgjO4NvsLg2fG1TqRf2UwPazWn1B8EQ0B+1NtRIHg==
|
||||||
|
|
||||||
|
"@swc/core-win32-ia32-msvc@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.209.tgz#2712745fa873d1bfa543614c58c750247a22b751"
|
||||||
|
integrity sha512-n/zAh+2YkSMVMLaDpVnsrm8SEcpKLhRSI2/MKDBwOxW9RwB8KqsjidKRijW1hOX89PyNwnVAeEljc0RIDJHTCw==
|
||||||
|
|
||||||
|
"@swc/core-win32-x64-msvc@1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.209.tgz#3561f7a242e06c6119c5c4ec6fa73861c274e6e2"
|
||||||
|
integrity sha512-0tN/pOHfKpTTgkn0eTfQj0MQfIplZ37/iuXHTsrQEULRcqHxxi+2POnbsLfKChrHOcSzrqFWl8I9szHEnYcyow==
|
||||||
|
|
||||||
|
"@swc/core@^1.2.209":
|
||||||
|
version "1.2.209"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.209.tgz#6bb2f93cc39159b07d53dfcfdb1c297d21fb8c99"
|
||||||
|
integrity sha512-UHRTGPAnr0tT7tP/5v7H8dO+Dy9ELymbVm2sqetDK3UXAODs/PsWSiDH6EC5W1yPj6DmzGhfDM+APxsu17VqrQ==
|
||||||
|
optionalDependencies:
|
||||||
|
"@swc/core-android-arm-eabi" "1.2.209"
|
||||||
|
"@swc/core-android-arm64" "1.2.209"
|
||||||
|
"@swc/core-darwin-arm64" "1.2.209"
|
||||||
|
"@swc/core-darwin-x64" "1.2.209"
|
||||||
|
"@swc/core-freebsd-x64" "1.2.209"
|
||||||
|
"@swc/core-linux-arm-gnueabihf" "1.2.209"
|
||||||
|
"@swc/core-linux-arm64-gnu" "1.2.209"
|
||||||
|
"@swc/core-linux-arm64-musl" "1.2.209"
|
||||||
|
"@swc/core-linux-x64-gnu" "1.2.209"
|
||||||
|
"@swc/core-linux-x64-musl" "1.2.209"
|
||||||
|
"@swc/core-win32-arm64-msvc" "1.2.209"
|
||||||
|
"@swc/core-win32-ia32-msvc" "1.2.209"
|
||||||
|
"@swc/core-win32-x64-msvc" "1.2.209"
|
||||||
|
|
||||||
|
"@swc/helpers@^0.4.3":
|
||||||
|
version "0.4.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.3.tgz#16593dfc248c53b699d4b5026040f88ddb497012"
|
||||||
|
integrity sha512-6JrF+fdUK2zbGpJIlN7G3v966PQjyx/dPt1T9km2wj+EUBqgrxCk3uX4Kct16MIm9gGxfKRcfax2hVf5jvlTzA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
braces@^3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||||
|
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||||
|
dependencies:
|
||||||
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
|
browserslist@^4.21.1:
|
||||||
|
version "4.21.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.1.tgz#c9b9b0a54c7607e8dc3e01a0d311727188011a00"
|
||||||
|
integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==
|
||||||
|
dependencies:
|
||||||
|
caniuse-lite "^1.0.30001359"
|
||||||
|
electron-to-chromium "^1.4.172"
|
||||||
|
node-releases "^2.0.5"
|
||||||
|
update-browserslist-db "^1.0.4"
|
||||||
|
|
||||||
|
caniuse-lite@^1.0.30001359:
|
||||||
|
version "1.0.30001363"
|
||||||
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001363.tgz#26bec2d606924ba318235944e1193304ea7c4f15"
|
||||||
|
integrity sha512-HpQhpzTGGPVMnCjIomjt+jvyUu8vNFo3TaDiZ/RcoTrlOq/5+tC8zHdsbgFB6MxmaY+jCpsH09aD80Bb4Ow3Sg==
|
||||||
|
|
||||||
|
commander@^7.1.0:
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
|
||||||
|
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
|
||||||
|
|
||||||
|
electron-to-chromium@^1.4.172:
|
||||||
|
version "1.4.178"
|
||||||
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.178.tgz#3dae6fda486007bb54bbfed420ebd40881a3de45"
|
||||||
|
integrity sha512-aWuhJXkwIdoQzGR8p2QvR3N0OzdUKZSP8+P/hzuMzNQIPZoEa8HiCGM75bQBHjyz+eKT5PB9dVCzkK/tyQ4B5Q==
|
||||||
|
|
||||||
|
escalade@^3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||||
|
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||||
|
|
||||||
|
fast-glob@^3.2.5:
|
||||||
|
version "3.2.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
|
||||||
|
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
|
||||||
|
dependencies:
|
||||||
|
"@nodelib/fs.stat" "^2.0.2"
|
||||||
|
"@nodelib/fs.walk" "^1.2.3"
|
||||||
|
glob-parent "^5.1.2"
|
||||||
|
merge2 "^1.3.0"
|
||||||
|
micromatch "^4.0.4"
|
||||||
|
|
||||||
|
fastq@^1.6.0:
|
||||||
|
version "1.13.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
||||||
|
integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
|
||||||
|
dependencies:
|
||||||
|
reusify "^1.0.4"
|
||||||
|
|
||||||
|
fill-range@^7.0.1:
|
||||||
|
version "7.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||||
|
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||||
|
dependencies:
|
||||||
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
|
glob-parent@^5.1.2:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||||
|
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||||
|
dependencies:
|
||||||
|
is-glob "^4.0.1"
|
||||||
|
|
||||||
|
is-extglob@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||||
|
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||||
|
|
||||||
|
is-glob@^4.0.1:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||||
|
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||||
|
dependencies:
|
||||||
|
is-extglob "^2.1.1"
|
||||||
|
|
||||||
|
is-number@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||||
|
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||||
|
|
||||||
|
merge2@^1.3.0:
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||||
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
|
micromatch@^4.0.4:
|
||||||
|
version "4.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||||
|
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
||||||
|
dependencies:
|
||||||
|
braces "^3.0.2"
|
||||||
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
|
node-releases@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
|
||||||
|
integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
|
||||||
|
|
||||||
|
picocolors@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
|
||||||
|
picomatch@^2.3.1:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||||
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
|
queue-microtask@^1.2.2:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
|
reusify@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
|
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||||
|
|
||||||
|
run-parallel@^1.1.9:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||||
|
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
|
||||||
|
dependencies:
|
||||||
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
|
slash@3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
|
source-map@^0.7.3:
|
||||||
|
version "0.7.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
|
||||||
|
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
||||||
|
|
||||||
|
to-regex-range@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||||
|
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||||
|
dependencies:
|
||||||
|
is-number "^7.0.0"
|
||||||
|
|
||||||
|
tslib@^2.4.0:
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||||
|
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||||
|
|
||||||
|
update-browserslist-db@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz#dbfc5a789caa26b1db8990796c2c8ebbce304824"
|
||||||
|
integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==
|
||||||
|
dependencies:
|
||||||
|
escalade "^3.1.1"
|
||||||
|
picocolors "^1.0.0"
|
@ -80,7 +80,7 @@ pub fn configure(config: &mut ServiceConfig) {
|
|||||||
.service(Files::new("/assets/images", "./assets/images"))
|
.service(Files::new("/assets/images", "./assets/images"))
|
||||||
.service(Files::new("/assets/css", "./assets/css"))
|
.service(Files::new("/assets/css", "./assets/css"))
|
||||||
.service(
|
.service(
|
||||||
Files::new("/assets/js", "./assets/js")
|
Files::new("/assets/js", "./client/dist")
|
||||||
.use_etag(true)
|
.use_etag(true)
|
||||||
.prefer_utf8(true)
|
.prefer_utf8(true)
|
||||||
.show_files_listing(),
|
.show_files_listing(),
|
||||||
|
Loading…
Reference in New Issue
Block a user