From 4a21ba9a18ac6ef59ff1178ec2f4da165029e5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Tue, 5 Jul 2022 16:02:27 +0200 Subject: [PATCH] Add items, choose user type --- .gitignore | 1 + assets/css/app.css | 1 + assets/js/app.js | 705 ------------------ client/.swcrc | 21 + client/package.json | 8 + client/spack.config.js | 11 + client/src/app.js | 12 + client/src/form-navigation.js | 65 ++ client/src/local-service-item.js | 52 ++ client/src/local-service.js | 42 ++ client/src/local-services.js | 94 +++ client/src/login-form.js | 41 + client/src/ow-account.js | 75 ++ client/src/ow-nav.js | 40 + client/src/ow-path.js | 71 ++ client/src/price/price-input.js | 98 +++ client/src/price/price-view.js | 58 ++ client/src/register-form.js | 136 ++++ .../src/register-form/register-basic-form.js | 40 + .../register-form/register-company-form.js | 27 + .../register-form/register-item-form-row.js | 95 +++ .../src/register-form/register-items-form.js | 64 ++ client/src/register-form/register-oauth2.js | 12 + .../src/register-form/register-submit-form.js | 75 ++ .../src/register-form/register-user-type.js | 69 ++ client/src/shared.js | 107 +++ client/yarn.lock | 286 +++++++ src/routes/unrestricted.rs | 2 +- 28 files changed, 1602 insertions(+), 706 deletions(-) delete mode 100644 assets/js/app.js create mode 100644 client/.swcrc create mode 100644 client/package.json create mode 100644 client/spack.config.js create mode 100644 client/src/app.js create mode 100644 client/src/form-navigation.js create mode 100644 client/src/local-service-item.js create mode 100644 client/src/local-service.js create mode 100644 client/src/local-services.js create mode 100644 client/src/login-form.js create mode 100644 client/src/ow-account.js create mode 100644 client/src/ow-nav.js create mode 100644 client/src/ow-path.js create mode 100644 client/src/price/price-input.js create mode 100644 client/src/price/price-view.js create mode 100644 client/src/register-form.js create mode 100644 client/src/register-form/register-basic-form.js create mode 100644 client/src/register-form/register-company-form.js create mode 100644 client/src/register-form/register-item-form-row.js create mode 100644 client/src/register-form/register-items-form.js create mode 100644 client/src/register-form/register-oauth2.js create mode 100644 client/src/register-form/register-submit-form.js create mode 100644 client/src/register-form/register-user-type.js create mode 100644 client/src/shared.js create mode 100644 client/yarn.lock diff --git a/.gitignore b/.gitignore index ea8c4bf..7daeddd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +node_modules diff --git a/assets/css/app.css b/assets/css/app.css index f9b501e..e403b27 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -24,6 +24,7 @@ * { --hover-color: #f18902; --border-slim-color: #495057; + --border-light-gray-color: #e5e5e5; } main { diff --git a/assets/js/app.js b/assets/js/app.js deleted file mode 100644 index dcabbe3..0000000 --- a/assets/js/app.js +++ /dev/null @@ -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 = ` - -
- -
- `; - } -}); - -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 = ` - - - `; - } - - 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 = ` - -
- -
-
- -
- `; - { - 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 = ` - -

- -
- -
- `; - } - - 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 = ` - -
-

- -
- `; - } - - 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 = ` - - - `; - } - - 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 = ` - -
- - -
- Nie masz konta? Utwórz nowe -
-
- Masz konta? Zaloguj się -
-
- `; - 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 = ` - -
-
-
- - -
-
- - -
-
- - -
-
- -
-
-
-
- -
-
- - -
-
- - -
-
-
- - - - - -
- - -
-
-
- `; - - 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 = ` - -
-
- - -
-
- - -
-
- -
-
- `; - } - - connectedCallback() { - } - - attributeChangedCallback(name, oldV, newV) { - if (oldV === newV) return; - switch (name) { - } - } -}); diff --git a/client/.swcrc b/client/.swcrc new file mode 100644 index 0000000..58c9fb9 --- /dev/null +++ b/client/.swcrc @@ -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 +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..44cc3e6 --- /dev/null +++ b/client/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "@swc/cli": "^0.1.57", + "@swc/core": "^1.2.209", + "@swc/helpers": "^0.4.3", + "browserslist": "^4.21.1" + } +} diff --git a/client/spack.config.js b/client/spack.config.js new file mode 100644 index 0000000..2b6246d --- /dev/null +++ b/client/spack.config.js @@ -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", + }, +}); diff --git a/client/src/app.js b/client/src/app.js new file mode 100644 index 0000000..83aa458 --- /dev/null +++ b/client/src/app.js @@ -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"; diff --git a/client/src/form-navigation.js b/client/src/form-navigation.js new file mode 100644 index 0000000..c292c38 --- /dev/null +++ b/client/src/form-navigation.js @@ -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 = ` + +
+
+ + +
+
+ `; + 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; + } + } + } +}); diff --git a/client/src/local-service-item.js b/client/src/local-service-item.js new file mode 100644 index 0000000..8123bfb --- /dev/null +++ b/client/src/local-service-item.js @@ -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 = ` + +
+

+ +
+ `; + } + + 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; + } +}); diff --git a/client/src/local-service.js b/client/src/local-service.js new file mode 100644 index 0000000..29e4389 --- /dev/null +++ b/client/src/local-service.js @@ -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 = ` + +

+ +
+ +
+ `; + } + + 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') || '' + } +}); diff --git a/client/src/local-services.js b/client/src/local-services.js new file mode 100644 index 0000000..bcfeb76 --- /dev/null +++ b/client/src/local-services.js @@ -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 = ` + +
+ +
+
+ +
+ `; + { + 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'); + } + } + } + } +}); diff --git a/client/src/login-form.js b/client/src/login-form.js new file mode 100644 index 0000000..e2d9af9 --- /dev/null +++ b/client/src/login-form.js @@ -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 = ` + +
+
+ + +
+
+ + +
+
+ +
+
+ `; + } + + connectedCallback() { + } + + attributeChangedCallback(name, oldV, newV) { + if (oldV === newV) return; + switch (name) { + } + } +}); diff --git a/client/src/ow-account.js b/client/src/ow-account.js new file mode 100644 index 0000000..fe3c46a --- /dev/null +++ b/client/src/ow-account.js @@ -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 = ` + +
+ + +
+ Nie masz konta? Utwórz nowe +
+
+ Masz konta? Zaloguj się +
+
+ `; + 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); + } +}); diff --git a/client/src/ow-nav.js b/client/src/ow-nav.js new file mode 100644 index 0000000..17d1ee0 --- /dev/null +++ b/client/src/ow-nav.js @@ -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 = ` + +
+ +
+ `; + } +}); diff --git a/client/src/ow-path.js b/client/src/ow-path.js new file mode 100644 index 0000000..c4e0b30 --- /dev/null +++ b/client/src/ow-path.js @@ -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 = ` + + + `; + } + + 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); + } +}); diff --git a/client/src/price/price-input.js b/client/src/price/price-input.js new file mode 100644 index 0000000..92d15a6 --- /dev/null +++ b/client/src/price/price-input.js @@ -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 = ` + +
+ + +
+ `; + } + + 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); + } +}); diff --git a/client/src/price/price-view.js b/client/src/price/price-view.js new file mode 100644 index 0000000..7adf93f --- /dev/null +++ b/client/src/price/price-view.js @@ -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 = ` + + + `; + } + + 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'; + } +}); diff --git a/client/src/register-form.js b/client/src/register-form.js new file mode 100644 index 0000000..31690f1 --- /dev/null +++ b/client/src/register-form.js @@ -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 = ` + +
+ + + + + + + + + + + + + + + + + +
+ `; + + 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); + } +}); diff --git a/client/src/register-form/register-basic-form.js b/client/src/register-form/register-basic-form.js new file mode 100644 index 0000000..5313a25 --- /dev/null +++ b/client/src/register-form/register-basic-form.js @@ -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 = ` + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ `; + + 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 })); + }) + } +}); diff --git a/client/src/register-form/register-company-form.js b/client/src/register-form/register-company-form.js new file mode 100644 index 0000000..0293304 --- /dev/null +++ b/client/src/register-form/register-company-form.js @@ -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 = ` + +
+
+ +
+
+ + +
+ +
+ `; + } +}) diff --git a/client/src/register-form/register-item-form-row.js b/client/src/register-form/register-item-form-row.js new file mode 100644 index 0000000..aabf666 --- /dev/null +++ b/client/src/register-form/register-item-form-row.js @@ -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 = ` + +
+
+ + +
+
+ + + +
+
+
+ `; + 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(); + } +}); diff --git a/client/src/register-form/register-items-form.js b/client/src/register-form/register-items-form.js new file mode 100644 index 0000000..e05a6d7 --- /dev/null +++ b/client/src/register-form/register-items-form.js @@ -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 = ` + +
+
+ +
+
+ +
+ +
+ `; + 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) + } +}); diff --git a/client/src/register-form/register-oauth2.js b/client/src/register-form/register-oauth2.js new file mode 100644 index 0000000..b1bcc4f --- /dev/null +++ b/client/src/register-form/register-oauth2.js @@ -0,0 +1,12 @@ +customElements.define('register-oauth2', class extends HTMLElement { + constructor() { + super(); + + const shadow = this.attachShadow({ mode: "closed" }); + shadow.innerHTML = ` + + Sign in with Google + + `; + } +}); diff --git a/client/src/register-form/register-submit-form.js b/client/src/register-form/register-submit-form.js new file mode 100644 index 0000000..cd954a5 --- /dev/null +++ b/client/src/register-form/register-submit-form.js @@ -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 = ` + +
+
+ + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+
+ `; + } + + 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); + } + } +}); diff --git a/client/src/register-form/register-user-type.js b/client/src/register-form/register-user-type.js new file mode 100644 index 0000000..c9546ef --- /dev/null +++ b/client/src/register-form/register-user-type.js @@ -0,0 +1,69 @@ +customElements.define('register-user-type', class extends HTMLElement { + constructor() { + super(); + + const shadow = this.attachShadow({ mode: "closed" }); + + shadow.innerHTML = ` + +
+ +
+ `; + + 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 })); + }); + } +}); diff --git a/client/src/shared.js b/client/src/shared.js new file mode 100644 index 0000000..49c5055 --- /dev/null +++ b/client/src/shared.js @@ -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; + } +} diff --git a/client/yarn.lock b/client/yarn.lock new file mode 100644 index 0000000..c3dc687 --- /dev/null +++ b/client/yarn.lock @@ -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" diff --git a/src/routes/unrestricted.rs b/src/routes/unrestricted.rs index 907358a..90bac5e 100644 --- a/src/routes/unrestricted.rs +++ b/src/routes/unrestricted.rs @@ -80,7 +80,7 @@ pub fn configure(config: &mut ServiceConfig) { .service(Files::new("/assets/images", "./assets/images")) .service(Files::new("/assets/css", "./assets/css")) .service( - Files::new("/assets/js", "./assets/js") + Files::new("/assets/js", "./client/dist") .use_etag(true) .prefer_utf8(true) .show_files_listing(),