diff --git a/components.js b/components.js new file mode 100644 index 0000000..e2f99c7 --- /dev/null +++ b/components.js @@ -0,0 +1,3576 @@ +//Button +const smButton = document.createElement('template') +smButton.innerHTML = ` + +`; +customElements.define('sm-button', + class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smButton.content.cloneNode(true)) + } + + get disabled() { + return this.isDisabled + } + + set disabled(value) { + if (value && !this.isDisabled) { + this.isDisabled = true + this.setAttribute('disabled', '') + this.button.removeAttribute('tabindex') + } else if (!value && this.isDisabled) { + this.isDisabled = false + this.removeAttribute('disabled') + } + } + + dispatch() { + if (this.isDisabled) { + this.dispatchEvent(new CustomEvent('disabled', { + bubbles: true, + composed: true + })) + } else { + this.dispatchEvent(new CustomEvent('clicked', { + bubbles: true, + composed: true + })) + } + } + + connectedCallback() { + this.isDisabled = false + this.button = this.shadowRoot.querySelector('.button') + if (this.hasAttribute('disabled') && !this.isDisabled) + this.isDisabled = true + this.addEventListener('click', (e) => { + this.dispatch() + }) + } + }) + +//Input +const smInput = document.createElement('template') +smInput.innerHTML = ` + +
+ +
+
+`; +customElements.define('sm-input', + class extends HTMLElement { + + static formAssociated = true; + + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smInput.content.cloneNode(true)) + } + + static get observedAttributes() { + return ['placeholder'] + } + + get value() { + return this.shadowRoot.querySelector('input').value + } + + set value(val) { + this.shadowRoot.querySelector('input').value = val; + this.checkInput() + this.fireEvent() + } + + get placeholder() { + return this.getAttribute('placeholder') + } + + set placeholder(val) { + this.setAttribute('placeholder', val) + } + + get type() { + return this.getAttribute('type') + } + + get isValid() { + return this.shadowRoot.querySelector('input').checkValidity() + } + + get validity() { + return this.shadowRoot.querySelector('input').validity + } + + set disabled(value) { + if (value) + this.shadowRoot.querySelector('.input').classList.add('disabled') + else + this.shadowRoot.querySelector('.input').classList.remove('disabled') + } + set readOnly(value) { + if (value) { + this.shadowRoot.querySelector('input').setAttribute('readonly', '') + this.shadowRoot.querySelector('.input').classList.add('readonly') + } else { + this.shadowRoot.querySelector('input').removeAttribute('readonly') + this.shadowRoot.querySelector('.input').classList.remove('readonly') + } + } + + setValidity = (message) => { + this.feedbackText.textContent = message + } + + showValidity = () => { + this.feedbackText.classList.remove('hide-completely') + } + + hideValidity = () => { + this.feedbackText.classList.add('hide-completely') + } + + focusIn = () => { + this.input.focus() + } + + focusOut = () => { + this.input.blur() + } + + fireEvent = () => { + let event = new Event('input', { + bubbles: true, + cancelable: true, + composed: true + }); + this.dispatchEvent(event); + } + + checkInput = (e) => { + if (!this.readonly) { + if (this.input.value !== '') { + this.clearBtn.classList.remove('hide') + } else { + this.clearBtn.classList.add('hide') + } + } + if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') return; + if (this.input.value !== '') { + if (this.animate) + this.inputParent.classList.add('animate-label') + else + this.label.classList.add('hide') + } else { + if (this.animate) + this.inputParent.classList.remove('animate-label') + else + this.label.classList.remove('hide') + } + } + + + connectedCallback() { + this.inputParent = this.shadowRoot.querySelector('.input') + this.clearBtn = this.shadowRoot.querySelector('.clear') + this.label = this.shadowRoot.querySelector('.label') + this.feedbackText = this.shadowRoot.querySelector('.feedback-text') + this.valueChanged = false; + this.readonly = false + this.isNumeric = false + this.min + this.max + this.animate = this.hasAttribute('animate') + this.input = this.shadowRoot.querySelector('input') + this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') + if (this.hasAttribute('value')) { + this.input.value = this.getAttribute('value') + this.checkInput() + } + if (this.hasAttribute('required')) { + this.input.setAttribute('required', '') + } + if (this.hasAttribute('min')) { + let minValue = this.getAttribute('min') + this.input.setAttribute('min', minValue) + this.min = parseInt(minValue) + } + if (this.hasAttribute('max')) { + let maxValue = this.getAttribute('max') + this.input.setAttribute('max', maxValue) + this.max = parseInt(maxValue) + } + if (this.hasAttribute('minlength')) { + const minValue = this.getAttribute('minlength') + this.input.setAttribute('minlength', minValue) + } + if (this.hasAttribute('maxlength')) { + const maxValue = this.getAttribute('maxlength') + this.input.setAttribute('maxlength', maxValue) + } + if (this.hasAttribute('step')) { + const steps = this.getAttribute('step') + this.input.setAttribute('step', steps) + } + if (this.hasAttribute('pattern')) { + this.input.setAttribute('pattern', this.getAttribute('pattern')) + } + if (this.hasAttribute('readonly')) { + this.input.setAttribute('readonly', '') + this.readonly = true + } + if (this.hasAttribute('disabled')) { + this.inputParent.classList.add('disabled') + } + if (this.hasAttribute('error-text')) { + this.feedbackText.textContent = this.getAttribute('error-text') + } + if (this.hasAttribute('type')) { + if (this.getAttribute('type') === 'number') { + this.input.setAttribute('inputmode', 'numeric') + this.input.setAttribute('type', 'number') + this.isNumeric = true + } else + this.input.setAttribute('type', this.getAttribute('type')) + } else + this.input.setAttribute('type', 'text') + this.input.addEventListener('input', e => { + this.checkInput(e) + }) + this.clearBtn.addEventListener('click', e => { + this.value = '' + }) + } + + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'placeholder') { + this.shadowRoot.querySelector('.label').textContent = newValue; + this.setAttribute('aria-label', newValue); + } + } + } + }) + +//textarea +const smTextarea = document.createElement('template') +smTextarea.innerHTML = ` + + +`; +customElements.define('sm-textarea', + class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smTextarea.content.cloneNode(true)) + this.textarea = this.shadowRoot.querySelector('textarea') + } + get value() { + return this.textarea.value + } + set value(val) { + this.textarea.value = val; + this.textareaBox.dataset.value = val + this.checkInput() + this.fireEvent() + } + focusIn = () => { + this.textarea.focus() + } + fireEvent() { + let event = new Event('input', { + bubbles: true, + cancelable: true, + composed: true + }); + this.dispatchEvent(event); + } + checkInput = () => { + if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') + return; + if (this.textarea.value !== '') { + this.placeholder.classList.add('hide') + } else { + this.placeholder.classList.remove('hide') + } + } + connectedCallback() { + this.textareaBox = this.shadowRoot.querySelector('.textarea') + this.placeholder = this.shadowRoot.querySelector('.placeholder') + + if(this.hasAttribute('placeholder')) + this.placeholder.textContent = this.getAttribute('placeholder') + + if (this.hasAttribute('value')) { + this.textarea.value = this.getAttribute('value') + this.checkInput() + } + if (this.hasAttribute('required')) { + this.textarea.setAttribute('required', '') + } + if (this.hasAttribute('readonly')) { + this.textarea.setAttribute('readonly', '') + } + if (this.hasAttribute('rows')) { + this.textarea.setAttribute('rows', this.getAttribute('rows')) + } + this.textarea.addEventListener('input', e => { + this.textareaBox.dataset.value = this.textarea.value + this.checkInput() + }) + } + }) + +// tab +const smTab = document.createElement('template') +smTab.innerHTML = ` + +
+ +
+`; + +customElements.define('sm-tab', class extends HTMLElement { + constructor() { + super() + this.shadow = this.attachShadow({ + mode: 'open' + }).append(smTab.content.cloneNode(true)) + } +}) + +//chcekbox + +const smCheckbox = document.createElement('template') +smCheckbox.innerHTML = ` + +` +customElements.define('sm-checkbox', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smCheckbox.content.cloneNode(true)) + + this.checkbox = this.shadowRoot.querySelector('.checkbox'); + this.input = this.shadowRoot.querySelector('input') + + this.isChecked = false + this.isDisabled = false + } + + static get observedAttributes() { + return ['disabled', 'checked'] + } + + get disabled() { + return this.isDisabled + } + + set disabled(val) { + if (val) { + this.setAttribute('disabled', '') + } else { + this.removeAttribute('disabled') + } + } + + get checked() { + return this.isChecked + } + + set checked(value) { + if (value) { + this.setAttribute('checked', '') + } + else { + this.removeAttribute('checked') + } + } + + set value(val) { + this.val = val + this.setAttribute('value', value) + } + + get value() { + return getAttribute('value') + } + + dispatch = () => { + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true + })) + } + handleKeyup = e => { + if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { + if (this.hasAttribute('checked')) { + this.input.checked = false + this.removeAttribute('checked') + } + else { + this.input.checked = true + this.setAttribute('checked', '') + } + } + } + handleChange = e => { + if (this.input.checked) { + this.setAttribute('checked', '') + } + else { + this.removeAttribute('checked') + } + } + + connectedCallback() { + this.val = '' + this.addEventListener('keyup', this.handleKeyup) + this.input.addEventListener('change', this.handleChange) + } + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'disabled') { + if (newValue === 'true') { + this.isDisabled = true + } else { + this.isDisabled = false + } + } + else if (name === 'checked') { + if (this.hasAttribute('checked')) { + this.isChecked = true + this.input.checked = true + } + else { + this.input.checked = false + this.isChecked = false + } + this.dispatch() + } + } + } + disconnectedCallback() { + this.removeEventListener('keyup', this.handleKeyup) + this.removeEventListener('change', this.handleChange) + } +}) + +//switch + +const smSwitch = document.createElement('template') +smSwitch.innerHTML = ` + +` + +customElements.define('sm-switch', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smSwitch.content.cloneNode(true)) + this.switch = this.shadowRoot.querySelector('.switch'); + this.input = this.shadowRoot.querySelector('input') + this.isChecked = false + this.isDisabled = false + } + + static get observedAttributes() { + return ['disabled', 'checked'] + } + + get disabled() { + return this.isDisabled + } + + set disabled(val) { + if (val) { + this.setAttribute('disabled', '') + } else { + this.removeAttribute('disabled') + } + } + + get checked() { + return this.isChecked + } + + set checked(value) { + if (value) { + this.setAttribute('checked', '') + } else { + this.removeAttribute('checked') + } + } + + dispatch = () => { + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true + })) + } + + connectedCallback() { + this.addEventListener('keyup', e => { + if ((e.code === "Enter" || e.code === "Space") && !this.isDisabled) { + this.input.click() + } + }) + this.input.addEventListener('click', e => { + if (this.input.checked) + this.checked = true + else + this.checked = false + this.dispatch() + }) + } + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'disabled') { + if (this.hasAttribute('disabled')) { + this.disabled = true + } + else { + this.disabled = false + } + } + else if (name === 'checked') { + if (this.hasAttribute('checked')) { + this.isChecked = true + this.input.checked = true + } + else { + this.isChecked = false + this.input.checked = false + } + } + } + } + +}) + +// select +const smSelect = document.createElement('template') +smSelect.innerHTML = ` + +
+
+
+ + + +
+
+ +
+
`; +customElements.define('sm-select', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smSelect.content.cloneNode(true)) + } + static get observedAttributes() { + return ['value'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + + collapse() { + this.optionList.animate(this.slideUp, this.animationOptions) + this.optionList.classList.add('hide') + this.chevron.classList.remove('rotate') + this.open = false + } + connectedCallback() { + this.availableOptions + this.optionList = this.shadowRoot.querySelector('.options') + this.chevron = this.shadowRoot.querySelector('.toggle') + let slot = this.shadowRoot.querySelector('.options slot'), + selection = this.shadowRoot.querySelector('.selection'), + previousOption + this.open = false; + this.slideDown = [{ + transform: `translateY(-0.5rem)` + }, + { + transform: `translateY(0)` + } + ], + this.slideUp = [{ + transform: `translateY(0)` + }, + { + transform: `translateY(-0.5rem)` + } + ], + this.animationOptions = { + duration: 300, + fill: "forwards", + easing: 'ease' + } + selection.addEventListener('click', e => { + if (!this.open) { + this.optionList.classList.remove('hide') + this.optionList.animate(this.slideDown, this.animationOptions) + this.chevron.classList.add('rotate') + this.open = true + } else { + this.collapse() + } + }) + selection.addEventListener('keydown', e => { + if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { + e.preventDefault() + this.availableOptions[0].focus() + } + if (e.code === 'Enter' || e.code === 'Space') + if (!this.open) { + this.optionList.classList.remove('hide') + this.optionList.animate(this.slideDown, this.animationOptions) + this.chevron.classList.add('rotate') + this.open = true + } else { + this.collapse() + } + }) + this.optionList.addEventListener('keydown', e => { + if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } + } + if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { + e.preventDefault() + if (document.activeElement.nextElementSibling) + document.activeElement.nextElementSibling.focus() + } + }) + this.addEventListener('optionSelected', e => { + if (previousOption !== e.target) { + this.setAttribute('value', e.detail.value) + this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true, + detail: { + value: e.detail.value + } + })) + if (previousOption) { + previousOption.classList.remove('check-selected') + } + previousOption = e.target; + } + if (!e.detail.switching) + this.collapse() + + e.target.classList.add('check-selected') + }) + slot.addEventListener('slotchange', e => { + this.availableOptions = slot.assignedElements() + if (this.availableOptions[0]) { + let firstElement = this.availableOptions[0]; + previousOption = firstElement; + firstElement.classList.add('check-selected') + this.setAttribute('value', firstElement.getAttribute('value')) + this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent + this.availableOptions.forEach((element, index) => { + element.setAttribute('data-rank', index + 1); + element.setAttribute('tabindex', "0"); + }) + } + }); + document.addEventListener('mousedown', e => { + if (!this.contains(e.target) && this.open) { + this.collapse() + } + }) + } +}) + +// option +const smOption = document.createElement('template') +smOption.innerHTML = ` + +
+ + + + +
`; +customElements.define('sm-option', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smOption.content.cloneNode(true)) + } + + sendDetails(switching) { + let optionSelected = new CustomEvent('optionSelected', { + bubbles: true, + composed: true, + detail: { + text: this.textContent, + value: this.getAttribute('value'), + switching: switching + } + }) + this.dispatchEvent(optionSelected) + } + + connectedCallback() { + let validKey = [ + 'ArrowUp', + 'ArrowDown', + 'ArrowLeft', + 'ArrowRight' + ] + this.addEventListener('click', e => { + this.sendDetails() + }) + this.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.sendDetails(false) + } + if (validKey.includes(e.code)) { + e.preventDefault() + this.sendDetails(true) + } + }) + if (this.hasAttribute('default')) { + setTimeout(() => { + this.sendDetails() + }, 0); + } + } +}) + +// select +const smStripSelect = document.createElement('template') +smStripSelect.innerHTML = ` + +
+
+ + Previous + + +
+ +
+ + Next + + +
+
`; +customElements.define('sm-strip-select', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smStripSelect.content.cloneNode(true)) + } + static get observedAttributes() { + return ['value'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + scrollLeft = () => { + this.select.scrollBy({ + top: 0, + left: -this.scrollDistance, + behavior: 'smooth' + }) + } + + scrollRight = () => { + this.select.scrollBy({ + top: 0, + left: this.scrollDistance, + behavior: 'smooth' + }) + } + connectedCallback() { + let previousOption, + slot = this.shadowRoot.querySelector('slot'); + this.selectContainer = this.shadowRoot.querySelector('.select-container') + this.select = this.shadowRoot.querySelector('.select') + this.nextArrow = this.shadowRoot.querySelector('.next-item') + this.previousArrow = this.shadowRoot.querySelector('.previous-item') + this.nextGradient = this.shadowRoot.querySelector('.right') + this.previousGradient = this.shadowRoot.querySelector('.left') + this.selectOptions + this.scrollDistance = this.selectContainer.getBoundingClientRect().width + const firstElementObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + this.previousArrow.classList.add('hide') + this.previousGradient.classList.add('hide') + } else { + this.previousArrow.classList.remove('hide') + this.previousGradient.classList.remove('hide') + } + }, { + root: this.selectContainer, + threshold: 0.95 + }) + const lastElementObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + this.nextArrow.classList.add('hide') + this.nextGradient.classList.add('hide') + } else { + this.nextArrow.classList.remove('hide') + this.nextGradient.classList.remove('hide') + } + }, { + root: this.selectContainer, + threshold: 0.95 + }) + + const selectObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + this.scrollDistance = this.selectContainer.getBoundingClientRect().width + } + }) + + selectObserver.observe(this.selectContainer) + this.addEventListener('optionSelected', e => { + if (previousOption === e.target) return; + if (previousOption) + previousOption.classList.remove('active') + e.target.classList.add('active') + e.target.scrollIntoView({ + behavior: 'smooth', + inline: 'center', + block: 'nearest' + }) + this.setAttribute('value', e.detail.value) + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true + })) + previousOption = e.target; + }) + slot.addEventListener('slotchange', e => { + this.selectOptions = slot.assignedElements() + firstElementObserver.observe(this.selectOptions[0]) + lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) + if (this.selectOptions[0]) { + let firstElement = this.selectOptions[0]; + this.setAttribute('value', firstElement.getAttribute('value')) + firstElement.classList.add('active') + previousOption = firstElement; + } + }); + this.nextArrow.addEventListener('click', this.scrollRight) + this.previousArrow.addEventListener('click', this.scrollLeft) + } + + disconnectedCallback() { + this.nextArrow.removeEventListener('click', this.scrollRight) + this.previousArrow.removeEventListener('click', this.scrollLeft) + } +}) + +// option +const smStripOption = document.createElement('template') +smStripOption.innerHTML = ` + +
+ +
`; +customElements.define('sm-strip-option', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smStripOption.content.cloneNode(true)) + } + sendDetails() { + let optionSelected = new CustomEvent('optionSelected', { + bubbles: true, + composed: true, + detail: { + text: this.textContent, + value: this.getAttribute('value') + } + }) + this.dispatchEvent(optionSelected) + } + + connectedCallback() { + this.addEventListener('click', e => { + this.sendDetails() + }) + this.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.sendDetails(false) + } + }) + if (this.hasAttribute('default')) { + setTimeout(() => { + this.sendDetails() + }, 0); + } + } +}) + +//popup +const smPopup = document.createElement('template') +smPopup.innerHTML = ` + + +`; +customElements.define('sm-popup', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smPopup.content.cloneNode(true)) + + this.allowClosing = false + } + + resumeScrolling = () => { + const scrollY = document.body.style.top; + window.scrollTo(0, parseInt(scrollY || '0') * -1); + setTimeout(() => { + document.body.style.overflow = 'auto'; + document.body.style.top= 'initial' + }, 300); + } + + show = (pinned, popupStack) => { + if (popupStack) + this.popupStack = popupStack + if (this.popupStack && !this.hasAttribute('open')) { + this.popupStack.push({ + popup: this, + permission: pinned + }) + if (this.popupStack.items.length > 1) { + this.popupStack.items[this.popupStack.items.length - 2].popup.classList.add('stacked') + } + this.dispatchEvent( + new CustomEvent("popupopened", { + bubbles: true, + detail: { + popup: this, + popupStack: this.popupStack + } + }) + ) + this.setAttribute('open', '') + this.pinned = pinned + } + this.popupContainer.classList.remove('hide') + this.popup.style.transform = 'none'; + document.body.style.overflow = 'hidden'; + document.body.style.top= `-${window.scrollY}px` + return this.popupStack + } + hide = () => { + if (window.innerWidth < 640) + this.popup.style.transform = 'translateY(100%)'; + else + this.popup.style.transform = 'translateY(3rem)'; + this.popupContainer.classList.add('hide') + this.removeAttribute('open') + if (typeof this.popupStack !== 'undefined') { + this.popupStack.pop() + if (this.popupStack.items.length) { + this.popupStack.items[this.popupStack.items.length - 1].popup.classList.remove('stacked') + } else { + this.resumeScrolling() + } + } else { + this.resumeScrolling() + } + + if (this.inputFields.length) { + setTimeout(() => { + this.inputFields.forEach(field => { + if (field.type === 'radio' || field.tagName === 'SM-CHECKBOX') + field.checked = false + if (field.tagName === 'SM-INPUT' || field.tagName === 'TEXTAREA'|| field.tagName === 'SM-TEXTAREA') + field.value = '' + }) + }, 300); + } + setTimeout(() => { + this.dispatchEvent( + new CustomEvent("popupclosed", { + bubbles: true, + detail: { + popup: this, + popupStack: this.popupStack + } + }) + ) + }, 300); + } + + handleTouchStart = (e) => { + this.touchStartY = e.changedTouches[0].clientY + this.popup.style.transition = 'transform 0.1s' + this.touchStartTime = e.timeStamp + } + + handleTouchMove = (e) => { + if (this.touchStartY < e.changedTouches[0].clientY) { + this.offset = e.changedTouches[0].clientY - this.touchStartY; + this.touchEndAnimataion = window.requestAnimationFrame(() => this.movePopup()) + } + /*else { + this.offset = this.touchStartY - e.changedTouches[0].clientY; + this.popup.style.transform = `translateY(-${this.offset}px)` + }*/ + } + + handleTouchEnd = (e) => { + this.touchEndTime = e.timeStamp + cancelAnimationFrame(this.touchEndAnimataion) + this.touchEndY = e.changedTouches[0].clientY + this.popup.style.transition = 'transform 0.3s' + this.threshold = this.popup.getBoundingClientRect().height * 0.3 + if (this.touchEndTime - this.touchStartTime > 200) { + if (this.touchEndY - this.touchStartY > this.threshold) { + if (this.pinned) { + this.show() + return + } else + this.hide() + } else { + this.show() + } + } else { + if (this.touchEndY > this.touchStartY) + if (this.pinned) { + this.show() + return + } + else + this.hide() + } + } + + movePopup = () => { + this.popup.style.transform = `translateY(${this.offset}px)` + } + + connectedCallback() { + this.pinned = false + this.popupStack + this.popupContainer = this.shadowRoot.querySelector('.popup-container') + this.popup = this.shadowRoot.querySelector('.popup') + this.popupBodySlot = this.shadowRoot.querySelector('.popup-body slot') + this.offset + this.popupHeader = this.shadowRoot.querySelector('.popup-top') + this.touchStartY = 0 + this.touchEndY = 0 + this.touchStartTime = 0 + this.touchEndTime = 0 + this.touchEndAnimataion; + this.threshold = this.popup.getBoundingClientRect().height * 0.3 + + if (this.hasAttribute('open')) + this.show() + this.popupContainer.addEventListener('mousedown', e => { + if (e.target === this.popupContainer && !this.pinned) { + if (this.pinned) { + this.show() + return + } else + this.hide() + } + }) + + this.popupBodySlot.addEventListener('slotchange', () => { + setTimeout(() => { + this.threshold = this.popup.getBoundingClientRect().height * 0.3 + }, 200); + this.inputFields = this.querySelectorAll('sm-input', 'sm-checkbox', 'textarea', 'sm-textarea', 'radio') + }) + + this.popupHeader.addEventListener('touchstart', (e) => { this.handleTouchStart(e) }, {passive: true}) + this.popupHeader.addEventListener('touchmove', (e) => {this.handleTouchMove(e)}, {passive: true}) + this.popupHeader.addEventListener('touchend', (e) => {this.handleTouchEnd(e)}, {passive: true}) + } + disconnectedCallback() { + this.popupHeader.removeEventListener('touchstart', this.handleTouchStart, {passive: true}) + this.popupHeader.removeEventListener('touchmove', this.handleTouchMove, {passive: true}) + this.popupHeader.removeEventListener('touchend', this.handleTouchEnd, {passive: true}) + } +}) + +//carousel + +const smCarousel = document.createElement('template') +smCarousel.innerHTML = ` + + +`; + +customElements.define('sm-carousel', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smCarousel.content.cloneNode(true)) + } + + static get observedAttributes() { + return ['indicator'] + } + + scrollLeft = () => { + this.carousel.scrollBy({ + top: 0, + left: -this.scrollDistance, + behavior: 'smooth' + }) + } + + scrollRight = () => { + this.carousel.scrollBy({ + top: 0, + left: this.scrollDistance, + behavior: 'smooth' + }) + } + + handleIndicatorClick = (e) => { + if (e.target.closest('.dot')) { + const slideNum = e.target.closest('.dot').getAttribute('rank') + if (this.activeSlideNum !== slideNum) { + this.showSlide(slideNum) + this.activeSlideNum = slideNum + } + } + } + + showSlide = (slideNum) => { + this.carouselItems[slideNum].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' }) + } + + connectedCallback() { + this.activeSlideNum + this.carousel = this.shadowRoot.querySelector('.carousel') + this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') + this.carouselSlot = this.shadowRoot.querySelector('slot') + this.nextArrow = this.shadowRoot.querySelector('.carousel__button--right') + this.previousArrow = this.shadowRoot.querySelector('.carousel__button--left') + this.indicatorsContainer = this.shadowRoot.querySelector('.indicators') + this.carouselItems + this.indicators + this.showIndicator = false + this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 + let frag = document.createDocumentFragment(); + if (this.hasAttribute('indicator')) + this.showIndicator = true + + + let firstVisible = false, + lastVisible = false + const allElementsObserver = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (this.showIndicator) + if (entry.isIntersecting) { + this.indicators[parseInt(entry.target.attributes.rank.textContent)].classList.add('active') + } + else + this.indicators[parseInt(entry.target.attributes.rank.textContent)].classList.remove('active') + if (!entry.target.previousElementSibling) + if (entry.isIntersecting) { + this.previousArrow.classList.remove('expand') + firstVisible = true + } + else { + this.previousArrow.classList.add('expand') + firstVisible = false + } + if (!entry.target.nextElementSibling) + if (entry.isIntersecting) { + this.nextArrow.classList.remove('expand') + lastVisible = true + } + else { + this.nextArrow.classList.add('expand') + + lastVisible = false + } + if (firstVisible && lastVisible) + this.indicatorsContainer.classList.add('hide') + else + this.indicatorsContainer.classList.remove('hide') + }) + }, { + root: this.carouselContainer, + threshold: 0.9 + }) + + const carouselObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 + } + }) + + carouselObserver.observe(this.carouselContainer) + + this.carouselSlot.addEventListener('slotchange', e => { + this.carouselItems = this.carouselSlot.assignedElements() + this.carouselItems.forEach(item => allElementsObserver.observe(item)) + if (this.showIndicator) { + this.indicatorsContainer.innerHTML = `` + this.carouselItems.forEach((item, index) => { + let dot = document.createElement('div') + dot.classList.add('dot') + dot.setAttribute('rank', index) + frag.append(dot) + item.setAttribute('rank', index) + }) + this.indicatorsContainer.append(frag) + this.indicators = this.indicatorsContainer.children + } + }) + + this.addEventListener('keyup', e => { + if (e.code === 'ArrowLeft') + this.scrollRight() + else if (e.code === 'ArrowRight') + this.scrollRight() + }) + + this.nextArrow.addEventListener('click', this.scrollRight) + this.previousArrow.addEventListener('click', this.scrollLeft) + this.indicatorsContainer.addEventListener('click', this.handleIndicatorClick) + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'indicator') { + if (this.hasAttribute('indicator')) + this.showIndicator = true + else + this.showIndicator = false + } + } + + disconnectedCallback() { + this.nextArrow.removeEventListener('click', this.scrollRight) + this.previousArrow.removeEventListener('click', this.scrollLeft) + this.indicatorsContainer.removeEventListener('click', this.handleIndicatorClick) + } +}) + +//notifications + +const smNotifications = document.createElement('template') +smNotifications.innerHTML = ` + +
+` + +customElements.define('sm-notifications', class extends HTMLElement { + constructor() { + super() + this.shadow = this.attachShadow({ + mode: 'open' + }).append(smNotifications.content.cloneNode(true)) + } + + handleTouchStart = (e) => { + this.notification = e.target.closest('.notification') + this.touchStartX = e.changedTouches[0].clientX + this.notification.style.transition = 'initial' + this.touchStartTime = e.timeStamp + } + + handleTouchMove = (e) => { + e.preventDefault() + if (this.touchStartX < e.changedTouches[0].clientX) { + this.offset = e.changedTouches[0].clientX - this.touchStartX; + this.touchEndAnimataion = requestAnimationFrame(this.movePopup) + } else { + this.offset = -(this.touchStartX - e.changedTouches[0].clientX); + this.touchEndAnimataion = requestAnimationFrame(this.movePopup) + } + } + + handleTouchEnd = (e) => { + this.notification.style.transition = 'transform 0.3s, opacity 0.3s' + this.touchEndTime = e.timeStamp + cancelAnimationFrame(this.touchEndAnimataion) + this.touchEndX = e.changedTouches[0].clientX + if (this.touchEndTime - this.touchStartTime > 200) { + if (this.touchEndX - this.touchStartX > this.threshold) { + this.removeNotification(this.notification) + } else if (this.touchStartX - this.touchEndX > this.threshold) { + this.removeNotification(this.notification, true) + } else { + this.resetPosition() + } + } else { + if (this.touchEndX > this.touchStartX) { + this.removeNotification(this.notification) + } else { + this.removeNotification(this.notification, true) + } + } + } + + movePopup = () => { + this.notification.style.transform = `translateX(${this.offset}px)` + } + + resetPosition = () => { + this.notification.style.transform = `translateX(0)` + } + + push = (messageBody, type, pinned) => { + let notification = document.createElement('div'), + composition = `` + notification.classList.add('notification') + if (pinned) + notification.classList.add('pinned') + if (type === 'error') { + composition += ` + + + + + ` + } else if (type === 'success') { + composition += ` + + + ` + } + composition += ` +

${messageBody}

+ + Close + + + ` + notification.innerHTML = composition + this.notificationPanel.prepend(notification) + if (window.innerWidth > 640) { + notification.animate([{ + transform: `translateX(1rem)`, + opacity: '0' + }, + { + transform: 'translateX(0)', + opacity: '1' + } + ], this.animationOptions).onfinish = () => { + notification.setAttribute('style', `transform: none;`); + } + } else { + notification.setAttribute('style', `transform: translateY(0); opacity: 1`) + } + notification.addEventListener('touchstart', this.handleTouchStart) + notification.addEventListener('touchmove', this.handleTouchMove) + notification.addEventListener('touchend', this.handleTouchEnd) + } + + removeNotification = (notification, toLeft) => { + if (!this.offset) + this.offset = 0; + + if (toLeft) + notification.animate([{ + transform: `translateX(${this.offset}px)`, + opacity: '1' + }, + { + transform: `translateX(-100%)`, + opacity: '0' + } + ], this.animationOptions).onfinish = () => { + notification.remove() + } + else { + notification.animate([{ + transform: `translateX(${this.offset}px)`, + opacity: '1' + }, + { + transform: `translateX(100%)`, + opacity: '0' + } + ], this.animationOptions).onfinish = () => { + notification.remove() + } + } + } + + clearAll = () => { + Array.from(this.notificationPanel.children).forEach(child => { + this.removeNotification(child) + }) + } + + connectedCallback() { + this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') + this.animationOptions = { + duration: 300, + fill: "forwards", + easing: "ease" + } + this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) + this.notification + this.offset + this.touchStartX = 0 + this.touchEndX = 0 + this.touchStartTime = 0 + this.touchEndTime = 0 + this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 + this.touchEndAnimataion; + + this.notificationPanel.addEventListener('click', e => { + if (e.target.closest('.close'))( + this.removeNotification(e.target.closest('.notification')) + ) + }) + + const observer = new MutationObserver(mutationList => { + mutationList.forEach(mutation => { + if (mutation.type === 'childList') { + if (mutation.addedNodes.length) { + if (!mutation.addedNodes[0].classList.contains('pinned')) + setTimeout(() => { + this.removeNotification(mutation.addedNodes[0]) + }, 5000); + if (window.innerWidth > 640) + this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; + else + this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; + } else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { + this.notificationPanel.style.padding = 0; + } + } + }) + }) + observer.observe(this.notificationPanel, { + attributes: true, + childList: true, + subtree: true + }) + } +}) + + + +// sm-menu +const smMenu = document.createElement('template') +smMenu.innerHTML = ` + +
+ +
+ +
+
`; +customElements.define('sm-menu', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smMenu.content.cloneNode(true)) + } + static get observedAttributes() { + return ['value'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + expand = () => { + if (!this.open) { + this.optionList.classList.remove('hide') + this.optionList.classList.add('no-transformations') + this.open = true + this.icon.classList.add('focused') + this.availableOptions.forEach(option => { + option.setAttribute('tabindex', '0') + }) + } + } + collapse() { + if (this.open) { + this.open = false + this.icon.classList.remove('focused') + this.optionList.classList.add('hide') + this.optionList.classList.remove('no-transformations') + this.availableOptions.forEach(option => { + option.removeAttribute('tabindex') + }) + } + } + connectedCallback() { + this.availableOptions + this.containerDimensions + this.optionList = this.shadowRoot.querySelector('.options') + let slot = this.shadowRoot.querySelector('.options slot'), + menu = this.shadowRoot.querySelector('.menu') + this.icon = this.shadowRoot.querySelector('.icon') + this.open = false; + menu.addEventListener('click', e => { + if (!this.open) { + this.expand() + } else { + this.collapse() + } + }) + menu.addEventListener('keydown', e => { + if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { + e.preventDefault() + this.availableOptions[0].focus() + } + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + if (!this.open) { + this.expand() + } else { + this.collapse() + } + } + }) + this.optionList.addEventListener('keydown', e => { + if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } + } + if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { + e.preventDefault() + if (document.activeElement.nextElementSibling) + document.activeElement.nextElementSibling.focus() + } + }) + this.optionList.addEventListener('click', e => { + this.collapse() + }) + slot.addEventListener('slotchange', e => { + this.availableOptions = slot.assignedElements() + this.containerDimensions = this.optionList.getBoundingClientRect() + }); + window.addEventListener('mousedown', e => { + if (!this.contains(e.target) && e.button !== 2) { + this.collapse() + } + }) + } +}) + +// option +const smMenuOption = document.createElement('template') +smMenuOption.innerHTML = ` + +
+ +
`; +customElements.define('sm-menu-option', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smMenuOption.content.cloneNode(true)) + } + + connectedCallback() { + this.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.click() + } + }) + } +}) + +// tab-header + +const smTabHeader = document.createElement('template') +smTabHeader.innerHTML = ` + +
+
+ +
+
+
+`; + +customElements.define('sm-tab-header', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smTabHeader.content.cloneNode(true)) + + this.indicator = this.shadowRoot.querySelector('.indicator'); + this.tabSlot = this.shadowRoot.querySelector('slot'); + this.tabHeader = this.shadowRoot.querySelector('.tab-header'); + } + + sendDetails(element) { + this.dispatchEvent( + new CustomEvent("switchtab", { + bubbles: true, + detail: { + target: this.target, + rank: parseInt(element.getAttribute('rank')) + } + }) + ) + } + + moveIndiactor(tabDimensions) { + //if(this.isTab) + this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) + //else + //this.indicator.setAttribute('style', `width: calc(${tabDimensions.width}px - 1.6rem); transform: translateX(calc(${ tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px + 0.8rem)`) + } + + connectedCallback() { + if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return; + this.prevTab + this.allTabs + this.activeTab + this.isTab = false + this.target = this.getAttribute('target') + + if (this.hasAttribute('variant') && this.getAttribute('variant') === 'tab') { + this.isTab = true + } + + this.tabSlot.addEventListener('slotchange', () => { + this.tabSlot.assignedElements().forEach((tab, index) => { + tab.setAttribute('rank', index) + }) + }) + this.allTabs = this.tabSlot.assignedElements(); + + this.tabSlot.addEventListener('click', e => { + if (e.target === this.prevTab || !e.target.closest('sm-tab')) + return + if (this.prevTab) + this.prevTab.classList.remove('active') + e.target.classList.add('active') + + e.target.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + inline: 'center' + }) + this.moveIndiactor(e.target.getBoundingClientRect()) + this.sendDetails(e.target) + this.prevTab = e.target; + this.activeTab = e.target; + }) + let resizeObserver = new ResizeObserver(entries => { + entries.forEach((entry) => { + if (this.prevTab) { + let tabDimensions = this.activeTab.getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + } + }) + }) + resizeObserver.observe(this) + let observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + this.indicator.style.transition = 'none' + if (this.activeTab) { + let tabDimensions = this.activeTab.getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + } else { + this.allTabs[0].classList.add('active') + let tabDimensions = this.allTabs[0].getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + this.sendDetails(this.allTabs[0]) + this.prevTab = this.tabSlot.assignedElements()[0]; + this.activeTab = this.prevTab; + } + } + }) + }, { + threshold: 1.0 + }) + observer.observe(this) + } +}) + +// tab-panels + +const smTabPanels = document.createElement('template') +smTabPanels.innerHTML = ` + +
+ Nothing to see here. +
+`; + +customElements.define('sm-tab-panels', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smTabPanels.content.cloneNode(true)) + this.panelSlot = this.shadowRoot.querySelector('slot'); + } + connectedCallback() { + + //animations + let flyInLeft = [{ + opacity: 0, + transform: 'translateX(-1rem)' + }, + { + opacity: 1, + transform: 'none' + } + ], + flyInRight = [{ + opacity: 0, + transform: 'translateX(1rem)' + }, + { + opacity: 1, + transform: 'none' + } + ], + flyOutLeft = [{ + opacity: 1, + transform: 'none' + }, + { + opacity: 0, + transform: 'translateX(-1rem)' + } + ], + flyOutRight = [{ + opacity: 1, + transform: 'none' + }, + { + opacity: 0, + transform: 'translateX(1rem)' + } + ], + animationOptions = { + duration: 300, + fill: 'forwards', + easing: 'ease' + } + this.prevPanel + this.allPanels + this.previousRank + + this.panelSlot.addEventListener('slotchange', () => { + this.panelSlot.assignedElements().forEach((panel) => { + panel.classList.add('hide-completely') + }) + }) + this.allPanels = this.panelSlot.assignedElements() + this._targetBodyFlyRight = (targetBody) => { + targetBody.classList.remove('hide-completely') + targetBody.animate(flyInRight, animationOptions) + } + this._targetBodyFlyLeft = (targetBody) => { + targetBody.classList.remove('hide-completely') + targetBody.animate(flyInLeft, animationOptions) + } + document.addEventListener('switchtab', e => { + if (e.detail.target !== this.id) + return + + if (this.prevPanel) { + let targetBody = this.allPanels[e.detail.rank], + currentBody = this.prevPanel; + if (this.previousRank < e.detail.rank) { + if (currentBody && !targetBody) + currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + } + else if (targetBody && !currentBody) { + this._targetBodyFlyRight(targetBody) + } else if (currentBody && targetBody) { + currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + this._targetBodyFlyRight(targetBody) + } + } + } else { + if (currentBody && !targetBody) + currentBody.animate(flyOutRight, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + } + else if (targetBody && !currentBody) { + this._targetBodyFlyLeft(targetBody) + } else if (currentBody && targetBody) { + currentBody.animate(flyOutRight, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + this._targetBodyFlyLeft(targetBody) + } + } + } + } else { + this.allPanels[e.detail.rank].classList.remove('hide-completely') + } + this.previousRank = e.detail.rank + this.prevPanel = this.allPanels[e.detail.rank]; + }) + } +}) diff --git a/css/bg.jpg b/css/bg.jpg new file mode 100644 index 0000000..650e18e Binary files /dev/null and b/css/bg.jpg differ diff --git a/css/main.css b/css/main.css index 95d85b0..1d131ec 100644 --- a/css/main.css +++ b/css/main.css @@ -11,7 +11,7 @@ html { } body { - --accent-color: #00a566; + --accent-color: #4d00a5; --light-shade: rgba(var(--text-color), 0.06); --text-color: 17, 17, 17; --text-color-light: 100, 100, 100; @@ -33,6 +33,14 @@ body[data-theme=dark] { background: rgba(var(--foreground-color), 1); } +.font-mono { + font-family: "Roboto Mono", sans-serif; +} + +.font-slab { + font-family: "Roboto slab", sans-serif; +} + .h1 { font-size: 2.5rem; } @@ -53,7 +61,16 @@ body[data-theme=dark] { font-size: 0.8rem; } +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + p { + max-width: 60ch; line-height: 1.5; } @@ -170,7 +187,7 @@ ul { justify-content: space-between; } -.full-width { +.w-100 { width: 100%; } @@ -178,22 +195,30 @@ ul { margin-top: 1.5rem; } -.margin-bottom-0-5 { +.margin-bottom-0-5r { margin-bottom: 0.5rem; } -.margin-bottom-1 { +.margin-bottom-1r { margin-bottom: 1rem; } -.margin-bottom-1-5 { +.margin-bottom-1-5r { margin-bottom: 1.5rem; } -.margin-bottom-2 { +.margin-bottom-2r { margin-bottom: 2rem; } +.margin-bottom-3r { + margin-bottom: 3rem; +} + +.margin-bottom-4r { + margin-bottom: 4rem; +} + .margin-left-0-5 { margin-left: 0.5rem; } @@ -306,16 +331,8 @@ ul { font-weight: 700; } -#background_tile { - position: absolute; - width: 100%; - height: 80vh; - left: 0; - top: 50vh; - z-index: -1; - -webkit-transform: skewY(-3deg); - transform: skewY(-3deg); - background: #f6f6f6; +.weight-900 { + font-weight: 900; } #main_header { @@ -338,14 +355,22 @@ ul { padding: 0 1rem; } +.common-padding { + padding: 0 1rem; +} + +.floor { + margin-bottom: 3rem; +} + #floor_1__outlets { margin: 1rem 0; gap: 1rem; - grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); } .outlet-preview { - padding: 1rem; + padding-top: 1rem; background: rgba(var(--foreground-color), 1); -webkit-transition: -webkit-box-shadow 0.3s; transition: -webkit-box-shadow 0.3s; @@ -353,23 +378,10 @@ ul { transition: box-shadow 0.3s, -webkit-box-shadow 0.3s; -webkit-box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px; box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px; - /* &:nth-of-type(1){ - transform: rotateY(1deg); - } - &:nth-of-type(2){ - transform: translateZ(-0.2rem); - } - &:nth-of-type(3){ - transform: rotateY(-1deg); - } */ -} -.outlet-preview:hover { - -webkit-box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; - box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; } .outlet__title { - font-weight: bold; + font-weight: 900; text-transform: capitalize; } @@ -377,9 +389,37 @@ ul { color: rgba(var(--text-color), 0.8); } +.label { + margin-bottom: 0.4rem; + font-size: 0.8rem; +} + +sm-carousel { + height: 100%; + background: rgba(var(--text-color), 0.04); + padding-bottom: 4rem; + padding-top: 1.5rem; + --arrow-left: 2rem; + --arrow-right: 2rem; + --arrow-fill: rgba(var(--text-color), 1); + --arrow-background: transparent; + --arrow-box-shadow: none; + --arrow-bottom: -3.5rem; + --indicator-bottom: -2.5rem; +} + +.bit-bond-series__row, +.bob-fund__row, .investor-card { + min-width: 100%; +} + +.investor-card { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; grid-template-columns: auto 1fr; - grid-template-areas: "img ." "img ."; + grid-template-areas: "img ." "para para"; } .investor__image { @@ -389,7 +429,48 @@ ul { border-radius: 50%; } +.investor__contribution-container { + grid-area: para; +} + +sm-tab-header { + padding: 0.3rem; + border-radius: 0.3rem; + background: rgba(var(--text-color), 0.06); +} + +table { + border-collapse: collapse; +} + +.tr { + margin: 0.5rem; +} +.tr:nth-of-type(even) { + background: rgba(var(--text-color), 0.1); +} + +.td { + padding: 0.6rem 0.8rem; +} + @media only screen and (min-width: 640px) { + .h1 { + font-size: 4rem; + } + + .h2 { + font-size: 2.5rem; + } + + .h3 { + font-size: 1.5rem; + } + + .h4 { + font-size: 1.1rem; + } + #main_header { padding: 1.5rem 2rem; } @@ -397,15 +478,19 @@ ul { .page { padding: 0 3rem; } + + .common-padding { + padding: 0 2rem; + } + + .outlet-preview { + padding-top: 3rem; + } } @media only screen and (min-width: 1280px) { .page { padding: 0 10vw; } - - .outlet-preview { - padding: 3rem 2rem; - } } @media (any-hover: hover) { ::-webkit-scrollbar { @@ -420,4 +505,10 @@ ul { ::-webkit-scrollbar-thumb:hover { background: rgba(var(--text-color), 0.5); } + + .outlet-preview:hover { + z-index: 1; + -webkit-box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; + box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; + } } \ No newline at end of file diff --git a/css/main.min.css b/css/main.min.css index dfaac0c..be8e98d 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -*{padding:0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:"Roboto",sans-serif}html{scroll-behavior:smooth}body{--accent-color: #00a566;--light-shade: rgba(var(--text-color), 0.06);--text-color: 17, 17, 17;--text-color-light: 100, 100, 100;--foreground-color: 255, 255, 255;--background-color: #efefef;--error-color: red;color:rgba(var(--text-color), 1);height:calc(100%);font-size:clamp(1rem, 1.2vmax, 3rem);background:rgba(var(--text-color), 0.06)}body[data-theme=dark]{--accent-color:#00fa9a;--text-color: 240, 240, 240;--text-color-light: 170, 170, 170;--foreground-color: 20, 20, 20;--error-color: rgb(255, 106, 106);background:rgba(var(--foreground-color), 1)}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}p{line-height:1.5}img{-o-object-fit:cover;object-fit:cover}button{position:relative;overflow:hidden;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:none;background:none;cursor:pointer;outline:none;color:inherit;font-weight:500;-webkit-tap-highlight-color:transparent}.button{border-radius:.2rem;padding:.5rem .6rem}.button--primary{background:var(--accent-color);color:rgba(var(--foreground-color), 1)}.button--primary .icon{fill:rgba(var(--foreground-color), 1)}button:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}sm-input,sm-textarea{--border-radius: 0.2rem;--background: rgba(var(--text-color), 0.06)}sm-button{--border-radius: 0.2rem}ul{list-style:none}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.align-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.text-center{text-align:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-right{margin-left:auto}.direction-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.full-width{width:100%}.margin-top-1-5{margin-top:1.5rem}.margin-bottom-0-5{margin-bottom:.5rem}.margin-bottom-1{margin-bottom:1rem}.margin-bottom-1-5{margin-bottom:1.5rem}.margin-bottom-2{margin-bottom:2rem}.margin-left-0-5{margin-left:.5rem}.margin-right-0-5{margin-right:.5rem}.hide{opacity:0;pointer-events:none}.hide-completely{display:none !important}.no-transformations{-webkit-transform:none !important;transform:none !important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ripple{position:absolute;border-radius:50%;-webkit-transform:scale(0);transform:scale(0);background:rgba(var(--text-color), 0.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color), 0.9)}.icon-only{height:2.6rem;width:2.6rem;padding:.6rem}.close-icon{padding:.3rem}.close-button{left:-0.5rem}.button__label{font-size:1rem}.button__icon{height:1.1rem;width:1.1rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}.color-0-9{color:rgba(var(--text-color), 0.9)}.color-0-8{color:rgba(var(--text-color), 0.8)}.color-0-7{color:rgba(var(--text-color), 0.7)}.weight-400{font-weight:400}.weight-500{font-weight:500}.weight-700{font-weight:700}#background_tile{position:absolute;width:100%;height:80vh;left:0;top:50vh;z-index:-1;-webkit-transform:skewY(-3deg);transform:skewY(-3deg);background:#f6f6f6}#main_header{position:relative;padding:1rem;grid-template-columns:repeat(3, 1fr)}#main_logo{position:absolute;justify-self:center}#main_header__logo{height:1.8rem;width:1.8rem}.page{padding:0 1rem}#floor_1__outlets{margin:1rem 0;gap:1rem;grid-template-columns:repeat(auto-fill, minmax(18rem, 1fr))}.outlet-preview{padding:1rem;background:rgba(var(--foreground-color), 1);-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s, -webkit-box-shadow .3s;-webkit-box-shadow:rgba(50,50,93,.25) 0px 2px 5px -1px,rgba(0,0,0,.3) 0px 1px 3px -1px;box-shadow:rgba(50,50,93,.25) 0px 2px 5px -1px,rgba(0,0,0,.3) 0px 1px 3px -1px}.outlet-preview:hover{-webkit-box-shadow:rgba(17,12,46,.15) 0px 48px 100px 0px;box-shadow:rgba(17,12,46,.15) 0px 48px 100px 0px}.outlet__title{font-weight:bold;text-transform:capitalize}.outlet__description{color:rgba(var(--text-color), 0.8)}.investor-card{grid-template-columns:auto 1fr;grid-template-areas:"img ." "img ."}.investor__image{grid-area:img;width:4rem;height:4rem;border-radius:50%}@media only screen and (min-width: 640px){#main_header{padding:1.5rem 2rem}.page{padding:0 3rem}}@media only screen and (min-width: 1280px){.page{padding:0 10vw}.outlet-preview{padding:3rem 2rem}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}} \ No newline at end of file +*{padding:0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:"Roboto",sans-serif}html{scroll-behavior:smooth}body{--accent-color: #4d00a5;--light-shade: rgba(var(--text-color), 0.06);--text-color: 17, 17, 17;--text-color-light: 100, 100, 100;--foreground-color: 255, 255, 255;--background-color: #efefef;--error-color: red;color:rgba(var(--text-color), 1);height:calc(100%);font-size:clamp(1rem, 1.2vmax, 3rem);background:rgba(var(--text-color), 0.06)}body[data-theme=dark]{--accent-color:#00fa9a;--text-color: 240, 240, 240;--text-color-light: 170, 170, 170;--foreground-color: 20, 20, 20;--error-color: rgb(255, 106, 106);background:rgba(var(--foreground-color), 1)}.font-mono{font-family:"Roboto Mono",sans-serif}.font-slab{font-family:"Roboto slab",sans-serif}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}p{max-width:60ch;line-height:1.5}img{-o-object-fit:cover;object-fit:cover}button{position:relative;overflow:hidden;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:none;background:none;cursor:pointer;outline:none;color:inherit;font-weight:500;-webkit-tap-highlight-color:transparent}.button{border-radius:.2rem;padding:.5rem .6rem}.button--primary{background:var(--accent-color);color:rgba(var(--foreground-color), 1)}.button--primary .icon{fill:rgba(var(--foreground-color), 1)}button:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}sm-input,sm-textarea{--border-radius: 0.2rem;--background: rgba(var(--text-color), 0.06)}sm-button{--border-radius: 0.2rem}ul{list-style:none}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.align-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.text-center{text-align:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-right{margin-left:auto}.direction-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.w-100{width:100%}.margin-top-1-5{margin-top:1.5rem}.margin-bottom-0-5r{margin-bottom:.5rem}.margin-bottom-1r{margin-bottom:1rem}.margin-bottom-1-5r{margin-bottom:1.5rem}.margin-bottom-2r{margin-bottom:2rem}.margin-bottom-3r{margin-bottom:3rem}.margin-bottom-4r{margin-bottom:4rem}.margin-left-0-5{margin-left:.5rem}.margin-right-0-5{margin-right:.5rem}.hide{opacity:0;pointer-events:none}.hide-completely{display:none !important}.no-transformations{-webkit-transform:none !important;transform:none !important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ripple{position:absolute;border-radius:50%;-webkit-transform:scale(0);transform:scale(0);background:rgba(var(--text-color), 0.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color), 0.9)}.icon-only{height:2.6rem;width:2.6rem;padding:.6rem}.close-icon{padding:.3rem}.close-button{left:-0.5rem}.button__label{font-size:1rem}.button__icon{height:1.1rem;width:1.1rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}.color-0-9{color:rgba(var(--text-color), 0.9)}.color-0-8{color:rgba(var(--text-color), 0.8)}.color-0-7{color:rgba(var(--text-color), 0.7)}.weight-400{font-weight:400}.weight-500{font-weight:500}.weight-700{font-weight:700}.weight-900{font-weight:900}#main_header{position:relative;padding:1rem;grid-template-columns:repeat(3, 1fr)}#main_logo{position:absolute;justify-self:center}#main_header__logo{height:1.8rem;width:1.8rem}.page{padding:0 1rem}.common-padding{padding:0 1rem}.floor{margin-bottom:3rem}#floor_1__outlets{margin:1rem 0;gap:1rem;grid-template-columns:repeat(auto-fill, minmax(20rem, 1fr))}.outlet-preview{padding-top:1rem;background:rgba(var(--foreground-color), 1);-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s, -webkit-box-shadow .3s;-webkit-box-shadow:rgba(50,50,93,.25) 0px 2px 5px -1px,rgba(0,0,0,.3) 0px 1px 3px -1px;box-shadow:rgba(50,50,93,.25) 0px 2px 5px -1px,rgba(0,0,0,.3) 0px 1px 3px -1px}.outlet__title{font-weight:900;text-transform:capitalize}.outlet__description{color:rgba(var(--text-color), 0.8)}.label{margin-bottom:.4rem;font-size:.8rem}sm-carousel{height:100%;background:rgba(var(--text-color), 0.04);padding-bottom:4rem;padding-top:1.5rem;--arrow-left: 2rem;--arrow-right: 2rem;--arrow-fill: rgba(var(--text-color), 1);--arrow-background: transparent;--arrow-box-shadow: none;--arrow-bottom: -3.5rem;--indicator-bottom: -2.5rem}.bit-bond-series__row,.bob-fund__row,.investor-card{min-width:100%}.investor-card{-webkit-box-align:center;-ms-flex-align:center;align-items:center;grid-template-columns:auto 1fr;grid-template-areas:"img ." "para para"}.investor__image{grid-area:img;width:4rem;height:4rem;border-radius:50%}.investor__contribution-container{grid-area:para}sm-tab-header{padding:.3rem;border-radius:.3rem;background:rgba(var(--text-color), 0.06)}table{border-collapse:collapse}.tr{margin:.5rem}.tr:nth-of-type(even){background:rgba(var(--text-color), 0.1)}.td{padding:.6rem .8rem}@media only screen and (min-width: 640px){.h1{font-size:4rem}.h2{font-size:2.5rem}.h3{font-size:1.5rem}.h4{font-size:1.1rem}#main_header{padding:1.5rem 2rem}.page{padding:0 3rem}.common-padding{padding:0 2rem}.outlet-preview{padding-top:3rem}}@media only screen and (min-width: 1280px){.page{padding:0 10vw}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}.outlet-preview:hover{z-index:1;-webkit-box-shadow:rgba(17,12,46,.15) 0px 48px 100px 0px;box-shadow:rgba(17,12,46,.15) 0px 48px 100px 0px}} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss index 702266d..a364ef7 100644 --- a/css/main.scss +++ b/css/main.scss @@ -10,7 +10,7 @@ html { } body { - --accent-color: #00a566; + --accent-color: #4d00a5; --light-shade: rgba(var(--text-color), 0.06); --text-color: 17, 17, 17; --text-color-light: 100, 100, 100; @@ -30,8 +30,11 @@ body[data-theme='dark']{ --error-color: rgb(255, 106, 106); background: rgba(var(--foreground-color), 1); } -.heading{ - // font-family: 'Roboto Mono', sans-serif; +.font-mono{ + font-family: 'Roboto Mono', sans-serif; +} +.font-slab{ + font-family: 'Roboto slab', sans-serif; } .h1{ @@ -50,7 +53,15 @@ body[data-theme='dark']{ font-size: 0.8rem; } +.uppercase{ + text-transform: uppercase; +} +.capitalize{ + text-transform: capitalize; +} + p { + max-width: 60ch; line-height: 1.5; } @@ -132,24 +143,30 @@ ul{ .space-between{ justify-content: space-between; } -.full-width{ +.w-100{ width: 100%; } .margin-top-1-5{ margin-top: 1.5rem; } -.margin-bottom-0-5{ +.margin-bottom-0-5r{ margin-bottom: 0.5rem; } -.margin-bottom-1{ +.margin-bottom-1r{ margin-bottom: 1rem; } -.margin-bottom-1-5{ +.margin-bottom-1-5r{ margin-bottom: 1.5rem; } -.margin-bottom-2{ +.margin-bottom-2r{ margin-bottom: 2rem; } +.margin-bottom-3r{ + margin-bottom: 3rem; +} +.margin-bottom-4r{ + margin-bottom: 4rem; +} .margin-left-0-5{ margin-left: 0.5rem; } @@ -241,19 +258,11 @@ ul{ .weight-700{ font-weight: 700; } - - -#background_tile{ - position: absolute; - width: 100%; - height: 80vh; - left: 0; - top: 50vh; - z-index: -1; - transform: skewY(-3deg); - background: #f6f6f6; +.weight-900{ + font-weight: 900; } + #main_header{ position: relative; padding: 1rem; @@ -272,34 +281,29 @@ ul{ padding: 0 1rem; } +.common-padding{ + padding: 0 1rem; +} + +.floor{ + margin-bottom: 3rem; +} + #floor_1__outlets{ margin: 1rem 0; gap: 1rem; - grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); } .outlet-preview{ - // transform-style: preserve-3d; - padding: 1rem; + padding-top: 1rem; background: rgba(var(--foreground-color), 1); // border: solid 0.8rem rgba(var(--text-color), 1); transition: box-shadow 0.3s; box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px; - &:hover{ - box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; - } -/* &:nth-of-type(1){ - transform: rotateY(1deg); - } - &:nth-of-type(2){ - transform: translateZ(-0.2rem); - } - &:nth-of-type(3){ - transform: rotateY(-1deg); - } */ } .outlet__title{ - font-weight: bold; + font-weight: 900; text-transform: capitalize; } .outlet__description{ @@ -307,9 +311,35 @@ ul{ } .outlet-preview__button{} +.label{ + margin-bottom: 0.4rem; + font-size: 0.8rem; +} + +sm-carousel{ + height: 100%; + background: rgba(var(--text-color), 0.04); + padding-bottom: 4rem; + padding-top: 1.5rem; + --arrow-left: 2rem; + --arrow-right: 2rem; + --arrow-fill: rgba(var(--text-color), 1); + --arrow-background: transparent; + --arrow-box-shadow: none; + --arrow-bottom: -3.5rem; + --indicator-bottom: -2.5rem; +} + +.bit-bond-series__row, +.bob-fund__row, .investor-card{ + min-width: 100%; +} + +.investor-card{ + align-items: center; grid-template-columns: auto 1fr; - grid-template-areas: 'img .' 'img .'; + grid-template-areas: 'img .' 'para para'; } .investor__image{ grid-area: img; @@ -317,23 +347,62 @@ ul{ height: 4rem; border-radius: 50%; } +.investor__contribution-container{ + grid-area: para; +} + + + +sm-tab-header{ + padding: 0.3rem; + border-radius: 0.3rem; + background: rgba(var(--text-color), 0.06); +} + +table{ + border-collapse: collapse; +} +.tr{ + margin: 0.5rem; + &:nth-of-type(even){ + background: rgba(var(--text-color), 0.1); + } +} +.td{ + padding: 0.6rem 0.8rem; +} @media only screen and (min-width: 640px) { + .h1{ + font-size: 4rem; + } + .h2{ + font-size: 2.5rem; + } + .h3{ + font-size: 1.5rem; + } + .h4{ + font-size: 1.1rem; + } #main_header{ padding: 1.5rem 2rem; } .page{ padding: 0 3rem; } + .common-padding{ + padding: 0 2rem; + } + .outlet-preview{ + padding-top: 3rem; + } } @media only screen and (min-width: 1280px) { .page{ padding: 0 10vw; } - .outlet-preview{ - padding: 3rem 2rem; - } } @media (any-hover: hover){ @@ -349,4 +418,8 @@ ul{ background: rgba(var(--text-color), 0.5); } } + .outlet-preview:hover{ + z-index: 1; + box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; + } } \ No newline at end of file diff --git a/index.html b/index.html index ab16fa6..b072ee9 100644 --- a/index.html +++ b/index.html @@ -7,152 +7,622 @@ Document - + - - + + +

+

+
+ Cancel + OK +
+
+ +

+

+ +
+ Cancel + OK +
+
+ + + + + + + - -
-
+
-
+
-
-

Floor 1

+
+

Floor 1

-
-

bitcoin bonds

-

+

+

bitcoin bonds

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam reprehenderit cumque sequi earum.

-
-
+
-
-

Bob's Fund

-

+

+

Bob's Fund

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam reprehenderit cumque sequi earum.

-
-
-
-
- Investor -
-

- John Doe -

-
-
-
-
- Series -
-

- $975 -

-
-
-

- Current value -

-

- $XXXXXX -

-
-
-

- Time Elapsed -

-

- XXXXXX -

-
-
-
+
-
-

ICO

-

+

+

ICO

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam reprehenderit cumque sequi earum.

-
-
-
- -
-

- Investor -

-

- John Doe -

-
-
-

- Contribution -

-

- Helping us in social media with increasing reach of Twitter -

-
-
-
+
- + \ No newline at end of file