diff --git a/components.js b/components.js index eb60810..8ec9766 100644 --- a/components.js +++ b/components.js @@ -1,3543 +1,12 @@ -//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() - }) - this.addEventListener('keyup', (e) => { - if (e.code === "Enter" || e.code === "Space") - this.dispatch() - }) - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - -
- -
-
-`; -customElements.define('sm-input', - class extends HTMLElement { - 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.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') - if (!this.readonly) - this.clearBtn.classList.remove('hide') - } else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - if (!this.readonly) - this.clearBtn.classList.add('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')) { - let minValue = this.getAttribute('minlength') - this.input.setAttribute('minlength', minValue) - } - if (this.hasAttribute('maxlength')) { - let maxValue = this.getAttribute('maxlength') - this.input.setAttribute('maxlength', maxValue) - } - 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') - this.textareaBox = this.shadowRoot.querySelector('.textarea') - this.placeholder = this.shadowRoot.querySelector('.placeholder') - this.reflectedAttributes = ['disabled', 'required', 'readonly', 'rows', 'minlength', 'maxlength'] - - this.reset = this.reset.bind(this) - this.focusIn = this.focusIn.bind(this) - this.fireEvent = this.fireEvent.bind(this) - this.checkInput = this.checkInput.bind(this) - } - static get observedAttributes() { - return ['disabled', 'value', 'placeholder', 'required', 'readonly', 'rows', 'minlength', 'maxlength'] - } - get value() { - return this.textarea.value - } - set value(val) { - this.setAttribute('value', val) - this.fireEvent() - } - get disabled() { - return this.hasAttribute('disabled') - } - set disabled(val) { - if (val) { - this.setAttribute('disabled', '') - } else { - this.removeAttribute('disabled') - } - } - get isValid() { - return this.textarea.checkValidity() - } - reset() { - this.setAttribute('value', '') - } - 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.textarea.addEventListener('input', e => { - this.textareaBox.dataset.value = this.textarea.value - this.checkInput() - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (this.reflectedAttributes.includes(name)) { - if (this.hasAttribute(name)) { - this.textarea.setAttribute(name, this.getAttribute(name) ? this.getAttribute(name) : '') - } - else { - this.textContent.removeAttribute(name) - } - } - else if (name === 'placeholder') { - this.placeholder.textContent = this.getAttribute('placeholder') - } - else if (name === 'value') { - this.textarea.value = newValue; - this.textareaBox.dataset.value = newValue - 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.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.getAttribute('checked') - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch() { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.checkbox.classList.add('disabled') - this.isDisabled = true - } else { - this.checkbox.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } - -}) - -//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 - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - if (val) { - this.disabled = true - this.setAttribute('disabled', '') - this.switch.classList.add('disabled') - } else { - this.disabled = false - this.removeAttribute('disabled') - this.switch.classList.remove('disabled') - - } - } - - get checked() { - return this.isChecked - } - - set checked(value) { - if (value) { - this.setAttribute('checked', '') - this.isChecked = true - this.input.checked = true - } else { - this.removeAttribute('checked') - this.isChecked = false - this.input.checked = false - } - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - if (this.hasAttribute('disabled')) - this.switch.classList.add('disabled') - if (this.hasAttribute('checked')) - this.input.checked = true - 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() - }) - } -}) - -// 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 - })) - 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.setAttribute('style', `overflow: auto; 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.setAttribute('style', `overflow: hidden; 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.value = '' - }) - }, 300); - } - this.dispatchEvent( - new CustomEvent("popupclosed", { - bubbles: true, - detail: { - popup: this, - popupStack: this.popupStack - } - }) - ) - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.1s' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - e.preventDefault() - 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' - 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 - - 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) - }) - this.popupHeader.addEventListener('touchmove', (e) => { - this.handleTouchMove(e) - }) - this.popupHeader.addEventListener('touchend', (e) => { - this.handleTouchEnd(e) - }) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd) - } -}) - -//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' - }) - } - - connectedCallback() { - this.carousel = this.shadowRoot.querySelector('.carousel') - this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') - this.carouselSlot = this.shadowRoot.querySelector('slot') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - 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') - 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 - this.scrollRight() - }) - - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - 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) - } -}) - -//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') - } - } - collapse() { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - } - } - 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() - this.menuDimensions = menu.getBoundingClientRect() - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - if (this.hasAttribute('set-context') && this.getAttribute('set-context') === 'true') { - this.parentNode.setAttribute('oncontextmenu', 'return false') - this.parentNode.addEventListener('mouseup', e => { - if (e.button === 2) { - this.expand() - } - }) - } - } -}) - -// 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() - } - }) - this.setAttribute('tabindex', '0') - } -}) - -// 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]; - }) - } -}) - - -const slidingSection = document.createElement('template') -slidingSection.innerHTML = ` - -
- -
-` - -customElements.define('sm-sliding-section', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(slidingSection.content.cloneNode(true)) - } - connectedCallback() { - - } -}) - -const section = document.createElement('template') -section.innerHTML = ` - -
- -
-` - -customElements.define('sm-section', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(section.content.cloneNode(true)) - } -}) \ No newline at end of file +const smButton = document.createElement("template"); smButton.innerHTML = "\n\n
\n \n
", customElements.define("sm-button", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smButton.content.cloneNode(!0)) } static get observedAttributes() { return ["disabled"] } get disabled() { return this.hasAttribute("disabled") } set disabled(t) { t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled") } focusIn() { this.focus() } handleKeyDown(t) { this.hasAttribute("disabled") || "Enter" !== t.key && " " !== t.key || (t.preventDefault(), this.click()) } connectedCallback() { this.hasAttribute("disabled") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "button"), this.addEventListener("keydown", this.handleKeyDown) } attributeChangedCallback(t) { "disabled" === t && (this.hasAttribute("disabled") ? this.removeAttribute("tabindex") : this.setAttribute("tabindex", "0"), this.setAttribute("aria-disabled", this.hasAttribute("disabled"))) } }); +const smCheckbox = document.createElement("template"); smCheckbox.innerHTML = '\n\n', customElements.define("sm-checkbox", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smCheckbox.content.cloneNode(!0)), this.defaultState, this.checkbox = this.shadowRoot.querySelector(".checkbox"), this.reset = this.reset.bind(this), this.dispatch = this.dispatch.bind(this), this.handleKeyDown = this.handleKeyDown.bind(this), this.handleClick = this.handleClick.bind(this) } static get observedAttributes() { return ["value", "disabled", "checked"] } get disabled() { return this.hasAttribute("disabled") } set disabled(e) { e ? this.setAttribute("disabled", "") : this.removeAttribute("disabled") } get checked() { return this.hasAttribute("checked") } set checked(e) { e ? this.setAttribute("checked", "") : this.removeAttribute("checked") } set value(e) { this.setAttribute("value", e) } get value() { return this.getAttribute("value") } focusIn() { this.focus() } reset() { this.value = this.defaultState } dispatch() { this.dispatchEvent(new CustomEvent("change", { bubbles: !0, composed: !0 })) } handleKeyDown(e) { " " === e.key && (e.preventDefault(), this.click()) } handleClick(e) { this.toggleAttribute("checked") } connectedCallback() { this.hasAttribute("disabled") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "checkbox"), this.defaultState = this.hasAttribute("checked"), this.hasAttribute("checked") || this.setAttribute("aria-checked", "false"), this.addEventListener("keydown", this.handleKeyDown), this.addEventListener("click", this.handleClick) } attributeChangedCallback(e, t, n) { t !== n && ("checked" === e ? (this.setAttribute("aria-checked", this.hasAttribute("checked")), this.dispatch()) : "disabled" === e && (this.hasAttribute("disabled") ? this.removeAttribute("tabindex") : this.setAttribute("tabindex", "0"))) } disconnectedCallback() { this.removeEventListener("keydown", this.handleKeyDown), this.removeEventListener("change", this.handleClick) } }); +const smForm = document.createElement("template"); smForm.innerHTML = '\n \n
\n \n
\n ', customElements.define("sm-form", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smForm.content.cloneNode(!0)), this.form = this.shadowRoot.querySelector("form"), this.formElements, this.requiredElements, this.submitButton, this.resetButton, this.invalidFields = !1, this.mutationObserver, this.debounce = this.debounce.bind(this), this._checkValidity = this._checkValidity.bind(this), this.handleKeydown = this.handleKeydown.bind(this), this.reset = this.reset.bind(this), this.elementsChanged = this.elementsChanged.bind(this) } debounce(t, e) { let i = null; return (...s) => { window.clearTimeout(i), i = window.setTimeout(() => { t.apply(null, s) }, e) } } _checkValidity() { this.submitButton && (this.invalidFields = this.requiredElements.filter(t => !t.isValid), this.submitButton.disabled = this.invalidFields.length) } handleKeydown(t) { "Enter" === t.key && t.target.tagName.includes("SM-INPUT") && (this.invalidFields.length ? this.requiredElements.forEach(t => { t.isValid || t.vibrate() }) : (this.submitButton && this.submitButton.click(), this.dispatchEvent(new CustomEvent("submit", { bubbles: !0, composed: !0 })))) } reset() { this.formElements.forEach(t => t.reset()) } elementsChanged() { this.formElements = [...this.querySelectorAll("sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio")], this.requiredElements = this.formElements.filter(t => t.hasAttribute("required")), this.submitButton = this.querySelector('[variant="primary"], [type="submit"]'), this.resetButton = this.querySelector('[type="reset"]'), this.resetButton && this.resetButton.addEventListener("click", this.reset), this._checkValidity() } connectedCallback() { this.shadowRoot.querySelector("slot").addEventListener("slotchange", this.elementsChanged), this.addEventListener("input", this.debounce(this._checkValidity, 100)), this.addEventListener("keydown", this.debounce(this.handleKeydown, 100)), this.mutationObserver = new MutationObserver(t => { t.forEach(t => { "childList" === t.type && this.elementsChanged() }) }), this.mutationObserver.observe(this, { childList: !0, subtree: !0 }) } disconnectedCallback() { this.removeEventListener("input", this.debounce(this._checkValidity, 100)), this.removeEventListener("keydown", this.debounce(this.handleKeydown, 100)), this.mutationObserver.disconnect() } }); +const smInput = document.createElement("template"); smInput.innerHTML = '\n \n
\n \n

\n
\n ', customElements.define("sm-input", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smInput.content.cloneNode(!0)), this.inputParent = this.shadowRoot.querySelector(".input"), this.input = this.shadowRoot.querySelector("input"), this.clearBtn = this.shadowRoot.querySelector(".clear"), this.label = this.shadowRoot.querySelector(".label"), this.feedbackText = this.shadowRoot.querySelector(".feedback-text"), this.outerContainer = this.shadowRoot.querySelector(".outer-container"), this._helperText = "", this._errorText = "", this.isRequired = !1, this.validationFunction = void 0, this.reflectedAttributes = ["value", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step"], this.reset = this.reset.bind(this), this.clear = this.clear.bind(this), this.focusIn = this.focusIn.bind(this), this.focusOut = this.focusOut.bind(this), this.fireEvent = this.fireEvent.bind(this), this.checkInput = this.checkInput.bind(this), this.handleKeydown = this.handleKeydown.bind(this), this.vibrate = this.vibrate.bind(this) } static get observedAttributes() { return ["value", "placeholder", "required", "disabled", "type", "inputmode", "readonly", "min", "max", "pattern", "minlength", "maxlength", "step", "helper-text", "error-text", "hiderequired"] } get value() { return this.input.value } set value(t) { t !== this.input.value && (this.input.value = t, this.checkInput()) } get placeholder() { return this.getAttribute("placeholder") } set placeholder(t) { this.setAttribute("placeholder", t) } get type() { return this.getAttribute("type") } set type(t) { this.setAttribute("type", t) } get validity() { return this.input.validity } get disabled() { return this.hasAttribute("disabled") } set disabled(t) { t ? this.inputParent.classList.add("disabled") : this.inputParent.classList.remove("disabled") } get readOnly() { return this.hasAttribute("readonly") } set readOnly(t) { t ? this.setAttribute("readonly", "") : this.removeAttribute("readonly") } set customValidation(t) { this.validationFunction = t } set errorText(t) { this._errorText = t } set helperText(t) { this._helperText = t } get isValid() { if ("" !== this.input.value) { const t = this.input.checkValidity(); let e = !0; return this.validationFunction && (e = Boolean(this.validationFunction(this.input.value))), t && e ? (this.feedbackText.classList.remove("error"), this.feedbackText.classList.add("success"), this.feedbackText.textContent = "") : this._errorText && (this.feedbackText.classList.add("error"), this.feedbackText.classList.remove("success"), this.feedbackText.innerHTML = `\n \n ${this._errorText}\n `), t && e } } reset() { this.value = "" } clear() { this.value = "", this.input.focus() } focusIn() { this.input.focus() } focusOut() { this.input.blur() } fireEvent() { let t = new Event("input", { bubbles: !0, cancelable: !0, composed: !0 }); this.dispatchEvent(t) } checkInput(t) { this.hasAttribute("readonly") || ("" !== this.input.value.trim() ? this.clearBtn.classList.remove("hide") : this.clearBtn.classList.add("hide")), this.hasAttribute("placeholder") && "" !== this.getAttribute("placeholder").trim() && ("" !== this.input.value ? this.animate ? this.inputParent.classList.add("animate-placeholder") : this.label.classList.add("hide") : (this.animate ? this.inputParent.classList.remove("animate-placeholder") : this.label.classList.remove("hide"), this.feedbackText.textContent = "")) } handleKeydown(t) { 1 === t.key.length && (["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."].includes(t.key) ? "." === t.key && t.target.value.includes(".") && t.preventDefault() : t.preventDefault()) } vibrate() { this.outerContainer.animate([{ transform: "translateX(-1rem)" }, { transform: "translateX(1rem)" }, { transform: "translateX(-0.5rem)" }, { transform: "translateX(0.5rem)" }, { transform: "translateX(0)" }], { duration: 300, easing: "ease" }) } connectedCallback() { this.animate = this.hasAttribute("animate"), this.setAttribute("role", "textbox"), this.input.addEventListener("input", this.checkInput), this.clearBtn.addEventListener("click", this.clear) } attributeChangedCallback(t, e, n) { e !== n && (this.reflectedAttributes.includes(t) && (this.hasAttribute(t) ? this.input.setAttribute(t, this.getAttribute(t) ? this.getAttribute(t) : "") : this.input.removeAttribute(t)), "placeholder" === t ? (this.label.textContent = n, this.setAttribute("aria-label", n)) : this.hasAttribute("value") ? this.checkInput() : "type" === t ? this.hasAttribute("type") && "number" === this.getAttribute("type") ? (this.input.setAttribute("inputmode", "decimal"), this.input.addEventListener("keydown", this.handleKeydown)) : this.input.removeEventListener("keydown", this.handleKeydown) : "helper-text" === t ? this._helperText = this.getAttribute("helper-text") : "error-text" === t ? this._errorText = this.getAttribute("error-text") : "required" === t ? (this.isRequired = this.hasAttribute("required"), this.isRequired ? this.setAttribute("aria-required", "true") : this.setAttribute("aria-required", "false")) : "readonly" === t ? this.hasAttribute("readonly") ? this.inputParent.classList.add("readonly") : this.inputParent.classList.remove("readonly") : "disabled" === t && (this.hasAttribute("disabled") ? this.inputParent.classList.add("disabled") : this.inputParent.classList.remove("disabled"))) } disconnectedCallback() { this.input.removeEventListener("input", this.checkInput), this.clearBtn.removeEventListener("click", this.clear), this.input.removeEventListener("keydown", this.handleKeydown) } }); +const smNotifications = document.createElement("template"); smNotifications.innerHTML = '\n \n
\n ', customElements.define("sm-notifications", class extends HTMLElement { constructor() { super(), this.shadow = this.attachShadow({ mode: "open" }).append(smNotifications.content.cloneNode(!0)), this.notificationPanel = this.shadowRoot.querySelector(".notification-panel"), this.animationOptions = { duration: 300, fill: "forwards", easing: "cubic-bezier(0.175, 0.885, 0.32, 1.275)" }, this.push = this.push.bind(this), this.createNotification = this.createNotification.bind(this), this.removeNotification = this.removeNotification.bind(this), this.clearAll = this.clearAll.bind(this), this.handlePointerMove = this.handlePointerMove.bind(this), this.startX = 0, this.currentX = 0, this.endX = 0, this.swipeDistance = 0, this.swipeDirection = "", this.swipeThreshold = 0, this.startTime = 0, this.swipeTime = 0, this.swipeTimeThreshold = 200, this.currentTarget = null, this.mediaQuery = window.matchMedia("(min-width: 640px)"), this.handleOrientationChange = this.handleOrientationChange.bind(this), this.isLandscape = !1 } randString(n) { let t = ""; const i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (let e = 0; e < n; e++)t += i.charAt(Math.floor(Math.random() * i.length)); return t } createNotification(n, t = {}) { const { pinned: i = !1, icon: e = "", action: o } = t, a = document.createElement("div"); a.id = this.randString(8), a.classList.add("notification"); let r = ""; return r += `\n
${e}
\n ${n}\n `, o && (r += `\n \n `), i && (a.classList.add("pinned"), r += '\n \n '), a.innerHTML = r, a } push(n, t = {}) { const i = this.createNotification(n, t); return this.isLandscape ? this.notificationPanel.append(i) : this.notificationPanel.prepend(i), this.notificationPanel.animate([{ transform: `translateY(${this.isLandscape ? "" : "-"}${i.clientHeight}px)` }, { transform: "none" }], this.animationOptions), i.animate([{ transform: "translateY(-1rem)", opacity: "0" }, { transform: "none", opacity: "1" }], this.animationOptions).onfinish = (n => { n.target.commitStyles(), n.target.cancel() }), i.querySelector(".action") && i.querySelector(".action").addEventListener("click", t.action.callback), i.id } removeNotification(n, t = "left") { if (!n) return; const i = "left" === t ? "-" : "+"; n.animate([{ transform: this.currentX ? `translateX(${this.currentX}px)` : "none", opacity: "1" }, { transform: `translateX(calc(${i}${Math.abs(this.currentX)}px ${i} 1rem))`, opacity: "0" }], this.animationOptions).onfinish = (() => { n.remove() }) } clearAll() { Array.from(this.notificationPanel.children).forEach(n => { this.removeNotification(n) }) } handlePointerMove(n) { this.currentX = n.clientX - this.startX, this.currentTarget.style.transform = `translateX(${this.currentX}px)` } handleOrientationChange(n) { this.isLandscape = n.matches, n.matches } connectedCallback() { this.handleOrientationChange(this.mediaQuery), this.mediaQuery.addEventListener("change", this.handleOrientationChange), this.notificationPanel.addEventListener("pointerdown", n => { n.target.closest(".close") ? this.removeNotification(n.target.closest(".notification")) : n.target.closest(".notification") && (this.swipeThreshold = n.target.closest(".notification").getBoundingClientRect().width / 2, this.currentTarget = n.target.closest(".notification"), this.currentTarget.setPointerCapture(n.pointerId), this.startTime = Date.now(), this.startX = n.clientX, this.startY = n.clientY, this.notificationPanel.addEventListener("pointermove", this.handlePointerMove)) }), this.notificationPanel.addEventListener("pointerup", n => { this.endX = n.clientX, this.endY = n.clientY, this.swipeDistance = Math.abs(this.endX - this.startX), this.swipeTime = Date.now() - this.startTime, this.endX > this.startX ? this.swipeDirection = "right" : this.swipeDirection = "left", this.swipeTime < this.swipeTimeThreshold ? this.swipeDistance > 50 && this.removeNotification(this.currentTarget, this.swipeDirection) : this.swipeDistance > this.swipeThreshold ? this.removeNotification(this.currentTarget, this.swipeDirection) : this.currentTarget.animate([{ transform: `translateX(${this.currentX}px)` }, { transform: "none" }], this.animationOptions).onfinish = (n => { n.target.commitStyles(), n.target.cancel() }), this.notificationPanel.removeEventListener("pointermove", this.handlePointerMove), this.notificationPanel.releasePointerCapture(n.pointerId), this.currentX = 0 }); const n = new MutationObserver(n => { n.forEach(n => { "childList" === n.type && n.addedNodes.length && !n.addedNodes[0].classList.contains("pinned") && setTimeout(() => { this.removeNotification(n.addedNodes[0]) }, 5e3) }) }); n.observe(this.notificationPanel, { childList: !0 }) } disconnectedCallback() { mediaQueryList.removeEventListener("change", handleOrientationChange) } }); +class Stack { constructor() { this.items = [] } push(t) { this.items.push(t) } pop() { return 0 == this.items.length ? "Underflow" : this.items.pop() } peek() { return this.items[this.items.length - 1] } } const popupStack = new Stack, smPopup = document.createElement("template"); smPopup.innerHTML = '\n\n\n', customElements.define("sm-popup", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smPopup.content.cloneNode(!0)), this.allowClosing = !1, this.isOpen = !1, this.pinned = !1, this.offset = 0, this.touchStartY = 0, this.touchEndY = 0, this.touchStartTime = 0, this.touchEndTime = 0, this.touchEndAnimation = void 0, this.focusable, this.autoFocus, this.mutationObserver, this.popupContainer = this.shadowRoot.querySelector(".popup-container"), this.backdrop = this.shadowRoot.querySelector(".background"), this.dialogBox = this.shadowRoot.querySelector(".popup"), this.popupBodySlot = this.shadowRoot.querySelector(".popup-body slot"), this.popupHeader = this.shadowRoot.querySelector(".popup-top"), this.resumeScrolling = this.resumeScrolling.bind(this), this.setStateOpen = this.setStateOpen.bind(this), this.show = this.show.bind(this), this.hide = this.hide.bind(this), this.handleTouchStart = this.handleTouchStart.bind(this), this.handleTouchMove = this.handleTouchMove.bind(this), this.handleTouchEnd = this.handleTouchEnd.bind(this), this.detectFocus = this.detectFocus.bind(this) } static get observedAttributes() { return ["open"] } get open() { return this.isOpen } animateTo(t, e, n) { const i = t.animate(e, { ...n, fill: "both" }); return i.finished.then(() => { i.commitStyles(), i.cancel() }), i } resumeScrolling() { const t = document.body.style.top; window.scrollTo(0, -1 * parseInt(t || "0")), document.body.style.overflow = "", document.body.style.top = "initial" } setStateOpen() { if (!this.isOpen || this.offset) { const t = { duration: 300, easing: "ease" }, e = window.innerWidth > 640 ? "scale(1.1)" : `translateY(${this.offset ? `${this.offset}px` : "100%"})`; this.animateTo(this.dialogBox, [{ opacity: this.offset ? 1 : 0, transform: e }, { opacity: 1, transform: "none" }], t) } } show(t = {}) { const { pinned: e = !1 } = t; if (!this.isOpen) { const t = { duration: 300, easing: "ease" }; popupStack.push({ popup: this, permission: e }), popupStack.items.length > 1 && this.animateTo(popupStack.items[popupStack.items.length - 2].popup.shadowRoot.querySelector(".popup"), [{ transform: "none" }, { transform: window.innerWidth > 640 ? "scale(0.95)" : "translateY(-1.5rem)" }], t), this.popupContainer.classList.remove("hide"), this.offset || this.backdrop.animate([{ opacity: 0 }, { opacity: 1 }], t), this.setStateOpen(), this.dispatchEvent(new CustomEvent("popupopened", { bubbles: !0, detail: { popup: this } })), this.pinned = e, this.isOpen = !0, document.body.style.overflow = "hidden", document.body.style.top = `-${window.scrollY}px`; const n = this.autoFocus || this.focusable[0]; n.tagName.includes("SM-") ? n.focusIn() : n.focus(), this.hasAttribute("open") || this.setAttribute("open", "") } } hide() { const t = { duration: 150, easing: "ease" }; this.backdrop.animate([{ opacity: 1 }, { opacity: 0 }], t), this.animateTo(this.dialogBox, [{ opacity: 1, transform: window.innerWidth > 640 ? "none" : `translateY(${this.offset ? `${this.offset}px` : "0"})` }, { opacity: 0, transform: window.innerWidth > 640 ? "scale(1.1)" : "translateY(100%)" }], t).finished.finally(() => { this.popupContainer.classList.add("hide"), this.dialogBox.style = "", this.removeAttribute("open"), this.forms.length && this.forms.forEach(t => t.reset()), this.dispatchEvent(new CustomEvent("popupclosed", { bubbles: !0, detail: { popup: this } })), this.isOpen = !1 }), popupStack.pop(), popupStack.items.length ? this.animateTo(popupStack.items[popupStack.items.length - 1].popup.shadowRoot.querySelector(".popup"), [{ transform: window.innerWidth > 640 ? "scale(0.95)" : "translateY(-1.5rem)" }, { transform: "none" }], t) : this.resumeScrolling() } handleTouchStart(t) { this.offset = 0, this.popupHeader.addEventListener("touchmove", this.handleTouchMove, { passive: !0 }), this.popupHeader.addEventListener("touchend", this.handleTouchEnd, { passive: !0 }), this.touchStartY = t.changedTouches[0].clientY, this.touchStartTime = t.timeStamp } handleTouchMove(t) { this.touchStartY < t.changedTouches[0].clientY && (this.offset = t.changedTouches[0].clientY - this.touchStartY, this.touchEndAnimation = window.requestAnimationFrame(() => { this.dialogBox.style.transform = `translateY(${this.offset}px)` })) } handleTouchEnd(t) { if (this.touchEndTime = t.timeStamp, cancelAnimationFrame(this.touchEndAnimation), this.touchEndY = t.changedTouches[0].clientY, this.threshold = .3 * this.dialogBox.getBoundingClientRect().height, this.touchEndTime - this.touchStartTime > 200) if (this.touchEndY - this.touchStartY > this.threshold) { if (this.pinned) return void this.setStateOpen(); this.hide() } else this.setStateOpen(); else if (this.touchEndY > this.touchStartY) { if (this.pinned) return void this.setStateOpen(); this.hide() } this.popupHeader.removeEventListener("touchmove", this.handleTouchMove, { passive: !0 }), this.popupHeader.removeEventListener("touchend", this.handleTouchEnd, { passive: !0 }) } detectFocus(t) { if ("Tab" === t.key) { const e = this.focusable[this.focusable.length - 1], n = this.focusable[0]; t.shiftKey && document.activeElement === n ? (t.preventDefault(), e.tagName.includes("SM-") ? e.focusIn() : e.focus()) : t.shiftKey || document.activeElement !== e || (t.preventDefault(), n.tagName.includes("SM-") ? n.focusIn() : n.focus()) } } updateFocusableList() { this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input:not([readonly]), sm-select, select, sm-checkbox, sm-textarea, textarea, [tabindex]:not([tabindex="-1"])'), this.autoFocus = this.querySelector("[autofocus]") } connectedCallback() { this.popupBodySlot.addEventListener("slotchange", () => { this.forms = this.querySelectorAll("sm-form"), this.updateFocusableList() }), this.popupContainer.addEventListener("mousedown", t => { t.target !== this.popupContainer || this.pinned || (this.pinned ? this.setStateOpen() : this.hide()) }); const t = new ResizeObserver(t => { for (let e of t) if (e.contentBoxSize) { const t = Array.isArray(e.contentBoxSize) ? e.contentBoxSize[0] : e.contentBoxSize; this.threshold = .3 * t.blockSize.height } else this.threshold = .3 * e.contentRect.height }); t.observe(this), this.mutationObserver = new MutationObserver(t => { this.updateFocusableList() }), this.mutationObserver.observe(this, { attributes: !0, childList: !0, subtree: !0 }), this.addEventListener("keydown", this.detectFocus), this.popupHeader.addEventListener("touchstart", this.handleTouchStart, { passive: !0 }) } disconnectedCallback() { this.removeEventListener("keydown", this.detectFocus), resizeObserver.unobserve(), this.mutationObserver.disconnect(), this.popupHeader.removeEventListener("touchstart", this.handleTouchStart, { passive: !0 }) } attributeChangedCallback(t) { "open" === t && this.hasAttribute("open") && this.show() } }); +const smSwitch = document.createElement("template"); smSwitch.innerHTML = '\t\n\n', customElements.define("sm-switch", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smSwitch.content.cloneNode(!0)), this.switch = this.shadowRoot.querySelector(".switch"), this.input = this.shadowRoot.querySelector("input"), this.isChecked = !1, this.isDisabled = !1, this.dispatch = this.dispatch.bind(this) } static get observedAttributes() { return ["disabled", "checked"] } get disabled() { return this.isDisabled } set disabled(n) { n ? this.setAttribute("disabled", "") : this.removeAttribute("disabled") } get checked() { return this.isChecked } set checked(n) { n ? this.setAttribute("checked", "") : this.removeAttribute("checked") } get value() { return this.isChecked } reset() { } dispatch() { this.dispatchEvent(new CustomEvent("change", { bubbles: !0, composed: !0, detail: { value: this.isChecked } })) } connectedCallback() { this.addEventListener("keydown", n => { " " !== n.key || this.isDisabled || (n.preventDefault(), this.input.click()) }), this.input.addEventListener("click", n => { this.input.checked ? this.checked = !0 : this.checked = !1, this.dispatch() }) } attributeChangedCallback(n, e, t) { e !== t && ("disabled" === n ? this.hasAttribute("disabled") ? this.disabled = !0 : this.disabled = !1 : "checked" === n && (this.hasAttribute("checked") ? (this.isChecked = !0, this.input.checked = !0) : (this.isChecked = !1, this.input.checked = !1))) } }); +const smSelect = document.createElement("template"); smSelect.innerHTML = '\n\n
\n
\n
\n \n
\n
\n \n
\n
', customElements.define("sm-select", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smSelect.content.cloneNode(!0)), this.focusIn = this.focusIn.bind(this), this.reset = this.reset.bind(this), this.open = this.open.bind(this), this.collapse = this.collapse.bind(this), this.toggle = this.toggle.bind(this), this.handleOptionsNavigation = this.handleOptionsNavigation.bind(this), this.handleOptionSelection = this.handleOptionSelection.bind(this), this.handleKeydown = this.handleKeydown.bind(this), this.handleClickOutside = this.handleClickOutside.bind(this), this.selectOption = this.selectOption.bind(this), this.debounce = this.debounce.bind(this), this.availableOptions = [], this.previousOption, this.isOpen = !1, this.label = "", this.slideDown = [{ transform: "translateY(-0.5rem)", opacity: 0 }, { transform: "translateY(0)", opacity: 1 }], this.slideUp = [{ transform: "translateY(0)", opacity: 1 }, { transform: "translateY(-0.5rem)", opacity: 0 }], this.animationOptions = { duration: 300, fill: "forwards", easing: "ease" }, this.optionList = this.shadowRoot.querySelector(".options"), this.selection = this.shadowRoot.querySelector(".selection"), this.selectedOptionText = this.shadowRoot.querySelector(".selected-option-text") } static get observedAttributes() { return ["disabled", "label"] } get value() { return this.getAttribute("value") } set value(t) { const e = this.shadowRoot.querySelector("slot").assignedElements().find(e => e.getAttribute("value") === t); e ? (this.setAttribute("value", t), this.selectOption(e)) : console.warn(`There is no option with ${t} as value`) } debounce(t, e) { let n = null; return (...i) => { window.clearTimeout(n), n = window.setTimeout(() => { t.apply(null, i) }, e) } } reset(t = !0) { if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) { const e = this.availableOptions.find(t => t.hasAttribute("selected")) || this.availableOptions[0]; this.value = e.getAttribute("value"), t && this.fireEvent() } } selectOption(t) { this.previousOption !== t && (this.querySelectorAll("[selected]").forEach(t => t.removeAttribute("selected")), this.selectedOptionText.textContent = `${this.label}${t.textContent}`, t.setAttribute("selected", ""), this.previousOption = t) } focusIn() { this.selection.focus() } open() { this.availableOptions.forEach(t => t.setAttribute("tabindex", 0)), this.optionList.classList.remove("hide"), this.optionList.animate(this.slideDown, this.animationOptions), this.setAttribute("open", ""), (this.availableOptions.find(t => t.hasAttribute("selected")) || this.availableOptions[0]).focus(), this.isOpen = !0 } collapse() { this.removeAttribute("open"), this.optionList.animate(this.slideUp, this.animationOptions).onfinish = (() => { this.availableOptions.forEach(t => t.removeAttribute("tabindex")), this.optionList.classList.add("hide"), this.isOpen = !1 }) } toggle() { this.isOpen || this.hasAttribute("disabled") ? this.collapse() : this.open() } fireEvent() { this.dispatchEvent(new CustomEvent("change", { bubbles: !0, composed: !0, detail: { value: this.value } })) } handleOptionsNavigation(t) { "ArrowUp" === t.key ? (t.preventDefault(), document.activeElement.previousElementSibling ? document.activeElement.previousElementSibling.focus() : this.availableOptions[this.availableOptions.length - 1].focus()) : "ArrowDown" === t.key && (t.preventDefault(), document.activeElement.nextElementSibling ? document.activeElement.nextElementSibling.focus() : this.availableOptions[0].focus()) } handleOptionSelection(t) { this.previousOption !== document.activeElement && (this.value = document.activeElement.getAttribute("value"), this.fireEvent()) } handleClick(t) { t.target === this ? this.toggle() : (this.handleOptionSelection(), this.collapse()) } handleKeydown(t) { t.target === this ? this.isOpen && "ArrowDown" === t.key ? (t.preventDefault(), (this.availableOptions.find(t => t.hasAttribute("selected")) || this.availableOptions[0]).focus(), this.handleOptionSelection(t)) : " " === t.key && (t.preventDefault(), this.toggle()) : (this.handleOptionsNavigation(t), this.handleOptionSelection(t), ["Enter", " ", "Escape", "Tab"].includes(t.key) && (t.preventDefault(), this.collapse(), this.focusIn())) } handleClickOutside(t) { this.isOpen && !this.contains(t.target) && this.collapse() } connectedCallback() { this.setAttribute("role", "listbox"), this.hasAttribute("disabled") || this.selection.setAttribute("tabindex", "0"); let t = this.shadowRoot.querySelector("slot"); t.addEventListener("slotchange", this.debounce(e => { this.availableOptions = t.assignedElements(), this.reset(!1) }, 100)), new IntersectionObserver((t, e) => { t.forEach(t => { if (t.isIntersecting) { const t = this.selection.getBoundingClientRect().left; t < window.innerWidth / 2 ? this.setAttribute("align-select", "left") : this.setAttribute("align-select", "right") } }) }).observe(this), this.addEventListener("click", this.handleClick), this.addEventListener("keydown", this.handleKeydown), document.addEventListener("mousedown", this.handleClickOutside) } disconnectedCallback() { this.removeEventListener("click", this.handleClick), this.removeEventListener("click", this.toggle), this.removeEventListener("keydown", this.handleKeydown), document.removeEventListener("mousedown", this.handleClickOutside) } attributeChangedCallback(t) { "disabled" === t ? this.hasAttribute("disabled") ? this.selection.removeAttribute("tabindex") : this.selection.setAttribute("tabindex", "0") : "label" === t && (this.label = this.hasAttribute("label") ? `${this.getAttribute("label")} ` : "") } }); const smOption = document.createElement("template"); smOption.innerHTML = "\n\n
\n \n
", customElements.define("sm-option", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smOption.content.cloneNode(!0)) } connectedCallback() { this.setAttribute("role", "option") } }); +const spinner = document.createElement("template"); spinner.innerHTML = '\n\n\n\n'; class SpinnerLoader extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(spinner.content.cloneNode(!0)) } } window.customElements.define("sm-spinner", SpinnerLoader); +const stripSelect = document.createElement("template"); stripSelect.innerHTML = '\n\n
\n
\n \n
\n \n
\n \n
\n
\n\n', customElements.define("strip-select", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(stripSelect.content.cloneNode(!0)), this.stripSelect = this.shadowRoot.querySelector(".strip-select"), this.slottedOptions = void 0, this._value = void 0, this.scrollDistance = 0, this.assignedElements = [], this.scrollLeft = this.scrollLeft.bind(this), this.scrollRight = this.scrollRight.bind(this), this.fireEvent = this.fireEvent.bind(this), this.setSelectedOption = this.setSelectedOption.bind(this) } get value() { return this._value } set value(t) { this.setSelectedOption(t) } scrollLeft() { this.stripSelect.scrollBy({ left: -this.scrollDistance, behavior: "smooth" }) } scrollRight() { this.stripSelect.scrollBy({ left: this.scrollDistance, behavior: "smooth" }) } setSelectedOption(t) { this._value !== t && (this._value = t, this.assignedElements.forEach(e => { e.value === t ? (e.setAttribute("active", ""), e.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" })) : e.removeAttribute("active") })) } fireEvent() { this.dispatchEvent(new CustomEvent("change", { bubbles: !0, composed: !0, detail: { value: this._value } })) } connectedCallback() { this.setAttribute("role", "listbox"); const t = this.shadowRoot.querySelector("slot"), e = this.shadowRoot.querySelector(".cover--left"), n = this.shadowRoot.querySelector(".cover--right"), i = this.shadowRoot.querySelector(".nav-button--left"), s = this.shadowRoot.querySelector(".nav-button--right"); t.addEventListener("slotchange", o => { this.assignedElements = t.assignedElements(), this.assignedElements.forEach(t => { t.hasAttribute("selected") && (t.setAttribute("active", ""), this._value = t.value) }), this.hasAttribute("multiline") || (this.assignedElements.length > 0 ? (r.observe(this.assignedElements[0]), a.observe(this.assignedElements[this.assignedElements.length - 1])) : (i.classList.add("hide"), s.classList.add("hide"), e.classList.add("hide"), n.classList.add("hide"), r.disconnect(), a.disconnect())) }); const o = new ResizeObserver(t => { t.forEach(t => { if (t.contentBoxSize) { const e = Array.isArray(t.contentBoxSize) ? t.contentBoxSize[0] : t.contentBoxSize; this.scrollDistance = .6 * e.inlineSize } else this.scrollDistance = .6 * t.contentRect.width }) }); o.observe(this), this.stripSelect.addEventListener("option-clicked", t => { this._value !== t.target.value && (this.setSelectedOption(t.target.value), this.fireEvent()) }); const r = new IntersectionObserver(t => { t.forEach(t => { t.isIntersecting ? (i.classList.add("hide"), e.classList.add("hide")) : (i.classList.remove("hide"), e.classList.remove("hide")) }) }, { threshold: .9, root: this }), a = new IntersectionObserver(t => { t.forEach(t => { t.isIntersecting ? (s.classList.add("hide"), n.classList.add("hide")) : (s.classList.remove("hide"), n.classList.remove("hide")) }) }, { threshold: .9, root: this }); i.addEventListener("click", this.scrollLeft), s.addEventListener("click", this.scrollRight) } disconnectedCallback() { navButtonLeft.removeEventListener("click", this.scrollLeft), navButtonRight.removeEventListener("click", this.scrollRight) } }); const stripOption = document.createElement("template"); stripOption.innerHTML = '\n\n\n', customElements.define("strip-option", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(stripOption.content.cloneNode(!0)), this._value = void 0, this.radioButton = this.shadowRoot.querySelector("input"), this.fireEvent = this.fireEvent.bind(this), this.handleKeyDown = this.handleKeyDown.bind(this) } get value() { return this._value } fireEvent() { this.dispatchEvent(new CustomEvent("option-clicked", { bubbles: !0, composed: !0, detail: { value: this._value } })) } handleKeyDown(t) { "Enter" !== t.key && "Space" !== t.key || this.fireEvent() } connectedCallback() { this.setAttribute("role", "option"), this.setAttribute("tabindex", "0"), this._value = this.getAttribute("value"), this.addEventListener("click", this.fireEvent), this.addEventListener("keydown", this.handleKeyDown) } disconnectedCallback() { this.removeEventListener("click", this.fireEvent), this.removeEventListener("keydown", this.handleKeyDown) } }); +const smTextarea = document.createElement("template"); smTextarea.innerHTML = '\n \n \n ', customElements.define("sm-textarea", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smTextarea.content.cloneNode(!0)), this.textarea = this.shadowRoot.querySelector("textarea"), this.textareaBox = this.shadowRoot.querySelector(".textarea"), this.placeholder = this.shadowRoot.querySelector(".placeholder"), this.reflectedAttributes = ["disabled", "required", "readonly", "rows", "minlength", "maxlength"], this.reset = this.reset.bind(this), this.focusIn = this.focusIn.bind(this), this.fireEvent = this.fireEvent.bind(this), this.checkInput = this.checkInput.bind(this) } static get observedAttributes() { return ["disabled", "value", "placeholder", "required", "readonly", "rows", "minlength", "maxlength"] } get value() { return this.textarea.value } set value(e) { this.setAttribute("value", e), this.fireEvent() } get disabled() { return this.hasAttribute("disabled") } set disabled(e) { e ? this.setAttribute("disabled", "") : this.removeAttribute("disabled") } get isValid() { return this.textarea.checkValidity() } reset() { this.setAttribute("value", "") } focusIn() { this.textarea.focus() } fireEvent() { let e = new Event("input", { bubbles: !0, cancelable: !0, composed: !0 }); this.dispatchEvent(e) } checkInput() { this.hasAttribute("placeholder") && "" !== this.getAttribute("placeholder") && ("" !== this.textarea.value ? this.placeholder.classList.add("hide") : this.placeholder.classList.remove("hide")) } connectedCallback() { this.textarea.addEventListener("input", e => { this.textareaBox.dataset.value = this.textarea.value, this.checkInput() }) } attributeChangedCallback(e, t, n) { this.reflectedAttributes.includes(e) ? this.hasAttribute(e) ? this.textarea.setAttribute(e, this.getAttribute(e) ? this.getAttribute(e) : "") : this.textContent.removeAttribute(e) : "placeholder" === e ? this.placeholder.textContent = this.getAttribute("placeholder") : "value" === e && (this.textarea.value = n, this.textareaBox.dataset.value = n, this.checkInput()) } }); +const themeToggle = document.createElement("template"); themeToggle.innerHTML = '\n \n \n'; class ThemeToggle extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(themeToggle.content.cloneNode(!0)), this.isChecked = !1, this.hasTheme = "light", this.toggleState = this.toggleState.bind(this), this.fireEvent = this.fireEvent.bind(this), this.handleThemeChange = this.handleThemeChange.bind(this) } static get observedAttributes() { return ["checked"] } daylight() { this.hasTheme = "light", document.body.dataset.theme = "light", this.setAttribute("aria-checked", "false") } nightlight() { this.hasTheme = "dark", document.body.dataset.theme = "dark", this.setAttribute("aria-checked", "true") } toggleState() { this.toggleAttribute("checked"), this.fireEvent() } handleKeyDown(e) { " " === e.key && this.toggleState() } handleThemeChange(e) { e.detail.theme !== this.hasTheme && ("dark" === e.detail.theme ? this.setAttribute("checked", "") : this.removeAttribute("checked")) } fireEvent() { this.dispatchEvent(new CustomEvent("themechange", { bubbles: !0, composed: !0, detail: { theme: this.hasTheme } })) } connectedCallback() { this.setAttribute("role", "switch"), this.setAttribute("aria-label", "theme toggle"), "dark" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.nightlight(), this.setAttribute("checked", "")) : "light" === localStorage.getItem(`${window.location.hostname}-theme`) ? (this.daylight(), this.removeAttribute("checked")) : window.matchMedia("(prefers-color-scheme: dark)").matches ? (this.nightlight(), this.setAttribute("checked", "")) : (this.daylight(), this.removeAttribute("checked")), this.addEventListener("click", this.toggleState), this.addEventListener("keydown", this.handleKeyDown), document.addEventListener("themechange", this.handleThemeChange) } disconnectedCallback() { this.removeEventListener("click", this.toggleState), this.removeEventListener("keydown", this.handleKeyDown), document.removeEventListener("themechange", this.handleThemeChange) } attributeChangedCallback(e, t, n) { "checked" === e && (this.hasAttribute("checked") ? (this.nightlight(), localStorage.setItem(`${window.location.hostname}-theme`, "dark")) : (this.daylight(), localStorage.setItem(`${window.location.hostname}-theme`, "light"))) } } window.customElements.define("theme-toggle", ThemeToggle); const smCopy = document.createElement("template"); smCopy.innerHTML = '\n\n
\n

\n \n
\n', customElements.define("sm-copy", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smCopy.content.cloneNode(!0)), this.copyContent = this.shadowRoot.querySelector(".copy-content"), this.copyButton = this.shadowRoot.querySelector(".copy-button"), this.copy = this.copy.bind(this) } static get observedAttributes() { return ["value"] } set value(n) { this.setAttribute("value", n) } get value() { return this.getAttribute("value") } fireEvent() { this.dispatchEvent(new CustomEvent("copy", { composed: !0, bubbles: !0, cancelable: !0 })) } copy() { navigator.clipboard.writeText(this.copyContent.textContent).then(n => this.fireEvent()).catch(n => console.error(n)) } connectedCallback() { this.copyButton.addEventListener("click", this.copy) } attributeChangedCallback(n, t, o) { "value" === n && (this.copyContent.textContent = o) } disconnectedCallback() { this.copyButton.removeEventListener("click", this.copy) } }); \ No newline at end of file diff --git a/css/main.css b/css/main.css index 7bba142..62152cc 100644 --- a/css/main.css +++ b/css/main.css @@ -1,274 +1,681 @@ @charset "UTF-8"; * { - box-sizing: border-box; padding: 0; margin: 0; + box-sizing: border-box; font-family: "Roboto", sans-serif; } +:root { + font-size: clamp(1rem, 1.2vmax, 1.2rem); +} + +html, body { - --accent-color:#169685; - --text-color: 17, 17, 17; - --text-color-light: 85, 85, 85; - --foreground-color: 255, 255, 255; - --background-color: rgba(var(--foreground-color), 1); - --dark-shade: #f8f8f8; - --error-color: #E53935; - --hue: 172; - --saturation: 74%; - --lightness: 34%; + height: 100%; +} + +body { + --accent-color: #3d5afe; + --secondary-color: #ffac2e; + --text-color: 20, 20, 20; + --foreground-color: 252, 253, 255; + --background-color: 241, 243, 248; + --danger-color: rgb(255, 75, 75); + --green: #1cad59; + --yellow: rgb(220, 165, 0); color: rgba(var(--text-color), 1); - font-size: 16px; - background: var(--dark-shade); - background-size: cover; + background-color: rgba(var(--background-color), 1); + overflow-y: hidden; } body[data-theme=dark] { - --accent-color: #00e2c4; - --text-color: 238, 238, 238; - --text-color-light: 170, 170, 170; - --foreground-color: 26, 26, 26; - --background-color: #111; - --dark-shade: #080808; - --hue: 172; - --saturation: 70%; - --lightness: 44%; + --accent-color: #6d83ff; + --secondary-color: #d60739; + --text-color: 220, 220, 220; + --foreground-color: 27, 28, 29; + --background-color: 21, 22, 22; + --danger-color: rgb(255, 106, 106); + --green: #00e676; + --yellow: rgb(255, 213, 5); +} +body[data-theme=dark] ::-webkit-calendar-picker-indicator { + filter: invert(1); } -a { - font-weight: 600; - text-decoration: none; - color: var(--accent-color); -} - -.dark-text { - color: #111; -} - -h1 { - font-size: 3.5rem; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -h4 { - font-size: 1rem; -} - -h5 { - font-size: 0.8rem; -} - -h1, -h2, -h3, -h4, -h5 { - font-family: "Poppins", sans-serif; - font-weight: 600; -} - -p { - line-height: 1.5; +p, +strong { + font-size: 0.9rem; max-width: 65ch; + line-height: 1.7; color: rgba(var(--text-color), 0.9); } -strong { - font-weight: 500; +img { + -o-object-fit: cover; + object-fit: cover; } -::-moz-focus-inner { +a:where([class]) { + color: inherit; + text-decoration: none; +} +a:where([class]):focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +a { + color: var(--accent-color); +} + +a:-webkit-any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +a:-moz-any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +a.button { + padding: 0.4rem 0.6rem; + border-radius: 0.3rem; + font-size: 0.9rem; + font-weight: 500; + color: inherit; +} + +button, +.button { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + -webkit-tap-highlight-color: transparent; + align-items: center; + font-size: 0.9rem; + font-weight: 500; + white-space: nowrap; + padding: 0.8rem; + border-radius: 0.3rem; + justify-content: center; +} +button:focus-visible, +.button:focus-visible { + outline: var(--accent-color) solid medium; +} +button:not(:disabled), +.button:not(:disabled) { + cursor: pointer; +} + +.button { + background-color: rgba(var(--text-color), 0.1); +} +.button--primary, .button--danger { + color: rgba(var(--background-color), 1) !important; +} +.button--primary .icon, .button--danger .icon { + fill: rgba(var(--background-color), 1); +} +.button--primary { + text-transform: capitalize; + background-color: var(--accent-color); +} +.button--danger { + background-color: var(--danger-color); +} +.button--small { + padding: 0.4rem 0.6rem; +} +.button--outlined { + border: solid rgba(var(--text-color), 0.5) 0.1rem; + background-color: rgba(var(--foreground-color), 1); +} +.button--transparent { + background-color: transparent; +} + +.cta { + text-transform: uppercase; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.05em; + padding: 0.8rem 1rem; +} + +.icon { + width: 1.2rem; + height: 1.2rem; + fill: rgba(var(--text-color), 0.8); + flex-shrink: 0; +} + +.icon-only { + padding: 0.5rem; + border-radius: 0.3rem; + aspect-ratio: 1/1; +} + +button:disabled { + opacity: 0.5; +} + +a:-webkit-any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +a:-moz-any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +details summary { + display: flex; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: pointer; + align-items: center; + justify-content: space-between; + color: var(--accent-color); +} + +details[open] summary { + margin-bottom: 1rem; +} +details[open] > summary .down-arrow { + transform: rotate(180deg); +} + +fieldset { border: none; } -.bottom-padding { - padding-bottom: 1.5rem; +input { + accent-color: var(--accent-color); +} +input[type=range]:active { + cursor: -webkit-grab; + cursor: grab; } -.top-padding { - padding-top: 1em; +sm-copy { + font-size: 0.9rem; } -.bottom-margin { - margin-bottom: 1.5rem; +sm-input, +sm-textarea { + font-size: 0.9rem; + --border-radius: 0.5rem; + --background-color: rgba(var(--foreground-color), 1); +} +sm-input button .icon, +sm-textarea button .icon { + fill: var(--accent-color); } -.top-margin { - margin-top: 1.5rem; +sm-textarea { + --max-height: 32ch; } -.flex { - display: flex; +sm-button { + --padding: 0.8rem; +} +sm-button[variant=primary] .icon { + fill: rgba(var(--background-color), 1); +} +sm-button[disabled] .icon { + fill: rgba(var(--text-color), 0.6); +} +sm-button.danger { + --background: var(--danger-color); + color: rgba(var(--background-color), 1); } -.grid { - display: grid; +sm-spinner { + --size: 1.5rem; + --stroke-width: 0.1rem; } -.grid-2 { - grid-template-columns: auto auto; - gap: 1em; +sm-form { + --gap: 1rem; } -.align-center { - align-items: center; +sm-select { + --padding: 0.8rem; + font-size: 0.9rem; + --min-width: 8rem; } -.direction-column { - flex-direction: column; +sm-option { + font-size: 0.9rem; } -.justify-right { - margin-left: auto; +strip-select { + --gap: 0; + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.3rem; + padding: 0.3rem; } -.space-between { - justify-content: space-between; +strip-option { + position: relative; + font-size: 0.8rem; + --border-radius: 0.2rem; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; } -.label { - margin-bottom: 0.4rem; +sm-button { + --border-radius: 0.3rem; +} +sm-button[variant=primary] .icon { + fill: rgba(var(--background-color), 1); +} +sm-button[disabled] .icon { + fill: rgba(var(--text-color), 0.6); } -.light-text { - opacity: 0.7; +sm-select[open] { + z-index: 10; } -.hide { - opacity: 0; - pointer-events: none; -} - -.hide-completely { - display: none !important; -} - -.breakable { - word-break: break-all; +ul { + list-style: none; } .overflow-ellipsis { - white-space: nowrap; + width: 100%; overflow: hidden; + white-space: nowrap; text-overflow: ellipsis; } -.separator { - padding: 0.1em; +.wrap-around { + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; + -webkit-hyphens: auto; + hyphens: auto; } -.no-transformations { - transform: none !important; +.full-bleed { + grid-column: 1/-1; +} + +.uppercase { + text-transform: uppercase; } .capitalize { text-transform: capitalize; } -span.ripple { +.sticky { + position: -webkit-sticky; + position: sticky; +} + +.top-0 { + top: 0; +} + +.flex { + display: flex; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.flex-1 { + flex: 1; +} + +.grid { + display: grid; +} + +.flow-column { + grid-auto-flow: column; +} + +.gap-0-3 { + gap: 0.3rem; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} + +.text-align-left { + text-align: left; +} + +.align-items-start { + align-items: flex-start; +} + +.align-content-start { + align-content: flex-start; +} + +.align-start { + align-content: flex-start; +} + +.align-center { + align-items: center; +} + +.align-end { + align-items: flex-end; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-items: start; +} + +.justify-content-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-start { + align-self: start; +} + +.align-self-center { + align-self: center; +} + +.align-self-end { + align-self: end; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.flex-direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.h-100 { + height: 100%; +} + +.margin-right-0-3 { + margin-right: 0.3rem; +} + +.margin-right-0-5 { + margin-right: 0.5rem; +} + +.margin-left-0-5 { + margin-left: 0.5rem; +} + +.margin-left-auto { + margin-left: auto; +} + +.margin-right-auto { + margin-right: auto; +} + +.margin-bottom-0-5 { + margin-bottom: 0.5rem; +} + +.margin-bottom-1 { + margin-bottom: 1rem; +} + +.margin-bottom-2 { + margin-bottom: 2rem; +} + +.margin-block-0-5 { + margin-block: 0.5rem; +} + +.margin-block-1 { + margin-block: 1rem; +} + +.margin-block-1-5 { + margin-block: 1.5rem; +} + +.margin-inline-1 { + margin-inline: 1rem; +} + +.margin-inline-1-5 { + margin-inline: 1.5rem; +} + +.hidden { + display: none !important; +} + +.no-transformations { + transform: none !important; +} + +.full-bleed { + grid-column: 1/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} + +.w-100 { + width: 100%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { + font-weight: 400; +} + +.weight-500 { + font-weight: 500; +} + +.card { + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.5rem; + padding: max(1rem, 3vw); +} + +.ripple { + height: 8rem; + width: 8rem; position: absolute; border-radius: 50%; transform: scale(0); - animation: ripple 0.6s linear; - background: rgba(var(--text-color), 0.1); + background: radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%); + pointer-events: none; } -@keyframes ripple { - to { - transform: scale(4); - opacity: 0; - } +.interactive { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; } -.icon { + +.observe-empty-state:empty { + display: none; +} + +.observe-empty-state:not(:empty) ~ .empty-state { + display: none; +} + +.button__icon { height: 1.2rem; width: 1.2rem; - overflow: visible; - stroke: rgba(var(--text-color), 1); - opacity: 0.8; - fill: none; - stroke-width: 6; - stroke-linejoin: round; - stroke-linecap: round; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; } -sm-popup > sm-input:not(:last-of-type) { - margin-bottom: 1rem; +[data-editable] { + transition: padding 0.2s; } -sm-popup sm-textarea { - margin-top: 1rem; -} - -.popup-header { - padding: 1.5rem; - padding-bottom: 0; - display: flex; - align-items: center; - width: 100%; -} -.popup-header .icon { - margin-right: 1rem; - padding: 0.2rem; - stroke-width: 10; - cursor: pointer; -} -.popup-header sm-button, .popup-header button { - width: auto; - margin-left: auto; -} - -button { - position: relative; - display: inline-flex; - align-items: center; - justify-content: center; - text-transform: capitalize; - padding: 0.6rem 1.2rem; - font-weight: 600; - cursor: pointer; +[data-editable]:focus-within { + padding: 0.5em; border-radius: 0.3rem; - color: var(--accent-color); - transition: transform 0.3s; - border: none; - background: rgba(var(--text-color), 0.1); - -webkit-tap-highlight-color: transparent; - font-family: "Poppins", sans-serif; -} -button:focus { - outline: thin solid rgba(var(--text-color-light), 0.4); -} -button:disabled { - cursor: default; - background: rgba(var(--text-color), 0.4); + outline: none; + background-color: rgba(var(--text-color), 0.06); + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; } -.primary-btn { - background: var(--accent-color); - justify-content: center; - color: rgba(var(--foreground-color), 1); +.multi-state-button { + display: grid; + text-align: center; + align-items: center; +} +.multi-state-button > * { + grid-area: 1/1/2/2; +} +.multi-state-button button { + z-index: 1; } -#confirmation { +#confirmation_popup, +#prompt_popup { flex-direction: column; } -#confirmation h4 { +#confirmation_popup h4, +#prompt_popup h4 { font-weight: 500; - margin-bottom: 1.5rem; + margin-bottom: 0.5rem; } -#confirmation .flex { +#confirmation_popup sm-button, +#prompt_popup sm-button { + margin: 0; +} +#confirmation_popup .flex, +#prompt_popup .flex { + padding: 0; margin-top: 1rem; } -#confirmation .flex sm-button:first-of-type { - margin-right: 0.6em; +#confirmation_popup .flex sm-button:first-of-type, +#prompt_popup .flex sm-button:first-of-type { + margin-right: 0.6rem; margin-left: auto; } +.popup__header { + display: grid; + gap: 0.5rem; + width: 100%; + padding: 0 1.5rem 0 0.5rem; + align-items: center; + grid-template-columns: auto 1fr auto; +} + +.popup__header__close { + padding: 0.5rem; + cursor: pointer; +} + #sign_in_page { background: url(sign-in-bg.svg) no-repeat center, linear-gradient(rgba(var(--text-color), 0.04), rgba(var(--text-color), 0.04)), linear-gradient(rgba(var(--foreground-color), 1), rgba(var(--foreground-color), 1)); background-size: cover; @@ -283,7 +690,6 @@ button:disabled { } #sign_in_page .info h4 { font-weight: 500; - font-family: "Roboto", sans-serif; opacity: 0.8; } #sign_in_page .sign-in-box { @@ -293,26 +699,6 @@ button:disabled { #sign_in_page .sign-in-box sm-input { text-align: left; } -#sign_in_page .sign-in-box sm-panel { - width: 100%; -} -#sign_in_page .sign-in-box sm-tab-header { - background: none; - align-self: flex-start; -} -#sign_in_page .sign-in-box sm-tab-header::part(tab-header) { - padding-bottom: 0.4rem; - gap: 1.5rem; -} -#sign_in_page .sign-in-box sm-tab::part(tab) { - padding: 0.4rem 0; -} -#sign_in_page .sign-in-box sm-tab-panels { - margin-top: 3rem; -} -#sign_in_page .sign-in-box form { - width: 100%; -} #sign_in_page .sign-in-box h2 { margin-bottom: 0.5rem; } @@ -327,16 +713,6 @@ button:disabled { opacity: 0.8; font-weight: 500; } -#sign_in_page .sign-in-box .copy-row h4 { - max-width: 34ch; -} -#sign_in_page .sign-in-box .copy-row:not(:last-of-type) { - margin-bottom: 1rem; -} -#sign_in_page .sign-in-box button { - margin-top: 1rem; - padding: 0.6rem 1.6rem; -} #sign_in_page .sign-in-box p { margin-bottom: 0.5rem; max-width: 35ch; @@ -347,7 +723,17 @@ button:disabled { border-top: 1px rgba(var(--text-color), 0.2) solid; margin-top: 1rem; padding-top: 1.5rem; - animation: slide-down 0.3s forwards; + -webkit-animation: slide-down 0.3s forwards; + animation: slide-down 0.3s forwards; +} + +@-webkit-keyframes slide-down { + from { + transform: translateY(-1rem); + } + to { + transform: none; + } } @keyframes slide-down { @@ -358,103 +744,37 @@ button:disabled { transform: none; } } -.copy-row { - display: grid; - grid-template-columns: 1fr auto; - align-items: center; - gap: 0.5rem; - width: auto; -} -.copy-row h4 { - font-family: "Roboto", sans-serif; - margin-bottom: 0; - font-weight: 400; - margin: 0 !important; -} -.copy-row .icon { - cursor: pointer; - padding: 0.4rem; - height: 1.8rem; - width: 1.8rem; -} -.copy-row .copy { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - #main_loader { text-align: center; place-content: center; + justify-items: center; height: 100vh; width: 100vw; position: fixed; left: 0; + gap: 1rem; } #main_loader sm-button { margin-left: 0; margin-top: 1rem; + width: -webkit-max-content; + width: -moz-max-content; width: max-content; justify-self: center; } -#main_loader svg { - height: 2rem; - width: 2rem; - stroke: var(--accent-color); - stroke-width: 6; - fill: none; - overflow: visible; - stroke-linecap: round; - stroke-dashoffset: 210; - stroke-dasharray: 210; - justify-self: center; - align-self: center; - margin-bottom: 2rem; -} #main_loader h3 { width: 100%; font-weight: 400; word-spacing: 0.16em; } -.loader { - fill: none; - stroke-width: 10; - stroke: var(--accent-color); - height: 2rem; - width: 2rem; - overflow: visible; - stroke-dashoffset: 230; - stroke-dasharray: 230; - padding: 2px; - justify-self: center; -} - -.animate-loader { - animation: load 2.6s infinite, rotate 1s infinite linear; -} - -@keyframes rotate { - 100% { - transform: rotate(360deg); - } -} -@keyframes load { - 50% { - stroke-dashoffset: 0; - } - 100% { - stroke-dashoffset: -210; - } -} #main_header { padding: 1rem; - box-shadow: 0 0.1rem 0.2rem #00000010; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.062745098); background: rgba(var(--foreground-color), 1); } #main_header h5 { font-weight: 500; - font-family: "Roboto", sans-serif; opacity: 0.8; } #main_header h4 { @@ -466,6 +786,7 @@ button:disabled { } .section-header { + position: -webkit-sticky; position: sticky; top: 0; z-index: 1; @@ -487,8 +808,6 @@ button:disabled { width: 2.4rem; height: 2.4rem; padding: 0.6rem; - cursor: pointer; - background: rgba(var(--text-color), 0.1); border-radius: 2rem; } @@ -496,7 +815,17 @@ button:disabled { gap: 2rem 1.5rem; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); margin-bottom: 3rem; - animation: slide-up 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); + -webkit-animation: slide-up 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); + animation: slide-up 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@-webkit-keyframes slide-up { + from { + transform: translateY(2rem); + } + to { + transform: none; + } } @keyframes slide-up { @@ -523,7 +852,7 @@ button:disabled { align-items: center; justify-content: center; position: relative; - background: url(card-bg1.svg), #A7003E; + background: url(card-bg1.svg), #a7003e; background-size: cover; } @@ -532,14 +861,11 @@ button:disabled { display: flex; flex-direction: column; align-items: center; - cursor: pointer; -} -.sheet-card:active .card { - transform: scale(0.95); + color: inherit; } .sheet-card .card { position: relative; - border-radius: 0.4rem; + border-radius: 0.5rem; background: url(card-bg2.svg) center, rgba(var(--text-color), 0.06); background-size: contain; padding: 1rem; @@ -548,7 +874,6 @@ button:disabled { transition: box-shadow 0.3s, transform 0.3s; } .sheet-card h4 { - font-family: "Roboto", sans-serif; font-weight: 400; opacity: 0.9; margin-top: 0.8rem; @@ -556,7 +881,6 @@ button:disabled { max-width: 90%; } .sheet-card h5 { - font-family: "Roboto", sans-serif; background: rgba(var(--text-color), 0.1); position: absolute; top: 0; @@ -568,12 +892,12 @@ button:disabled { opacity: 0.8; } -#sheet_page { +#sheet_view { width: 100vw; height: 100vh; overflow-x: hidden; } -#sheet_page.toggle-side-bar #side_bar { +#sheet_view.toggle-side-bar #side_bar { transition: transform 0.3s; z-index: 10; transform: none; @@ -600,7 +924,6 @@ button:disabled { #sheet_editors { gap: 0.5rem; - flex-wrap: wrap; color: rgba(var(--text-color), 0.7); font-size: 0.9rem; } @@ -610,14 +933,15 @@ button:disabled { background: rgba(var(--text-color), 0.06); } -#toggle_details, #go_to_home { +#go_to_home { height: 2.4rem; width: 2.4rem; padding: 0.7rem; cursor: pointer; } -#go_to_home, #go_to_home + h5 { +#go_to_home, +#go_to_home + h5 { transform: translateX(-1rem); cursor: pointer; } @@ -629,7 +953,6 @@ button:disabled { #toggle_details { transform: rotateX(180deg); - transition: transform 0.3s; } #sheet_details { @@ -645,11 +968,6 @@ button:disabled { #sheet_details .flex:not(:first-of-type) { margin-bottom: 0.3rem; } -#sheet_details .flex:not(:first-of-type) .icon { - cursor: pointer; - margin-right: 1rem; - height: 100%; -} #sheet_details.collapse { padding: 0.5rem 1rem; margin-bottom: 0; @@ -679,10 +997,6 @@ button:disabled { max-width: 100%; } -sm-select::part(options) { - max-height: 50vh; -} - table { border-collapse: collapse; position: relative; @@ -702,6 +1016,7 @@ table input:disabled { } th { + position: -webkit-sticky; position: sticky; top: 0; background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), rgba(var(--foreground-color), 1); @@ -712,7 +1027,7 @@ th { z-index: 1; padding: 1rem 0.8rem; white-space: nowrap; - box-shadow: 0 0.2rem 0.4rem #00000020; + box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.1254901961); cursor: pointer; } @@ -761,7 +1076,9 @@ th.ascending::after { #side_bar { position: fixed; transform: translateX(-100%); - background: var(--dark-shade); + background: rgba(var(--background-color), 1); + bottom: 0; + top: 0; } #side_bar > .flex:first-of-type { padding: 0 1rem; @@ -778,7 +1095,17 @@ th.ascending::after { overflow: auto; max-height: 100vh; background: rgba(var(--foreground-color), 1); - animation: slide-right 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); + -webkit-animation: slide-right 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); + animation: slide-right 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@-webkit-keyframes slide-right { + from { + transform: translateX(-2rem); + } + to { + transform: translateX(0); + } } @keyframes slide-right { @@ -790,7 +1117,8 @@ th.ascending::after { } } .placeholder { - animation: placeholder-loading 0.6s infinite alternate; + -webkit-animation: placeholder-loading 0.6s infinite alternate; + animation: placeholder-loading 0.6s infinite alternate; padding: 1.5rem 0; width: 100%; margin: 1.5rem; @@ -802,6 +1130,15 @@ th.ascending::after { height: calc(100% - 3rem); } +@-webkit-keyframes placeholder-loading { + from { + opacity: 0.4; + } + to { + opacity: 1; + } +} + @keyframes placeholder-loading { from { opacity: 0.4; @@ -826,9 +1163,6 @@ th.ascending::after { transition: transform 0.3s; -webkit-tap-highlight-color: transparent; } -.person-card:active { - transform: scale(0.95); -} .person-card:first-of-type { margin-top: 1.5rem; } @@ -872,29 +1206,6 @@ th.ascending::after { margin-bottom: 1.5rem; } -#new_sheet_popup p { - font-size: 0.9rem; -} - -#specify_columns, -#specify_editors, -#specify_details { - gap: 1rem; - margin-top: 1rem; - padding-top: 1rem; -} -#specify_columns h4, -#specify_editors h4, -#specify_details h4 { - font-weight: 500; - font-size: 0.9rem; - margin-bottom: 0.2rem; -} - -#columns_container { - flex-wrap: wrap; -} - #editors_container, #columns_container, #additional_fields { @@ -910,21 +1221,13 @@ th.ascending::after { #add_detail sm-input { width: 100%; } -#add_editor .icon, -#add_column .icon, -#add_detail .icon { - height: 3rem; - width: 3rem; - padding: 1rem; - cursor: pointer; -} #add_detail { gap: 0.2rem; grid-template-columns: 1fr auto; grid-template-areas: ". add" ". add"; } -#add_detail .icon { +#add_detail button { grid-area: add; align-self: flex-end; } @@ -935,16 +1238,9 @@ th.ascending::after { border-radius: 0.3rem; background: rgba(var(--text-color), 0.06); } -.editor-card .icon, -.column-card .icon, -.details-card .icon { - padding: 0.3rem; - cursor: pointer; -} .editor-card .editor-address, .column-card .editor-address, .details-card .editor-address { - font-family: "Roboto", sans-serif; font-size: 0.9rem; font-weight: 400; opacity: 0.8; @@ -959,7 +1255,6 @@ th.ascending::after { } .column-card h5 { font-weight: 500; - font-family: "Roboto", sans-serif; } .column-card .icon { margin-left: 0.4rem; @@ -971,8 +1266,8 @@ th.ascending::after { grid-template-columns: 1fr auto; grid-template-areas: ". close" ". close"; } -.details-card h4, .details-card h5 { - font-family: "Roboto", sans-serif; +.details-card h4, +.details-card h5 { margin: 0 !important; } .details-card h5 { @@ -982,7 +1277,7 @@ th.ascending::after { .details-card h4 { font-size: 1rem !important; } -.details-card .icon { +.details-card button { grid-area: close; } @@ -991,21 +1286,22 @@ th.ascending::after { overflow: hidden; bottom: 0; left: 0; - width: calc(100% - 2rem); + right: 0; + width: min(100% - 2rem, 24rem); padding: 1rem; margin: 1rem; - border-radius: 0.4rem; + border-radius: 0.5rem; + border: solid thin rgba(var(--text-color), 0.1); background: rgba(var(--foreground-color), 1); z-index: 20; - box-shadow: 0 0.1rem 0.1rem #00000010, 0 0 1rem #00000016; - transform: translateY(1rem); - transition: transform 0.3s, opacity 0.3s; + box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.16); } #save_button #changes_indicator { position: absolute; left: 0; - width: 0.5rem; - height: 100%; + width: 0.3rem; + border-radius: 0 0.5rem 0.5rem 0; + height: 2em; background: red; } #save_button sm-button { @@ -1022,11 +1318,12 @@ th.ascending::after { .hide-on-desktop { display: none; } - - sm-popup::part(popup) { - width: 24rem; + sm-popup { + --width: 24rem; + } + .popup__header { + padding: 1.5rem 1.5rem 0 0.75rem; } - #sign_in_page { grid-auto-flow: column; } @@ -1036,56 +1333,50 @@ th.ascending::after { min-height: 80vh; min-width: 26rem; border-radius: 0.5rem; - box-shadow: 0 0 0.3rem #00000016, 0 6rem 2rem -2rem #00000016; + box-shadow: 0 0 0.3rem rgba(0, 0, 0, 0.0862745098), 0 6rem 2rem -2rem rgba(0, 0, 0, 0.0862745098); background: rgba(var(--foreground-color), 1); } - #main_header { padding: 1.2rem 3rem; } - - #home_page, #main_header { + #home_page, +#main_header { grid-template-columns: 1fr 80vw 1fr; grid-template-areas: ". main ."; } - #main_section, #main_header > div { grid-area: main; } - #sheets_container { gap: 2rem; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); } - - #sheet_page.toggle-side-bar { + #sheet_view.toggle-side-bar { grid-template-columns: 19rem 1fr; } - #sheet_page.toggle-side-bar #side_bar { + #sheet_view.toggle-side-bar #side_bar { z-index: initial; } - #sheet_page:not(.toggle-side-bar) #side_bar { + #sheet_view:not(.toggle-side-bar) #side_bar { grid-template-columns: 1fr; position: fixed; transform: translateX(-100%); } - #side_bar { position: relative; transform: none; } - #group_by::part(popup) { width: 80vw; } - #save_button { - width: auto; + margin: 1rem auto; } } @media screen and (min-width: 1920px) { - #home_page, #main_header { + #home_page, +#main_header { grid-template-columns: 1fr 60vw 1fr; grid-template-areas: ". main ."; } @@ -1094,16 +1385,13 @@ th.ascending::after { :root { scrollbar-width: thin; } - ::-webkit-scrollbar { width: 0.7rem; height: 0.7rem; } - ::-webkit-scrollbar-track { border-radius: 10px; } - ::-webkit-scrollbar-thumb { border-radius: 10px; background: rgba(var(--text-color), 0.2); @@ -1111,13 +1399,14 @@ th.ascending::after { ::-webkit-scrollbar-thumb:hover { background: rgba(var(--text-color), 0.4); } - #people_container::-webkit-scrollbar { width: 0.4rem; } - #right { z-index: 1; - box-shadow: -0.5rem 0 0.5rem #00000010; + box-shadow: -0.5rem 0 0.5rem rgba(0, 0, 0, 0.062745098); } +} +.hidden { + display: none; } \ No newline at end of file diff --git a/css/main.min.css b/css/main.min.css index be2393d..0a4debd 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -@charset "UTF-8";.align-center,.popup-header{align-items:center}.capitalize,button{text-transform:capitalize}.person-card,button{transition:transform .3s;-webkit-tap-highlight-color:transparent}.copy-row .copy,.overflow-ellipsis{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}button,span.ripple{background:rgba(var(--text-color),.1)}*{box-sizing:border-box;padding:0;margin:0;font-family:Roboto,sans-serif}#confirmation h4,.bottom-margin{margin-bottom:1.5rem}button,h1,h2,h3,h4,h5{font-weight:600;font-family:Poppins,sans-serif}body{--accent-color:#169685;--text-color:17,17,17;--text-color-light:85,85,85;--foreground-color:255,255,255;--background-color:rgba(var(--foreground-color), 1);--dark-shade:#f8f8f8;--error-color:#E53935;--hue:172;--saturation:74%;--lightness:34%;color:rgba(var(--text-color),1);font-size:16px;background:var(--dark-shade);background-size:cover}body[data-theme=dark]{--accent-color:#00e2c4;--text-color:238,238,238;--text-color-light:170,170,170;--foreground-color:26,26,26;--background-color:#111;--dark-shade:#080808;--hue:172;--saturation:70%;--lightness:44%}a{font-weight:600;text-decoration:none;color:var(--accent-color)}.dark-text{color:#111}.person-initials,button{color:var(--accent-color)}h1{font-size:3.5rem}h2{font-size:2rem}h3{font-size:1.5rem}h4{font-size:1rem}h5{font-size:.8rem}p{line-height:1.5;max-width:65ch;color:rgba(var(--text-color),.9)}strong{font-weight:500}::-moz-focus-inner{border:none}.bottom-padding{padding-bottom:1.5rem}.top-padding{padding-top:1em}.top-margin{margin-top:1.5rem}#confirmation .flex,sm-popup sm-textarea{margin-top:1rem}.flex{display:flex}.grid{display:grid}.grid-2{grid-template-columns:auto auto;gap:1em}.direction-column{flex-direction:column}.justify-right{margin-left:auto}.space-between{justify-content:space-between}.label{margin-bottom:.4rem}.light-text{opacity:.7}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.breakable{word-break:break-all}.separator{padding:.1em}.no-transformations{transform:none!important}span.ripple{position:absolute;border-radius:50%;transform:scale(0);animation:ripple .6s linear}@keyframes ripple{to{transform:scale(4);opacity:0}}.icon{height:1.2rem;width:1.2rem;overflow:visible;stroke:rgba(var(--text-color),1);opacity:.8;fill:none;stroke-width:6;stroke-linejoin:round;stroke-linecap:round}sm-popup>sm-input:not(:last-of-type){margin-bottom:1rem}.popup-header{padding:1.5rem;padding-bottom:0;display:flex;width:100%}.popup-header .icon{margin-right:1rem;padding:.2rem;stroke-width:10;cursor:pointer}.popup-header button,.popup-header sm-button{width:auto;margin-left:auto}button{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:.6rem 1.2rem;cursor:pointer;border-radius:.3rem;border:none}#main_header h5,#sign_in_page .info h4,.column-card .editor-address,.column-card h5,.copy-row h4,.details-card .editor-address,.details-card h4,.details-card h5,.editor-card .editor-address,.sheet-card h4,.sheet-card h5{font-family:Roboto,sans-serif}button:focus{outline:solid thin}button:disabled{cursor:default;background:rgba(var(--text-color),.4)}.primary-btn{background:var(--accent-color);justify-content:center;color:rgba(var(--foreground-color),1)}#confirmation,.sheet-card{flex-direction:column}#confirmation h4{font-weight:500}#confirmation .flex sm-button:first-of-type{margin-right:.6em;margin-left:auto}#sign_in_page{background:url(sign-in-bg.svg) center no-repeat,linear-gradient(rgba(var(--text-color),.04),rgba(var(--text-color),.04)),linear-gradient(rgba(var(--foreground-color),1),rgba(var(--foreground-color),1));background-size:cover;min-height:100vh;width:100vw;align-items:center;padding:0 6vw}#sign_in_page .info h1{font-weight:800;font-size:clamp(1.5rem,8vw,4rem)}#sign_in_page .info h4{font-weight:500;opacity:.8}#sign_in_page .sign-in-box{width:calc(100vw - 4rem);z-index:1}#sign_in_page .sign-in-box form,#sign_in_page .sign-in-box sm-panel{width:100%}#sign_in_page .sign-in-box sm-input{text-align:left}#sign_in_page .sign-in-box sm-tab-header{background:0 0;align-self:flex-start}#sign_in_page .sign-in-box sm-tab-header::part(tab-header){padding-bottom:.4rem;gap:1.5rem}#sign_in_page .sign-in-box sm-tab::part(tab){padding:.4rem 0}#sign_in_page .sign-in-box sm-tab-panels{margin-top:3rem}#sign_in_page .sign-in-box h2{margin-bottom:.5rem}#sign_in_page .sign-in-box h3{font-weight:500}#sign_in_page .sign-in-box h4{font-weight:500;margin-bottom:1.5rem}#sign_in_page .sign-in-box h5{opacity:.8;font-weight:500}#sign_in_page .sign-in-box .copy-row h4{max-width:34ch}#sign_in_page .sign-in-box .copy-row:not(:last-of-type){margin-bottom:1rem}#sign_in_page .sign-in-box button{margin-top:1rem;padding:.6rem 1.6rem}#sign_in_page .sign-in-box p{max-width:35ch;margin-top:.5rem;margin-bottom:1.5rem}#sign_in_page .sign-in-box #credentials_section{border-top:1px rgba(var(--text-color),.2) solid;margin-top:1rem;padding-top:1.5rem;animation:slide-down .3s forwards}@keyframes slide-down{from{transform:translateY(-1rem)}to{transform:none}}.copy-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.5rem;width:auto}.copy-row h4{font-weight:400;margin:0!important}.copy-row .icon{cursor:pointer;padding:.4rem;height:1.8rem;width:1.8rem}#main_loader{text-align:center;place-content:center;height:100vh;width:100vw;position:fixed;left:0}#main_loader svg,.loader{fill:none;height:2rem;overflow:visible}#main_loader sm-button{margin-left:0;margin-top:1rem;width:max-content;justify-self:center}#main_loader svg{width:2rem;stroke:var(--accent-color);stroke-width:6;stroke-linecap:round;stroke-dashoffset:210;stroke-dasharray:210;justify-self:center;align-self:center;margin-bottom:2rem}#main_loader h3{width:100%;font-weight:400;word-spacing:.16em}.loader{stroke-width:10;stroke:var(--accent-color);width:2rem;stroke-dashoffset:230;stroke-dasharray:230;padding:2px;justify-self:center}.animate-loader{animation:load 2.6s infinite,rotate 1s infinite linear}@keyframes rotate{100%{transform:rotate(360deg)}}@keyframes load{50%{stroke-dashoffset:0}100%{stroke-dashoffset:-210}}#main_header{padding:1rem;box-shadow:0 .1rem .2rem #00010;background:rgba(var(--foreground-color),1)}#main_header h5{font-weight:500;opacity:.8}#main_header h4{font-size:1.2rem}#home_page{padding:1rem 1.5rem}.section-header{position:sticky;top:0;z-index:1;background:var(--dark-shade);padding:1rem 0;margin-bottom:1rem}.section-header h4{font-size:1.2rem;opacity:.8;font-weight:500}#main_section>header sm-input{margin-left:1rem}#user_icon{width:2.4rem;height:2.4rem;padding:.6rem;cursor:pointer;background:rgba(var(--text-color),.1);border-radius:2rem}#sheets_container{gap:2rem 1.5rem;grid-template-columns:repeat(auto-fill,minmax(9rem,1fr));margin-bottom:3rem;animation:slide-up .6s forwards cubic-bezier(.175,.885,.32,1.275)}@keyframes slide-up{from{transform:translateY(2rem)}to{transform:none}}#add_new_sheet .icon{height:2rem;width:2rem;stroke-width:10;stroke:#fff;stroke-linecap:square;opacity:1;top:50%;transform:translateY(-50%);position:absolute}#add_new_sheet .card{display:flex;align-items:center;justify-content:center;position:relative;background:url(card-bg1.svg),#A7003E;background-size:cover}.sheet-card{position:relative;display:flex;align-items:center;cursor:pointer}.sheet-card:active .card{transform:scale(.95)}.sheet-card .card{position:relative;border-radius:.4rem;background:url(card-bg2.svg) center,rgba(var(--text-color),.06);background-size:contain;padding:1rem;padding-top:66%;width:100%;transition:box-shadow .3s,transform .3s}#sheet_type,.sheet-card h5{background:rgba(var(--text-color),.1)}.sheet-card h4{font-weight:400;opacity:.9;margin-top:.8rem;text-align:center;max-width:90%}.sheet-card h5{position:absolute;top:0;right:0;margin:.5rem 0;padding:.4rem .6rem;border-radius:.2rem 0 0 .2rem;font-weight:500;opacity:.8}#sheet_editors .editor,table input{background:rgba(var(--text-color),.06)}#right,#sheet_container,table,table input{position:relative}#sheet_page{width:100vw;height:100vh;overflow-x:hidden}#sheet_page.toggle-side-bar #side_bar{transition:transform .3s;z-index:10;transform:none}#sheet_heading{font-weight:600;opacity:.9}#sheet_type{padding:.3rem .6rem;border-radius:.3rem;margin:0 1rem;font-weight:500;opacity:.8}#sheet_description{margin-top:.8rem;opacity:.8}#sheet_editors{gap:.5rem;flex-wrap:wrap;color:rgba(var(--text-color),.7);font-size:.9rem}#sheet_editors .editor{padding:.4rem .6rem;border-radius:.4rem}#go_to_home,#toggle_details{height:2.4rem;width:2.4rem;padding:.7rem;cursor:pointer}#go_to_home,#go_to_home+h5{transform:translateX(-1rem);cursor:pointer}#go_to_home+h5{font-weight:500;opacity:.9}#toggle_details{transform:rotateX(180deg);transition:transform .3s}#sheet_details{padding:1rem;margin-bottom:1rem}#sheet_details .flex:first-of-type{margin-bottom:1rem}#sheet_details .flex:nth-of-type(2){margin-bottom:1rem}#sheet_details .flex:not(:first-of-type){margin-bottom:.3rem}#sheet_details .flex:not(:first-of-type) .icon{cursor:pointer;margin-right:1rem;height:100%}#sheet_details.collapse{padding:.5rem 1rem;margin-bottom:0}#sheet_details.collapse .flex{margin-bottom:0}#sheet_details.collapse #toggle_details{transform:none}#sheet_details.collapse #sheet_heading{font-size:1.2rem;font-weight:600;opacity:.9}#sheet_details.collapse #sheet_description,#sheet_details.collapse #sheet_editors,#sheet_details.collapse #sheet_type{display:none}#sheet_container{overflow:auto;max-height:100%;bottom:0;max-width:100%}sm-select::part(options){max-height:50vh}table{border-collapse:collapse}table input{padding:.4rem;border:thin solid;font-size:1rem;width:100%;border-radius:.3rem;color:inherit}table input:disabled{border:transparent}th{position:sticky;top:0;background:linear-gradient(rgba(var(--text-color),.06),rgba(var(--text-color),.06)),rgba(var(--foreground-color),1);text-align:left;line-height:1;vertical-align:middle;font-weight:500;z-index:1;padding:1rem .8rem;white-space:nowrap;box-shadow:0 .2rem .4rem #00020;cursor:pointer}tr:nth-of-type(2n){background-color:rgba(var(--text-color),.04)}td{padding:.4rem .8rem;opacity:.9}.text-field{min-width:20ch;max-width:30ch}.grade-input{width:10ch}th.ascending::after,th.descending::after{display:inline-flex;justify-self:flex-end;position:relative;margin-left:auto;font-size:.8rem}th.descending::after{content:" ▼"}th.ascending::after{content:" ▲"}#group_by::part(popup){min-height:80vh}#group_by sm-select:last-of-type{margin-left:.5rem}#side_bar{position:fixed;transform:translateX(-100%);background:var(--dark-shade)}#side_bar>.flex:first-of-type{padding:0 1rem}#side_bar .section-header{margin-bottom:0;background:inherit}#right{display:flex;flex-direction:column;overflow:auto;max-height:100vh;background:rgba(var(--foreground-color),1);animation:slide-right .6s forwards cubic-bezier(.175,.885,.32,1.275)}.column-card,.details-card,.editor-card,.person-initials,.placeholder{background:rgba(var(--text-color),.06)}@keyframes slide-right{from{transform:translateX(-2rem)}to{transform:translateX(0)}}.placeholder{animation:placeholder-loading .6s infinite alternate;padding:1.5rem 0;width:100%;margin:1.5rem;border-radius:.5rem}.placeholder#sheet_container{width:calc(100% - 3rem);height:calc(100% - 3rem)}@keyframes placeholder-loading{from{opacity:.4}to{opacity:1}}#people_container{overflow:auto;max-height:calc(100vh - 3.6rem);gap:1.5rem}.person-card{display:grid;align-items:center;grid-template-columns:auto 1fr;grid-template-areas:"initials ." "initials .";cursor:pointer;padding:0 1rem}.person-card:active{transform:scale(.95)}.person-card:first-of-type{margin-top:1.5rem}.person-card:last-of-type{margin-bottom:2rem}.person-initials{grid-area:initials;display:flex;justify-content:center;height:2.6rem;width:2.6rem;font-size:1.2rem!important;font-weight:500;align-items:center;border-radius:2rem;margin-right:1rem;text-transform:uppercase;opacity:1!important}.person-name{font-size:.9rem;opacity:.9;font-weight:500;text-transform:capitalize}.person-flo-id{opacity:.7;font-weight:400}#user_popup sm-button{margin-top:.5rem}#user_popup section:not(:last-of-type){margin-bottom:1.5rem}#new_sheet_popup p{font-size:.9rem}#specify_columns,#specify_details,#specify_editors{gap:1rem;margin-top:1rem;padding-top:1rem}#specify_columns h4,#specify_details h4,#specify_editors h4{font-weight:500;font-size:.9rem;margin-bottom:.2rem}#columns_container{flex-wrap:wrap}#additional_fields,#columns_container,#editors_container{gap:.4rem}#add_detail,.details-card{gap:.2rem;grid-template-columns:1fr auto}#specify_editors{border-top:solid 1px rgba(var(--text-color),.2)}#add_column sm-input,#add_detail sm-input,#add_editor sm-input{width:100%}#add_column .icon,#add_detail .icon,#add_editor .icon{height:3rem;width:3rem;padding:1rem;cursor:pointer}#add_detail{grid-template-areas:". add" ". add"}#add_detail .icon{grid-area:add;align-self:flex-end}.column-card,.details-card,.editor-card{border-radius:.3rem}.column-card .icon,.details-card .icon,.editor-card .icon{padding:.3rem;cursor:pointer}.column-card .editor-address,.details-card .editor-address,.editor-card .editor-address{font-size:.9rem;font-weight:400;opacity:.8}.editor-card{padding:.4rem .8rem}.column-card{padding:.4rem .6rem}.column-card h5{font-weight:500}.column-card .icon{margin-left:.4rem}.details-card{padding:.6rem .8rem;grid-template-areas:". close" ". close"}.details-card h4,.details-card h5{margin:0!important}.details-card h5{font-weight:400;opacity:.8}.details-card h4{font-size:1rem!important}.details-card .icon{grid-area:close}#save_button{position:fixed;overflow:hidden;bottom:0;left:0;width:calc(100% - 2rem);padding:1rem;margin:1rem;border-radius:.4rem;background:rgba(var(--foreground-color),1);z-index:20;box-shadow:0 .1rem .1rem #00010,0 0 1rem #00016;transform:translateY(1rem);transition:transform .3s,opacity .3s}#save_button #changes_indicator{position:absolute;left:0;width:.5rem;height:100%;background:red}#save_button sm-button{margin-left:1rem}@media screen and (max-width:640px){#group_by_view{overflow:auto;max-width:calc(100vw - 3rem)}}@media screen and (min-width:640px){.hide-on-desktop{display:none}sm-popup::part(popup){width:24rem}#sign_in_page{grid-auto-flow:column}#sign_in_page .sign-in-box{width:26rem;padding:2rem;min-height:80vh;min-width:26rem;border-radius:.5rem;box-shadow:0 0 .3rem #00016,0 6rem 2rem -2rem #00016;background:rgba(var(--foreground-color),1)}#main_header{padding:1.2rem 3rem}#home_page,#main_header{grid-template-columns:1fr 80vw 1fr;grid-template-areas:". main ."}#main_header>div,#main_section{grid-area:main}#sheets_container{gap:2rem;grid-template-columns:repeat(auto-fill,minmax(11rem,1fr))}#sheet_page.toggle-side-bar{grid-template-columns:19rem 1fr}#sheet_page.toggle-side-bar #side_bar{z-index:initial}#sheet_page:not(.toggle-side-bar) #side_bar{grid-template-columns:1fr;position:fixed;transform:translateX(-100%)}#side_bar{position:relative;transform:none}#group_by::part(popup){width:80vw}#save_button{width:auto}}@media screen and (min-width:1920px){#home_page,#main_header{grid-template-columns:1fr 60vw 1fr;grid-template-areas:". main ."}}@media (any-hover:hover){:root{scrollbar-width:thin}::-webkit-scrollbar{width:.7rem;height:.7rem}::-webkit-scrollbar-track{border-radius:10px}::-webkit-scrollbar-thumb{border-radius:10px;background:rgba(var(--text-color),.2)}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.4)}#people_container::-webkit-scrollbar{width:.4rem}#right{z-index:1;box-shadow:-.5rem 0 .5rem #00010}} \ No newline at end of file +*{padding:0;margin:0;box-sizing:border-box;font-family:"Roboto",sans-serif}:root{font-size:clamp(1rem,1.2vmax,1.2rem)}html,body{height:100%}body{--accent-color: #3d5afe;--secondary-color: #ffac2e;--text-color: 20, 20, 20;--foreground-color: 252, 253, 255;--background-color: 241, 243, 248;--danger-color: rgb(255, 75, 75);--green: #1cad59;--yellow: rgb(220, 165, 0);color:rgba(var(--text-color), 1);background-color:rgba(var(--background-color), 1);overflow-y:hidden}body[data-theme=dark]{--accent-color: #6d83ff;--secondary-color: #d60739;--text-color: 220, 220, 220;--foreground-color: 27, 28, 29;--background-color: 21, 22, 22;--danger-color: rgb(255, 106, 106);--green: #00e676;--yellow: rgb(255, 213, 5)}body[data-theme=dark] ::-webkit-calendar-picker-indicator{filter:invert(1)}p,strong{font-size:.9rem;max-width:65ch;line-height:1.7;color:rgba(var(--text-color), 0.9)}img{-o-object-fit:cover;object-fit:cover}a:where([class]){color:inherit;text-decoration:none}a:where([class]):focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color), 1) inset}a{color:var(--accent-color)}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a.button{padding:.4rem .6rem;border-radius:.3rem;font-size:.9rem;font-weight:500;color:inherit}button,.button{-webkit-user-select:none;-moz-user-select:none;user-select:none;position:relative;display:inline-flex;border:none;background-color:rgba(0,0,0,0);overflow:hidden;color:inherit;-webkit-tap-highlight-color:rgba(0,0,0,0);align-items:center;font-size:.9rem;font-weight:500;white-space:nowrap;padding:.8rem;border-radius:.3rem;justify-content:center}button:focus-visible,.button:focus-visible{outline:var(--accent-color) solid medium}button:not(:disabled),.button:not(:disabled){cursor:pointer}.button{background-color:rgba(var(--text-color), 0.1)}.button--primary,.button--danger{color:rgba(var(--background-color), 1) !important}.button--primary .icon,.button--danger .icon{fill:rgba(var(--background-color), 1)}.button--primary{text-transform:capitalize;background-color:var(--accent-color)}.button--danger{background-color:var(--danger-color)}.button--small{padding:.4rem .6rem}.button--outlined{border:solid rgba(var(--text-color), 0.5) .1rem;background-color:rgba(var(--foreground-color), 1)}.button--transparent{background-color:rgba(0,0,0,0)}.cta{text-transform:uppercase;font-size:.8rem;font-weight:700;letter-spacing:.05em;padding:.8rem 1rem}.icon{width:1.2rem;height:1.2rem;fill:rgba(var(--text-color), 0.8);flex-shrink:0}.icon-only{padding:.5rem;border-radius:.3rem;aspect-ratio:1/1}button:disabled{opacity:.5}a:-webkit-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:-moz-any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}a:any-link:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}details summary{display:flex;-webkit-user-select:none;-moz-user-select:none;user-select:none;cursor:pointer;align-items:center;justify-content:space-between;color:var(--accent-color)}details[open] summary{margin-bottom:1rem}details[open]>summary .down-arrow{transform:rotate(180deg)}fieldset{border:none}input{accent-color:var(--accent-color)}input[type=range]:active{cursor:-webkit-grab;cursor:grab}sm-copy{font-size:.9rem}sm-input,sm-textarea{font-size:.9rem;--border-radius: 0.5rem;--background-color: rgba(var(--foreground-color), 1)}sm-input button .icon,sm-textarea button .icon{fill:var(--accent-color)}sm-textarea{--max-height: 32ch}sm-button{--padding: 0.8rem}sm-button[variant=primary] .icon{fill:rgba(var(--background-color), 1)}sm-button[disabled] .icon{fill:rgba(var(--text-color), 0.6)}sm-button.danger{--background: var(--danger-color);color:rgba(var(--background-color), 1)}sm-spinner{--size: 1.5rem;--stroke-width: 0.1rem}sm-form{--gap: 1rem}sm-select{--padding: 0.8rem;font-size:.9rem;--min-width: 8rem}sm-option{font-size:.9rem}strip-select{--gap: 0;background-color:rgba(var(--text-color), 0.06);border-radius:.3rem;padding:.3rem}strip-option{position:relative;font-size:.8rem;--border-radius: 0.2rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}sm-button{--border-radius: 0.3rem}sm-button[variant=primary] .icon{fill:rgba(var(--background-color), 1)}sm-button[disabled] .icon{fill:rgba(var(--text-color), 0.6)}sm-select[open]{z-index:10}ul{list-style:none}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.wrap-around{overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/-1}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.sticky{position:-webkit-sticky;position:sticky}.top-0{top:0}.flex{display:flex}.flex-wrap{flex-wrap:wrap}.flex-1{flex:1}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-3{gap:.3rem}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.text-align-left{text-align:left}.align-items-start{align-items:flex-start}.align-content-start{align-content:flex-start}.align-start{align-content:flex-start}.align-center{align-items:center}.align-end{align-items:flex-end}.text-center{text-align:center}.justify-start{justify-items:start}.justify-content-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-start{align-self:start}.align-self-center{align-self:center}.align-self-end{align-self:end}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.flex-direction-column{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.h-100{height:100%}.margin-right-0-3{margin-right:.3rem}.margin-right-0-5{margin-right:.5rem}.margin-left-0-5{margin-left:.5rem}.margin-left-auto{margin-left:auto}.margin-right-auto{margin-right:auto}.margin-bottom-0-5{margin-bottom:.5rem}.margin-bottom-1{margin-bottom:1rem}.margin-bottom-2{margin-bottom:2rem}.margin-block-0-5{margin-block:.5rem}.margin-block-1{margin-block:1rem}.margin-block-1-5{margin-block:1.5rem}.margin-inline-1{margin-inline:1rem}.margin-inline-1-5{margin-inline:1.5rem}.hidden{display:none !important}.no-transformations{transform:none !important}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color), 0.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.card{background-color:rgba(var(--text-color), 0.06);border-radius:.5rem;padding:max(1rem,3vw)}.ripple{height:8rem;width:8rem;position:absolute;border-radius:50%;transform:scale(0);background:radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%);pointer-events:none}.interactive{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}[data-editable]{transition:padding .2s}[data-editable]:focus-within{padding:.5em;border-radius:.3rem;outline:none;background-color:rgba(var(--text-color), 0.06);box-shadow:0 0 0 .1rem var(--accent-color) inset}.multi-state-button{display:grid;text-align:center;align-items:center}.multi-state-button>*{grid-area:1/1/2/2}.multi-state-button button{z-index:1}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}.popup__header{display:grid;gap:.5rem;width:100%;padding:0 1.5rem 0 .5rem;align-items:center;grid-template-columns:auto 1fr auto}.popup__header__close{padding:.5rem;cursor:pointer}#sign_in_page{background:url(sign-in-bg.svg) no-repeat center,linear-gradient(rgba(var(--text-color), 0.04), rgba(var(--text-color), 0.04)),linear-gradient(rgba(var(--foreground-color), 1), rgba(var(--foreground-color), 1));background-size:cover;min-height:100vh;width:100vw;align-items:center;padding:0 6vw}#sign_in_page .info h1{font-weight:800;font-size:clamp(1.5rem,8vw,4rem)}#sign_in_page .info h4{font-weight:500;opacity:.8}#sign_in_page .sign-in-box{width:calc(100vw - 4rem);z-index:1}#sign_in_page .sign-in-box sm-input{text-align:left}#sign_in_page .sign-in-box h2{margin-bottom:.5rem}#sign_in_page .sign-in-box h3{font-weight:500}#sign_in_page .sign-in-box h4{font-weight:500;margin-bottom:1.5rem}#sign_in_page .sign-in-box h5{opacity:.8;font-weight:500}#sign_in_page .sign-in-box p{margin-bottom:.5rem;max-width:35ch;margin-top:.5rem;margin-bottom:1.5rem}#sign_in_page .sign-in-box #credentials_section{border-top:1px rgba(var(--text-color), 0.2) solid;margin-top:1rem;padding-top:1.5rem;-webkit-animation:slide-down .3s forwards;animation:slide-down .3s forwards}@-webkit-keyframes slide-down{from{transform:translateY(-1rem)}to{transform:none}}@keyframes slide-down{from{transform:translateY(-1rem)}to{transform:none}}#main_loader{text-align:center;place-content:center;justify-items:center;height:100vh;width:100vw;position:fixed;left:0;gap:1rem}#main_loader sm-button{margin-left:0;margin-top:1rem;width:-webkit-max-content;width:-moz-max-content;width:max-content;justify-self:center}#main_loader h3{width:100%;font-weight:400;word-spacing:.16em}#main_header{padding:1rem;box-shadow:0 .1rem .2rem rgba(0,0,0,.062745098);background:rgba(var(--foreground-color), 1)}#main_header h5{font-weight:500;opacity:.8}#main_header h4{font-size:1.2rem}#home_page{padding:1rem 1.5rem}.section-header{position:-webkit-sticky;position:sticky;top:0;z-index:1;background:var(--dark-shade);padding:1rem 0;margin-bottom:1rem}.section-header h4{font-size:1.2rem;opacity:.8;font-weight:500}#main_section>header sm-input{margin-left:1rem}#user_icon{width:2.4rem;height:2.4rem;padding:.6rem;border-radius:2rem}#sheets_container{gap:2rem 1.5rem;grid-template-columns:repeat(auto-fill, minmax(9rem, 1fr));margin-bottom:3rem;-webkit-animation:slide-up .6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);animation:slide-up .6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)}@-webkit-keyframes slide-up{from{transform:translateY(2rem)}to{transform:none}}@keyframes slide-up{from{transform:translateY(2rem)}to{transform:none}}#add_new_sheet .icon{height:2rem;width:2rem;stroke-width:10;stroke:#fff;stroke-linecap:square;opacity:1;top:50%;transform:translateY(-50%);position:absolute}#add_new_sheet .card{display:flex;align-items:center;justify-content:center;position:relative;background:url(card-bg1.svg),#a7003e;background-size:cover}.sheet-card{position:relative;display:flex;flex-direction:column;align-items:center;color:inherit}.sheet-card .card{position:relative;border-radius:.5rem;background:url(card-bg2.svg) center,rgba(var(--text-color), 0.06);background-size:contain;padding:1rem;padding-top:66%;width:100%;transition:box-shadow .3s,transform .3s}.sheet-card h4{font-weight:400;opacity:.9;margin-top:.8rem;text-align:center;max-width:90%}.sheet-card h5{background:rgba(var(--text-color), 0.1);position:absolute;top:0;right:0;margin:.5rem 0;padding:.4rem .6rem;border-radius:.2rem 0 0 .2rem;font-weight:500;opacity:.8}#sheet_view{width:100vw;height:100vh;overflow-x:hidden}#sheet_view.toggle-side-bar #side_bar{transition:transform .3s;z-index:10;transform:none}#sheet_heading{font-weight:600;opacity:.9}#sheet_type{padding:.3rem .6rem;border-radius:.3rem;margin:0 1rem;font-weight:500;opacity:.8;background:rgba(var(--text-color), 0.1)}#sheet_description{margin-top:.8rem;opacity:.8}#sheet_editors{gap:.5rem;color:rgba(var(--text-color), 0.7);font-size:.9rem}#sheet_editors .editor{padding:.4rem .6rem;border-radius:.4rem;background:rgba(var(--text-color), 0.06)}#go_to_home{height:2.4rem;width:2.4rem;padding:.7rem;cursor:pointer}#go_to_home,#go_to_home+h5{transform:translateX(-1rem);cursor:pointer}#go_to_home+h5{font-weight:500;opacity:.9}#toggle_details{transform:rotateX(180deg)}#sheet_details{padding:1rem;margin-bottom:1rem}#sheet_details .flex:first-of-type{margin-bottom:1rem}#sheet_details .flex:nth-of-type(2){margin-bottom:1rem}#sheet_details .flex:not(:first-of-type){margin-bottom:.3rem}#sheet_details.collapse{padding:.5rem 1rem;margin-bottom:0}#sheet_details.collapse .flex{margin-bottom:0}#sheet_details.collapse #toggle_details{transform:none}#sheet_details.collapse #sheet_heading{font-size:1.2rem;font-weight:600;opacity:.9}#sheet_details.collapse #sheet_description,#sheet_details.collapse #sheet_editors,#sheet_details.collapse #sheet_type{display:none}#sheet_container{position:relative;overflow:auto;max-height:100%;bottom:0;max-width:100%}table{border-collapse:collapse;position:relative}table input{position:relative;padding:.4rem;border:thin solid rgba(var(--text-color), 0.3);font-size:1rem;width:100%;border-radius:.3rem;background:rgba(var(--text-color), 0.06);color:inherit}table input:disabled{border:rgba(0,0,0,0)}th{position:-webkit-sticky;position:sticky;top:0;background:linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)),rgba(var(--foreground-color), 1);text-align:left;line-height:1;vertical-align:middle;font-weight:500;z-index:1;padding:1rem .8rem;white-space:nowrap;box-shadow:0 .2rem .4rem rgba(0,0,0,.1254901961);cursor:pointer}tr:nth-of-type(2n){background-color:rgba(var(--text-color), 0.04)}td{padding:.4rem .8rem;opacity:.9}.text-field{min-width:20ch;max-width:30ch}.grade-input{width:10ch}th.descending::after,th.ascending::after{display:inline-flex;justify-self:flex-end;position:relative;margin-left:auto;font-size:.8rem}th.descending::after{content:" ▼"}th.ascending::after{content:" ▲"}#group_by::part(popup){min-height:80vh}#group_by sm-select:last-of-type{margin-left:.5rem}#side_bar{position:fixed;transform:translateX(-100%);background:rgba(var(--background-color), 1);bottom:0;top:0}#side_bar>.flex:first-of-type{padding:0 1rem}#side_bar .section-header{margin-bottom:0;background:inherit}#right{position:relative;display:flex;flex-direction:column;overflow:auto;max-height:100vh;background:rgba(var(--foreground-color), 1);-webkit-animation:slide-right .6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);animation:slide-right .6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)}@-webkit-keyframes slide-right{from{transform:translateX(-2rem)}to{transform:translateX(0)}}@keyframes slide-right{from{transform:translateX(-2rem)}to{transform:translateX(0)}}.placeholder{-webkit-animation:placeholder-loading .6s infinite alternate;animation:placeholder-loading .6s infinite alternate;padding:1.5rem 0;width:100%;margin:1.5rem;border-radius:.5rem;background:rgba(var(--text-color), 0.06)}.placeholder#sheet_container{width:calc(100% - 3rem);height:calc(100% - 3rem)}@-webkit-keyframes placeholder-loading{from{opacity:.4}to{opacity:1}}@keyframes placeholder-loading{from{opacity:.4}to{opacity:1}}#people_container{overflow:auto;max-height:calc(100vh - 3.6rem);gap:1.5rem}.person-card{display:grid;align-items:center;grid-template-columns:auto 1fr;grid-template-areas:"initials ." "initials .";cursor:pointer;padding:0 1rem;transition:transform .3s;-webkit-tap-highlight-color:rgba(0,0,0,0)}.person-card:first-of-type{margin-top:1.5rem}.person-card:last-of-type{margin-bottom:2rem}.person-initials{grid-area:initials;display:flex;justify-content:center;height:2.6rem;width:2.6rem;font-size:1.2rem !important;font-weight:500;align-items:center;border-radius:2rem;margin-right:1rem;text-transform:uppercase;opacity:1 !important;color:var(--accent-color);background:rgba(var(--text-color), 0.06)}.person-name{font-size:.9rem;opacity:.9;font-weight:500;text-transform:capitalize}.person-flo-id{opacity:.7;font-weight:400}#user_popup sm-button{margin-top:.5rem}#user_popup section:not(:last-of-type){margin-bottom:1.5rem}#editors_container,#columns_container,#additional_fields{gap:.4rem}#specify_editors{border-top:solid 1px rgba(var(--text-color), 0.2)}#add_editor sm-input,#add_column sm-input,#add_detail sm-input{width:100%}#add_detail{gap:.2rem;grid-template-columns:1fr auto;grid-template-areas:". add" ". add"}#add_detail button{grid-area:add;align-self:flex-end}.editor-card,.column-card,.details-card{border-radius:.3rem;background:rgba(var(--text-color), 0.06)}.editor-card .editor-address,.column-card .editor-address,.details-card .editor-address{font-size:.9rem;font-weight:400;opacity:.8}.editor-card{padding:.4rem .8rem}.column-card{padding:.4rem .6rem}.column-card h5{font-weight:500}.column-card .icon{margin-left:.4rem}.details-card{gap:.2rem;padding:.6rem .8rem;grid-template-columns:1fr auto;grid-template-areas:". close" ". close"}.details-card h4,.details-card h5{margin:0 !important}.details-card h5{font-weight:400;opacity:.8}.details-card h4{font-size:1rem !important}.details-card button{grid-area:close}#save_button{position:fixed;overflow:hidden;bottom:0;left:0;right:0;width:min(100% - 2rem,24rem);padding:1rem;margin:1rem;border-radius:.5rem;border:solid thin rgba(var(--text-color), 0.1);background:rgba(var(--foreground-color), 1);z-index:20;box-shadow:0 1rem 2rem rgba(0,0,0,.16)}#save_button #changes_indicator{position:absolute;left:0;width:.3rem;border-radius:0 .5rem .5rem 0;height:2em;background:red}#save_button sm-button{margin-left:1rem}@media screen and (max-width: 640px){#group_by_view{overflow:auto;max-width:calc(100vw - 3rem)}}@media screen and (min-width: 640px){.hide-on-desktop{display:none}sm-popup{--width: 24rem}.popup__header{padding:1.5rem 1.5rem 0 .75rem}#sign_in_page{grid-auto-flow:column}#sign_in_page .sign-in-box{width:26rem;padding:2rem;min-height:80vh;min-width:26rem;border-radius:.5rem;box-shadow:0 0 .3rem rgba(0,0,0,.0862745098),0 6rem 2rem -2rem rgba(0,0,0,.0862745098);background:rgba(var(--foreground-color), 1)}#main_header{padding:1.2rem 3rem}#home_page,#main_header{grid-template-columns:1fr 80vw 1fr;grid-template-areas:". main ."}#main_section,#main_header>div{grid-area:main}#sheets_container{gap:2rem;grid-template-columns:repeat(auto-fill, minmax(11rem, 1fr))}#sheet_view.toggle-side-bar{grid-template-columns:19rem 1fr}#sheet_view.toggle-side-bar #side_bar{z-index:initial}#sheet_view:not(.toggle-side-bar) #side_bar{grid-template-columns:1fr;position:fixed;transform:translateX(-100%)}#side_bar{position:relative;transform:none}#group_by::part(popup){width:80vw}#save_button{margin:1rem auto}}@media screen and (min-width: 1920px){#home_page,#main_header{grid-template-columns:1fr 60vw 1fr;grid-template-areas:". main ."}}@media(any-hover: hover){:root{scrollbar-width:thin}::-webkit-scrollbar{width:.7rem;height:.7rem}::-webkit-scrollbar-track{border-radius:10px}::-webkit-scrollbar-thumb{border-radius:10px;background:rgba(var(--text-color), 0.2)}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.4)}#people_container::-webkit-scrollbar{width:.4rem}#right{z-index:1;box-shadow:-0.5rem 0 .5rem rgba(0,0,0,.062745098)}}.hidden{display:none} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss index 9c225e0..45d4600 100644 --- a/css/main.scss +++ b/css/main.scss @@ -1,1091 +1,1371 @@ * { - box-sizing: border-box; - padding: 0; - margin: 0; - font-family: 'Roboto', sans-serif; + padding: 0; + margin: 0; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } + +:root { + font-size: clamp(1rem, 1.2vmax, 1.2rem); +} + +html, body { - --accent-color:#169685; - --text-color: 17, 17, 17; - --text-color-light: 85, 85, 85; - --foreground-color: 255, 255, 255; - --background-color: rgba(var(--foreground-color), 1); - --dark-shade: #f8f8f8; - --error-color: #E53935; - --hue: 172; - --saturation: 74%; - --lightness: 34%; - color: rgba(var(--text-color), 1); - font-size: 16px; - background: var(--dark-shade); - background-size: cover; -} -body[data-theme="dark"]{ - --accent-color: #00e2c4; - --text-color: 238, 238, 238; - --text-color-light: 170, 170, 170; - --foreground-color: 26, 26, 26; - --background-color: #111; - --dark-shade: #080808; - --hue: 172; - --saturation: 70%; - --lightness: 44%; + height: 100%; } +body { + --accent-color: #3d5afe; + --secondary-color: #ffac2e; + --text-color: 20, 20, 20; + --foreground-color: 252, 253, 255; + --background-color: 241, 243, 248; + --danger-color: rgb(255, 75, 75); + --green: #1cad59; + --yellow: rgb(220, 165, 0); + color: rgba(var(--text-color), 1); + background-color: rgba(var(--background-color), 1); + overflow-y: hidden; +} + +body[data-theme="dark"] { + --accent-color: #6d83ff; + --secondary-color: #d60739; + --text-color: 220, 220, 220; + --foreground-color: 27, 28, 29; + --background-color: 21, 22, 22; + --danger-color: rgb(255, 106, 106); + --green: #00e676; + --yellow: rgb(255, 213, 5); + ::-webkit-calendar-picker-indicator { + filter: invert(1); + } +} + +p, +strong { + font-size: 0.9rem; + max-width: 65ch; + line-height: 1.7; + color: rgba(var(--text-color), 0.9); +} + +img { + object-fit: cover; +} + +a:where([class]) { + color: inherit; + text-decoration: none; + + &:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} a { - font-weight: 600; - text-decoration: none; - color: var(--accent-color); + color: var(--accent-color); } -.dark-text { - color: #111; +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} +a.button { + padding: 0.4rem 0.6rem; + border-radius: 0.3rem; + font-size: 0.9rem; + font-weight: 500; + color: inherit; } -h1 { - font-size: 3.5rem; +button, +.button { + user-select: none; + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + -webkit-tap-highlight-color: transparent; + align-items: center; + font-size: 0.9rem; + font-weight: 500; + white-space: nowrap; + padding: 0.8rem; + border-radius: 0.3rem; + justify-content: center; + + &:focus-visible { + outline: var(--accent-color) solid medium; + } + + &:not(:disabled) { + cursor: pointer; + } } -h2 { - font-size: 2rem; +.button { + background-color: rgba(var(--text-color), 0.1); + + &--primary, + &--danger { + color: rgba(var(--background-color), 1) !important; + + .icon { + fill: rgba(var(--background-color), 1); + } + } + + &--primary { + text-transform: capitalize; + background-color: var(--accent-color); + } + + &--danger { + background-color: var(--danger-color); + } + + &--small { + padding: 0.4rem 0.6rem; + } + + &--outlined { + border: solid rgba(var(--text-color), 0.5) 0.1rem; + background-color: rgba(var(--foreground-color), 1); + } + &--transparent { + background-color: transparent; + } } -h3 { - font-size: 1.5rem; +.cta { + text-transform: uppercase; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.05em; + padding: 0.8rem 1rem; } -h4 { - font-size: 1rem; +.icon { + width: 1.2rem; + height: 1.2rem; + fill: rgba(var(--text-color), 0.8); + flex-shrink: 0; } -h5 { - font-size: 0.8rem; +.icon-only { + padding: 0.5rem; + border-radius: 0.3rem; + aspect-ratio: 1/1; } -h1, -h2, -h3, -h4, -h5 { - font-family: 'Poppins', sans-serif; - font-weight: 600; +button:disabled { + opacity: 0.5; } -p { - line-height: 1.5; - max-width: 65ch; - color: rgba(var(--text-color), 0.9); -} -strong{ - font-weight: 500; -} -::-moz-focus-inner { - border: none; -} -.bottom-padding { - padding-bottom: 1.5rem; +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; } -.top-padding { - padding-top: 1em; +details summary { + display: flex; + user-select: none; + cursor: pointer; + align-items: center; + justify-content: space-between; + color: var(--accent-color); } -.bottom-margin { - margin-bottom: 1.5rem; +details[open] { + & summary { + margin-bottom: 1rem; + } + + & > summary .down-arrow { + transform: rotate(180deg); + } } -.top-margin { - margin-top: 1.5rem; +fieldset { + border: none; +} + +input { + accent-color: var(--accent-color); + + &[type="range"] { + &:active { + cursor: grab; + } + } +} + +sm-copy { + font-size: 0.9rem; +} + +sm-input, +sm-textarea { + font-size: 0.9rem; + --border-radius: 0.5rem; + --background-color: rgba(var(--foreground-color), 1); + + button { + .icon { + fill: var(--accent-color); + } + } +} + +sm-textarea { + --max-height: 32ch; +} + +sm-button { + --padding: 0.8rem; + + &[variant="primary"] { + .icon { + fill: rgba(var(--background-color), 1); + } + } + + &[disabled] { + .icon { + fill: rgba(var(--text-color), 0.6); + } + } + + &.danger { + --background: var(--danger-color); + color: rgba(var(--background-color), 1); + } +} + +sm-spinner { + --size: 1.5rem; + --stroke-width: 0.1rem; +} + +sm-form { + --gap: 1rem; +} + +sm-select { + --padding: 0.8rem; + font-size: 0.9rem; + --min-width: 8rem; +} + +sm-option { + font-size: 0.9rem; +} + +strip-select { + --gap: 0; + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.3rem; + padding: 0.3rem; +} + +strip-option { + position: relative; + font-size: 0.8rem; + --border-radius: 0.2rem; + user-select: none; +} + +sm-button { + --border-radius: 0.3rem; + + &[variant="primary"] { + .icon { + fill: rgba(var(--background-color), 1); + } + } + + &[disabled] { + .icon { + fill: rgba(var(--text-color), 0.6); + } + } +} +sm-select { + &[open] { + z-index: 10; + } +} + +ul { + list-style: none; +} + +.overflow-ellipsis { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.wrap-around { + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/-1; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + +.sticky { + position: sticky; +} + +.top-0 { + top: 0; } .flex { - display: flex; + display: flex; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.flex-1 { + flex: 1; } .grid { - display: grid; + display: grid; } -.grid-2 { - grid-template-columns: auto auto; - gap: 1em; +.flow-column { + grid-auto-flow: column; +} + +.gap-0-3 { + gap: 0.3rem; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} +.text-align-left { + text-align: left; +} + +.align-items-start { + align-items: flex-start; +} +.align-content-start { + align-content: flex-start; +} + +.align-start { + align-content: flex-start; } .align-center { - align-items: center; + align-items: center; } -.direction-column { - flex-direction: column; +.align-end { + align-items: flex-end; } -.justify-right{ - margin-left: auto; +.text-center { + text-align: center; +} + +.justify-start { + justify-items: start; +} +.justify-content-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-start { + align-self: start; +} +.align-self-center { + align-self: center; +} + +.align-self-end { + align-self: end; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.flex-direction-column { + flex-direction: column; } .space-between { - justify-content: space-between; + justify-content: space-between; } -.label { - margin-bottom: 0.4rem; +.w-100 { + width: 100%; } -.light-text { - opacity: 0.7; +.h-100 { + height: 100%; } -.hide { - opacity: 0; - pointer-events: none; +.margin-right-0-3 { + margin-right: 0.3rem; +} +.margin-right-0-5 { + margin-right: 0.5rem; } -.hide-completely { - display: none !important; +.margin-left-0-5 { + margin-left: 0.5rem; } -.breakable { - word-break: break-all; +.margin-left-auto { + margin-left: auto; +} +.margin-right-auto { + margin-right: auto; } -.overflow-ellipsis{ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; +.margin-bottom-0-5 { + margin-bottom: 0.5rem; +} +.margin-bottom-1 { + margin-bottom: 1rem; +} +.margin-bottom-2 { + margin-bottom: 2rem; } -.separator { - padding: .1em; +.margin-block-0-5 { + margin-block: 0.5rem; +} +.margin-block-1 { + margin-block: 1rem; +} + +.margin-block-1-5 { + margin-block: 1.5rem; +} + +.margin-inline-1 { + margin-inline: 1rem; +} + +.margin-inline-1-5 { + margin-inline: 1.5rem; +} + +.hidden { + display: none !important; } .no-transformations { - transform: none !important; -} -.capitalize{ - text-transform: capitalize; + transform: none !important; } -span.ripple { - position: absolute; - border-radius: 50%; - transform: scale(0); - animation: ripple 0.6s linear; - background: rgba(var(--text-color), 0.1); -} -@keyframes ripple { - to { - transform: scale(4); - opacity: 0; - } -} -.icon{ - height: 1.2rem; - width: 1.2rem; - overflow: visible; - stroke: rgba(var(--text-color), 1); - opacity: 0.8; - fill: none; - stroke-width: 6; - stroke-linejoin: round; - stroke-linecap: round; +.full-bleed { + grid-column: 1/4; } -sm-popup{ - & > sm-input:not(:last-of-type) { - margin-bottom: 1rem; - } - sm-textarea{ - margin-top: 1rem; - } +.h1 { + font-size: 2.5rem; } -.popup-header{ - padding: 1.5rem; - padding-bottom: 0; - display: flex; - align-items: center; - width: 100%; - .icon{ - margin-right: 1rem; - padding: 0.2rem; - stroke-width: 10; - cursor: pointer; - } - sm-button, button{ - width: auto; - margin-left: auto; - } +.h2 { + font-size: 2rem; } -button { - position: relative; - display: inline-flex; - align-items: center; - justify-content: center; - text-transform: capitalize; - padding: 0.6rem 1.2rem; - font-weight: 600; - cursor: pointer; + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} +.w-100 { + width: 100%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { + font-weight: 400; +} + +.weight-500 { + font-weight: 500; +} + +.card { + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.5rem; + padding: max(1rem, 3vw); +} + +.ripple { + height: 8rem; + width: 8rem; + position: absolute; + border-radius: 50%; + transform: scale(0); + background: radial-gradient( + circle, + rgba(var(--text-color), 0.3) 0%, + rgba(0, 0, 0, 0) 50% + ); + pointer-events: none; +} +.interactive { + 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; +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; + + &--left { + margin-right: 0.5rem; + } + + &--right { + margin-left: 0.5rem; + } +} + +[data-editable] { + transition: padding 0.2s; + &:focus-within { + padding: 0.5em; border-radius: 0.3rem; - color: var(--accent-color); - transition: transform 0.3s; - border: none; - background: rgba(var(--text-color), 0.1); - -webkit-tap-highlight-color: transparent; - font-family: 'Poppins', sans-serif; - &:focus { - outline: thin solid rgba(var(--text-color-light), .4); - } - &:disabled { - cursor: default; - background: rgba(var(--text-color), 0.4); - } + outline: none; + background-color: rgba(var(--text-color), 0.06); + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; + } } -.primary-btn { - background: var(--accent-color); - justify-content: center; - color: rgba(var(--foreground-color), 1); -} -#confirmation{ - flex-direction: column; - h4 { - font-weight: 500; - margin-bottom: 1.5rem; - } +.multi-state-button { + display: grid; + text-align: center; + align-items: center; - .flex { - margin-top: 1rem; - sm-button:first-of-type { - margin-right: 0.6em; - margin-left: auto; - } - } -} -#sign_in_page{ - background: url(sign-in-bg.svg) no-repeat center, linear-gradient(rgba(var(--text-color), 0.04), rgba(var(--text-color), 0.04)), linear-gradient(rgba(var(--foreground-color), 1), rgba(var(--foreground-color), 1)); - background-size: cover; - min-height: 100vh; - width: 100vw; - align-items: center; - padding: 0 6vw; - .info{ - h1{ - font-weight: 800; - font-size: clamp(1.5rem, 8vw, 4rem); - } - h4{ - font-weight: 500; - font-family: 'Roboto', sans-serif; - opacity: 0.8; - } - } - .sign-in-box{ - width: calc(100vw - 4rem); - z-index: 1; - sm-input{ - text-align: left; - } - sm-panel{ - width: 100%; - } - sm-tab-header{ - background: none; - align-self: flex-start; - &::part(tab-header){ - padding-bottom: 0.4rem; - gap: 1.5rem; - } - } - sm-tab::part(tab){ - padding: 0.4rem 0; - } - sm-tab-panels{ - margin-top: 3rem; - } - form{ - width: 100%; - } - h2{ - margin-bottom: 0.5rem; - } - h3{ - font-weight: 500; - } - h4 { - font-weight: 500; - margin-bottom: 1.5rem; - } - h5{ - opacity: 0.8; - font-weight: 500; - } - .copy-row{ - h4{ - max-width: 34ch; - } - } - .copy-row:not(:last-of-type){ - margin-bottom: 1rem; - } - button { - margin-top: 1rem; - padding: 0.6rem 1.6rem; - } - p { - margin-bottom: 0.5rem; - max-width: 35ch; - margin-top: 0.5rem; - margin-bottom: 1.5rem; - } - #credentials_section{ - border-top: 1px rgba(var(--text-color), 0.2) solid; - margin-top: 1rem; - padding-top: 1.5rem; - animation: slide-down 0.3s forwards; - } - } -} -@keyframes slide-down{ - from{ - transform: translateY(-1rem); - } - to{ - transform: none; - } -} -.copy-row { - display: grid; - grid-template-columns: 1fr auto; - align-items: center; - gap: 0.5rem; - width: auto; - h4 { - font-family: 'Roboto', sans-serif; - margin-bottom: 0; - font-weight: 400; - margin: 0 !important; - } - .icon { - cursor: pointer; - padding: 0.4rem; - height: 1.8rem; - width: 1.8rem; - } + & > * { + grid-area: 1/1/2/2; + } - .copy { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + button { + z-index: 1; + } +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; + + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + + sm-button { + margin: 0; + } + + .flex { + padding: 0; + margin-top: 1rem; + + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; } + } +} + +.popup__header { + display: grid; + gap: 0.5rem; + width: 100%; + padding: 0 1.5rem 0 0.5rem; + align-items: center; + grid-template-columns: auto 1fr auto; +} + +.popup__header__close { + padding: 0.5rem; + cursor: pointer; +} + +#sign_in_page { + background: url(sign-in-bg.svg) no-repeat center, + linear-gradient( + rgba(var(--text-color), 0.04), + rgba(var(--text-color), 0.04) + ), + linear-gradient( + rgba(var(--foreground-color), 1), + rgba(var(--foreground-color), 1) + ); + background-size: cover; + min-height: 100vh; + width: 100vw; + align-items: center; + padding: 0 6vw; + .info { + h1 { + font-weight: 800; + font-size: clamp(1.5rem, 8vw, 4rem); + } + h4 { + font-weight: 500; + + opacity: 0.8; + } + } + .sign-in-box { + width: calc(100vw - 4rem); + z-index: 1; + sm-input { + text-align: left; + } + h2 { + margin-bottom: 0.5rem; + } + h3 { + font-weight: 500; + } + h4 { + font-weight: 500; + margin-bottom: 1.5rem; + } + h5 { + opacity: 0.8; + font-weight: 500; + } + p { + margin-bottom: 0.5rem; + max-width: 35ch; + margin-top: 0.5rem; + margin-bottom: 1.5rem; + } + #credentials_section { + border-top: 1px rgba(var(--text-color), 0.2) solid; + margin-top: 1rem; + padding-top: 1.5rem; + animation: slide-down 0.3s forwards; + } + } +} +@keyframes slide-down { + from { + transform: translateY(-1rem); + } + to { + transform: none; + } } #main_loader { - text-align: center; - place-content: center; - height: 100vh; - width: 100vw; - position: fixed; - left: 0; - sm-button { - margin-left: 0; - margin-top: 1rem; - width: max-content; - justify-self: center; - } + text-align: center; + place-content: center; + justify-items: center; + height: 100vh; + width: 100vw; + position: fixed; + left: 0; + gap: 1rem; + sm-button { + margin-left: 0; + margin-top: 1rem; + width: max-content; + justify-self: center; + } - svg { - height: 2rem; - width: 2rem; - stroke: var(--accent-color); - stroke-width: 6; - fill: none; - overflow: visible; - stroke-linecap: round; - stroke-dashoffset: 210; - stroke-dasharray: 210; - justify-self: center; - align-self: center; - margin-bottom: 2rem; - } - - h3 { - width: 100%; - font-weight: 400; - word-spacing: 0.16em; - } + h3 { + width: 100%; + font-weight: 400; + word-spacing: 0.16em; + } } -.loader { - fill: none; - stroke-width: 10; - stroke: var(--accent-color); +#main_header { + padding: 1rem; + box-shadow: 0 0.1rem 0.2rem #00000010; + background: rgba(var(--foreground-color), 1); + h5 { + font-weight: 500; + + opacity: 0.8; + } + h4 { + font-size: 1.2rem; + } +} +#home_page { + padding: 1rem 1.5rem; +} +.section-header { + position: sticky; + top: 0; + z-index: 1; + background: var(--dark-shade); + padding: 1rem 0; + margin-bottom: 1rem; + h4 { + font-size: 1.2rem; + opacity: 0.8; + font-weight: 500; + } +} + +#main_section { + & > header { + sm-input { + margin-left: 1rem; + } + } +} + +#user_icon { + width: 2.4rem; + height: 2.4rem; + padding: 0.6rem; + border-radius: 2rem; +} + +#sheets_container { + gap: 2rem 1.5rem; + grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); + margin-bottom: 3rem; + animation: slide-up 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@keyframes slide-up { + from { + transform: translateY(2rem); + } + to { + transform: none; + } +} + +#add_new_sheet { + .icon { height: 2rem; width: 2rem; - overflow: visible; - stroke-dashoffset: 230; - stroke-dasharray: 230; - padding: 2px; - justify-self: center; -} - -.animate-loader { - animation: load 2.6s infinite, rotate 1s infinite linear; -} - -@keyframes rotate { - 100% { - transform: rotate(360deg); - } -} - -@keyframes load { - 50% { - stroke-dashoffset: 0; - } - - 100% { - stroke-dashoffset: -210; - } -} - -#main_header{ - padding: 1rem; - box-shadow: 0 0.1rem 0.2rem #00000010; - background: rgba(var(--foreground-color), 1); - h5{ - font-weight: 500; - font-family: 'Roboto', sans-serif; - opacity: 0.8; - } - h4{ - font-size: 1.2rem; - } -} -#home_page{ - padding: 1rem 1.5rem; -} -.section-header{ - position: sticky; - top: 0; - z-index: 1; - background: var(--dark-shade); - padding: 1rem 0; - margin-bottom: 1rem; - h4{ - font-size: 1.2rem; - opacity: 0.8; - font-weight: 500; - } -} - -#main_section{ - & > header{ - sm-input{ - margin-left: 1rem; - } - } -} - -#user_icon{ - width: 2.4rem; - height: 2.4rem; - padding: 0.6rem; - cursor: pointer; - background: rgba(var(--text-color), 0.1); - border-radius: 2rem; -} - -#sheets_container{ - gap: 2rem 1.5rem; - grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); - margin-bottom: 3rem; - animation: slide-up 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -@keyframes slide-up{ - from{ - transform: translateY(2rem); - } - to{ - transform: none; - } -} - -#add_new_sheet{ - .icon{ - height: 2rem; - width: 2rem; - stroke-width: 10; - stroke: #fff; - stroke-linecap: square; - opacity: 1; - top: 50%; - transform: translateY(-50%); - position: absolute; - } - .card{ - display: flex; - align-items: center; - justify-content: center; - position: relative; - background: url(card-bg1.svg), #A7003E; - background-size: cover; - } -} - -.sheet-card{ - position: relative; + stroke-width: 10; + stroke: #fff; + stroke-linecap: square; + opacity: 1; + top: 50%; + transform: translateY(-50%); + position: absolute; + } + .card { display: flex; - flex-direction: column; align-items: center; - cursor: pointer; - &:active .card{ - transform: scale(0.95); - } - .card{ - position: relative; - border-radius: 0.4rem; - background: url(card-bg2.svg) center, rgba(var(--text-color), 0.06); - background-size: contain; - padding: 1rem; - padding-top: 66%; - width: 100%; - transition: box-shadow 0.3s, transform 0.3s; - } - h4{ - font-family: 'Roboto', sans-serif; - font-weight: 400; - opacity: 0.9; - margin-top: 0.8rem; - text-align: center; - max-width: 90%; - } - h5{ - font-family: 'Roboto', sans-serif; - background: rgba(var(--text-color), 0.1); - position: absolute; - top: 0; - right: 0; - margin: 0.5rem 0; - padding: 0.4rem 0.6rem; - border-radius: .2rem 0 0 .2rem; - font-weight: 500; - opacity: 0.8; - } + justify-content: center; + position: relative; + background: url(card-bg1.svg), #a7003e; + background-size: cover; + } } -#sheet_page{ - width: 100vw; - height: 100vh; - overflow-x: hidden; - &.toggle-side-bar #side_bar{ - transition: transform 0.3s; - z-index: 10; - transform: none; - } -} -#sheet_heading{ - font-weight: 600; - opacity: 0.9; -} -#sheet_type{ - padding: 0.3rem 0.6rem; - border-radius: 0.3rem; - margin: 0 1rem; - font-weight: 500; - opacity: 0.8; - background: rgba(var(--text-color), 0.1); -} -#sheet_description{ - margin-top: 0.8rem; - opacity: 0.8; -} -#sheet_editors{ - gap: 0.5rem; - flex-wrap: wrap; - color: rgba(var(--text-color), 0.7); - font-size: 0.9rem; - .editor{ - padding: 0.4rem 0.6rem; - border-radius: 0.4rem; - background: rgba(var(--text-color), 0.06); - } -} -#toggle_details, #go_to_home{ - height: 2.4rem; - width: 2.4rem; - padding: 0.7rem; - cursor: pointer; -} -#go_to_home, #go_to_home + h5{ - transform: translateX(-1rem); - cursor: pointer; -} -#go_to_home + h5{ - font-weight: 500; - opacity: 0.9; -} -#toggle_details{ - transform: rotateX(180deg); - transition: transform 0.3s; -} -#sheet_details{ +.sheet-card { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + color: inherit; + .card { + position: relative; + border-radius: 0.5rem; + background: url(card-bg2.svg) center, rgba(var(--text-color), 0.06); + background-size: contain; padding: 1rem; - margin-bottom: 1rem; - .flex:first-of-type{ - margin-bottom: 1rem; - } - .flex:nth-of-type(2){ - margin-bottom: 1rem; - } - .flex:not(:first-of-type){ - margin-bottom: 0.3rem; - .icon{ - cursor: pointer; - margin-right: 1rem; - height: 100%; - } - } - &.collapse{ - padding: 0.5rem 1rem; - margin-bottom: 0; - .flex{ - margin-bottom: 0; - } - #toggle_details{ - transform: none; - } - #sheet_heading{ - font-size: 1.2rem; - font-weight: 600; - opacity: 0.9; - } - #sheet_description, - #sheet_editors, - #sheet_type{ - display: none; - } - } -} -#sheet_container{ - position: relative; - overflow: auto; - max-height: 100%; - bottom: 0; - max-width: 100%; -} -sm-select::part(options){ - max-height: 50vh; -} -table{ - border-collapse: collapse; - position: relative; - input{ - position: relative; - padding: 0.4rem; - border: thin solid rgba(var(--text-color), 0.3); - font-size: 1rem; - width: 100%; - border-radius: 0.3rem; - background: rgba(var(--text-color), 0.06); - color: inherit; - &:disabled{ - border: transparent; - } - } -} -th{ - position: sticky; - top: 0; - background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), rgba(var(--foreground-color), 1); - text-align: left; - line-height: 1; - vertical-align: middle; - font-weight: 500; - z-index: 1; - padding: 1rem 0.8rem; - white-space: nowrap; - box-shadow: 0 0.2rem 0.4rem #00000020; - cursor: pointer; -} -tr{ - &:nth-of-type(2n){ - background-color: rgba(var(--text-color), 0.04); - } -} -td{ - padding: 0.4rem 0.8rem; + padding-top: 66%; + width: 100%; + transition: box-shadow 0.3s, transform 0.3s; + } + h4 { + font-weight: 400; opacity: 0.9; + margin-top: 0.8rem; + text-align: center; + max-width: 90%; + } + h5 { + background: rgba(var(--text-color), 0.1); + position: absolute; + top: 0; + right: 0; + margin: 0.5rem 0; + padding: 0.4rem 0.6rem; + border-radius: 0.2rem 0 0 0.2rem; + font-weight: 500; + opacity: 0.8; + } } -.text-field{ - min-width: 20ch; - max-width: 30ch; + +#sheet_view { + width: 100vw; + height: 100vh; + overflow-x: hidden; + &.toggle-side-bar #side_bar { + transition: transform 0.3s; + z-index: 10; + transform: none; + } } -.grade-input{ - width: 10ch; +#sheet_heading { + font-weight: 600; + opacity: 0.9; +} +#sheet_type { + padding: 0.3rem 0.6rem; + border-radius: 0.3rem; + margin: 0 1rem; + font-weight: 500; + opacity: 0.8; + background: rgba(var(--text-color), 0.1); +} +#sheet_description { + margin-top: 0.8rem; + opacity: 0.8; +} +#sheet_editors { + gap: 0.5rem; + color: rgba(var(--text-color), 0.7); + font-size: 0.9rem; + .editor { + padding: 0.4rem 0.6rem; + border-radius: 0.4rem; + background: rgba(var(--text-color), 0.06); + } +} +#go_to_home { + height: 2.4rem; + width: 2.4rem; + padding: 0.7rem; + cursor: pointer; +} +#go_to_home, +#go_to_home + h5 { + transform: translateX(-1rem); + cursor: pointer; +} +#go_to_home + h5 { + font-weight: 500; + opacity: 0.9; +} +#toggle_details { + transform: rotateX(180deg); +} +#sheet_details { + padding: 1rem; + margin-bottom: 1rem; + .flex:first-of-type { + margin-bottom: 1rem; + } + .flex:nth-of-type(2) { + margin-bottom: 1rem; + } + .flex:not(:first-of-type) { + margin-bottom: 0.3rem; + } + &.collapse { + padding: 0.5rem 1rem; + margin-bottom: 0; + .flex { + margin-bottom: 0; + } + #toggle_details { + transform: none; + } + #sheet_heading { + font-size: 1.2rem; + font-weight: 600; + opacity: 0.9; + } + #sheet_description, + #sheet_editors, + #sheet_type { + display: none; + } + } +} +#sheet_container { + position: relative; + overflow: auto; + max-height: 100%; + bottom: 0; + max-width: 100%; +} +table { + border-collapse: collapse; + position: relative; + input { + position: relative; + padding: 0.4rem; + border: thin solid rgba(var(--text-color), 0.3); + font-size: 1rem; + width: 100%; + border-radius: 0.3rem; + background: rgba(var(--text-color), 0.06); + color: inherit; + &:disabled { + border: transparent; + } + } +} +th { + position: sticky; + top: 0; + background: linear-gradient( + rgba(var(--text-color), 0.06), + rgba(var(--text-color), 0.06) + ), + rgba(var(--foreground-color), 1); + text-align: left; + line-height: 1; + vertical-align: middle; + font-weight: 500; + z-index: 1; + padding: 1rem 0.8rem; + white-space: nowrap; + box-shadow: 0 0.2rem 0.4rem #00000020; + cursor: pointer; +} +tr { + &:nth-of-type(2n) { + background-color: rgba(var(--text-color), 0.04); + } +} +td { + padding: 0.4rem 0.8rem; + opacity: 0.9; +} +.text-field { + min-width: 20ch; + max-width: 30ch; +} +.grade-input { + width: 10ch; } th.descending::after, -th.ascending::after{ - display: inline-flex; - justify-self: flex-end; - position: relative; - margin-left: auto; - font-size: 0.8rem; +th.ascending::after { + display: inline-flex; + justify-self: flex-end; + position: relative; + margin-left: auto; + font-size: 0.8rem; } -th.descending::after{ - content: " \25BC"; +th.descending::after { + content: " \25BC"; } -th.ascending::after{ - content: ' \25B2'; +th.ascending::after { + content: " \25B2"; } -#group_by{ - &::part(popup){ - min-height: 80vh; - } - sm-select:last-of-type{ - margin-left: 0.5rem; - } +#group_by { + &::part(popup) { + min-height: 80vh; + } + sm-select:last-of-type { + margin-left: 0.5rem; + } } -#side_bar{ - position: fixed; - transform: translateX(-100%); - background: var(--dark-shade); - & > .flex:first-of-type{ - padding: 0 1rem; - } - .section-header{ - margin-bottom: 0; - background: inherit; - } -} -#right{ - position: relative; - display: flex; - flex-direction: column; - overflow: auto; - max-height: 100vh; - background: rgba(var(--foreground-color), 1); - animation: slide-right 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -@keyframes slide-right{ - from{ - transform: translateX(-2rem); - } - to{ - transform: translateX(0); - } -} - -.placeholder{ - animation: placeholder-loading 0.6s infinite alternate; - padding: 1.5rem 0; - width: 100%; - margin: 1.5rem; - border-radius: 0.5rem; - background: rgba(var(--text-color), 0.06); - &#sheet_container{ - width: calc(100% - 3rem); - height: calc(100% - 3rem); - } -} - -@keyframes placeholder-loading{ - from{ - opacity: 0.4; - } - to{ - opacity: 1; - } -} - -#people_container{ - overflow: auto; - max-height: calc(100vh - 3.6rem); - gap: 1.5rem; -} - -.person-card{ - display: grid; - align-items: center; - grid-template-columns: auto 1fr; - grid-template-areas: 'initials .' 'initials .'; - cursor: pointer; +#side_bar { + position: fixed; + transform: translateX(-100%); + background: rgba(var(--background-color), 1); + bottom: 0; + top: 0; + & > .flex:first-of-type { padding: 0 1rem; - transition: transform 0.3s; - -webkit-tap-highlight-color: transparent; - &:active{ - transform: scale(0.95); - } - &:first-of-type{ - margin-top: 1.5rem; - } - &:last-of-type{ - margin-bottom: 2rem; - } + } + .section-header { + margin-bottom: 0; + background: inherit; + } } -.person-initials{ - grid-area: initials; - display: flex; - justify-content: center; - height: 2.6rem; - width: 2.6rem; - font-size: 1.2rem !important; - font-weight: 500; - align-items: center; - border-radius: 2rem; - margin-right: 1rem; - text-transform: uppercase; - opacity: 1 !important; - color: var(--accent-color); - background: rgba(var(--text-color), 0.06); -} -.person-name{ - font-size: 0.9rem; - opacity: 0.9; - font-weight: 500; - text-transform: capitalize; -} -.person-flo-id{ - opacity: 0.7; - font-weight: 400; +#right { + position: relative; + display: flex; + flex-direction: column; + overflow: auto; + max-height: 100vh; + background: rgba(var(--foreground-color), 1); + animation: slide-right 0.6s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); } -#user_popup{ - sm-button{ - margin-top: 0.5rem; - } - section:not(:last-of-type){ - margin-bottom: 1.5rem; - } +@keyframes slide-right { + from { + transform: translateX(-2rem); + } + to { + transform: translateX(0); + } } -#new_sheet_popup{ - p{ - font-size: 0.9rem; - } +.placeholder { + animation: placeholder-loading 0.6s infinite alternate; + padding: 1.5rem 0; + width: 100%; + margin: 1.5rem; + border-radius: 0.5rem; + background: rgba(var(--text-color), 0.06); + &#sheet_container { + width: calc(100% - 3rem); + height: calc(100% - 3rem); + } } -#specify_columns, -#specify_editors, -#specify_details{ - h4{ - font-weight: 500; - font-size: 0.9rem; - margin-bottom: 0.2rem; - } - gap: 1rem; - margin-top: 1rem; - padding-top: 1rem; +@keyframes placeholder-loading { + from { + opacity: 0.4; + } + to { + opacity: 1; + } } -#columns_container{ - flex-wrap: wrap; + +#people_container { + overflow: auto; + max-height: calc(100vh - 3.6rem); + gap: 1.5rem; +} + +.person-card { + display: grid; + align-items: center; + grid-template-columns: auto 1fr; + grid-template-areas: "initials ." "initials ."; + cursor: pointer; + padding: 0 1rem; + transition: transform 0.3s; + -webkit-tap-highlight-color: transparent; + &:first-of-type { + margin-top: 1.5rem; + } + &:last-of-type { + margin-bottom: 2rem; + } +} +.person-initials { + grid-area: initials; + display: flex; + justify-content: center; + height: 2.6rem; + width: 2.6rem; + font-size: 1.2rem !important; + font-weight: 500; + align-items: center; + border-radius: 2rem; + margin-right: 1rem; + text-transform: uppercase; + opacity: 1 !important; + color: var(--accent-color); + background: rgba(var(--text-color), 0.06); +} +.person-name { + font-size: 0.9rem; + opacity: 0.9; + font-weight: 500; + text-transform: capitalize; +} +.person-flo-id { + opacity: 0.7; + font-weight: 400; +} + +#user_popup { + sm-button { + margin-top: 0.5rem; + } + section:not(:last-of-type) { + margin-bottom: 1.5rem; + } } #editors_container, #columns_container, -#additional_fields{ - gap: 0.4rem; +#additional_fields { + gap: 0.4rem; } -#specify_editors{ - border-top: solid 1px rgba(var(--text-color), 0.2); +#specify_editors { + border-top: solid 1px rgba(var(--text-color), 0.2); } #add_editor, #add_column, -#add_detail{ - sm-input{ - width: 100%; - } - .icon{ - height: 3rem; - width: 3rem; - padding: 1rem; - cursor: pointer; - } +#add_detail { + sm-input { + width: 100%; + } } -#add_detail{ - gap: 0.2rem; - grid-template-columns: 1fr auto; - grid-template-areas: '. add' '. add'; - .icon{ - grid-area: add; - align-self: flex-end; - } +#add_detail { + gap: 0.2rem; + grid-template-columns: 1fr auto; + grid-template-areas: ". add" ". add"; + button { + grid-area: add; + align-self: flex-end; + } } .editor-card, .column-card, -.details-card{ - border-radius: 0.3rem; - background: rgba(var(--text-color), 0.06); - .icon{ - padding: 0.3rem; - cursor: pointer; - } - .editor-address{ - font-family: 'Roboto', sans-serif; - font-size: 0.9rem; - font-weight: 400; - opacity: 0.8; - } +.details-card { + border-radius: 0.3rem; + background: rgba(var(--text-color), 0.06); + .editor-address { + font-size: 0.9rem; + font-weight: 400; + opacity: 0.8; + } } -.editor-card{ - padding: 0.4rem 0.8rem; +.editor-card { + padding: 0.4rem 0.8rem; } -.column-card{ - padding: 0.4rem 0.6rem; - h5{ - font-weight: 500; - font-family: 'Roboto', sans-serif; - } - .icon{ - margin-left: 0.4rem; - } +.column-card { + padding: 0.4rem 0.6rem; + h5 { + font-weight: 500; + } + .icon { + margin-left: 0.4rem; + } } -.details-card{ - gap: 0.2rem; - padding: 0.6rem 0.8rem; - grid-template-columns: 1fr auto; - grid-template-areas: '. close' '. close'; - h4, h5{ - font-family: 'Roboto', sans-serif; - margin: 0 !important; - } - h5{ - font-weight: 400; - opacity: 0.8; - } - h4{ - font-size: 1rem !important; - } - .icon{ - grid-area: close; - } +.details-card { + gap: 0.2rem; + padding: 0.6rem 0.8rem; + grid-template-columns: 1fr auto; + grid-template-areas: ". close" ". close"; + h4, + h5 { + margin: 0 !important; + } + h5 { + font-weight: 400; + opacity: 0.8; + } + h4 { + font-size: 1rem !important; + } + button { + grid-area: close; + } } -#save_button{ - position: fixed; - overflow: hidden; - bottom: 0; +#save_button { + position: fixed; + overflow: hidden; + bottom: 0; + left: 0; + right: 0; + width: min(calc(100% - 2rem), 24rem); + padding: 1rem; + margin: 1rem; + border-radius: 0.5rem; + border: solid thin rgba(var(--text-color), 0.1); + background: rgba(var(--foreground-color), 1); + z-index: 20; + box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.16); + #changes_indicator { + position: absolute; left: 0; - width: calc(100% - 2rem); - padding: 1rem; - margin: 1rem; - border-radius: 0.4rem; - background: rgba(var(--foreground-color), 1); - z-index: 20; - box-shadow: 0 0.1rem 0.1rem #00000010, 0 0 1rem #00000016; - transform: translateY(1rem); - transition: transform 0.3s, opacity 0.3s; - #changes_indicator{ - position: absolute; - left: 0; - width: 0.5rem; - height: 100%; - background: red; - } - sm-button{ - margin-left: 1rem; - } + width: 0.3rem; + border-radius: 0 0.5rem 0.5rem 0; + height: 2em; + background: red; + } + sm-button { + margin-left: 1rem; + } } -@media screen and (max-width: 640px){ - #group_by_view{ - overflow: auto; - max-width: calc(100vw - 3rem); - } +@media screen and (max-width: 640px) { + #group_by_view { + overflow: auto; + max-width: calc(100vw - 3rem); + } } -@media screen and (min-width: 640px){ - .hide-on-desktop{ - display: none; - } - sm-popup::part(popup){ - width: 24rem; - } - #sign_in_page{ - grid-auto-flow: column; - .sign-in-box{ - width: 26rem; - padding: 2rem; - min-height: 80vh; - min-width: 26rem; - border-radius: 0.5rem; - box-shadow: 0 0 0.3rem #00000016, 0 6rem 2rem -2rem #00000016; - background: rgba(var(--foreground-color), 1); - } - } - #main_header{ - padding: 1.2rem 3rem; - } - #home_page, #main_header{ - grid-template-columns: 1fr 80vw 1fr; - grid-template-areas: '. main .'; - } - #main_section, - #main_header > div{ - grid-area: main; +@media screen and (min-width: 640px) { + .hide-on-desktop { + display: none; + } + sm-popup { + --width: 24rem; + } + .popup__header { + padding: 1.5rem 1.5rem 0 0.75rem; + } + #sign_in_page { + grid-auto-flow: column; + .sign-in-box { + width: 26rem; + padding: 2rem; + min-height: 80vh; + min-width: 26rem; + border-radius: 0.5rem; + box-shadow: 0 0 0.3rem #00000016, 0 6rem 2rem -2rem #00000016; + background: rgba(var(--foreground-color), 1); } + } + #main_header { + padding: 1.2rem 3rem; + } + #home_page, + #main_header { + grid-template-columns: 1fr 80vw 1fr; + grid-template-areas: ". main ."; + } + #main_section, + #main_header > div { + grid-area: main; + } - #sheets_container{ - gap: 2rem; - grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); + #sheets_container { + gap: 2rem; + grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); + } + #sheet_view { + &.toggle-side-bar { + grid-template-columns: 19rem 1fr; + #side_bar { + z-index: initial; + } } - #sheet_page{ - &.toggle-side-bar{ - grid-template-columns: 19rem 1fr; - #side_bar{ - z-index: initial; - } - } - &:not(.toggle-side-bar) #side_bar{ - grid-template-columns: 1fr; - position: fixed; - transform: translateX(-100%); - } + &:not(.toggle-side-bar) #side_bar { + grid-template-columns: 1fr; + position: fixed; + transform: translateX(-100%); } - #side_bar{ - position: relative; - transform: none; - } - #group_by{ - &::part(popup){ - width: 80vw; - } - } - #save_button{ - width: auto; + } + #side_bar { + position: relative; + transform: none; + } + #group_by { + &::part(popup) { + width: 80vw; } + } + #save_button { + margin: 1rem auto; + } } -@media screen and (min-width: 1920px){ - #home_page, #main_header{ - grid-template-columns: 1fr 60vw 1fr; - grid-template-areas: '. main .'; - } +@media screen and (min-width: 1920px) { + #home_page, + #main_header { + grid-template-columns: 1fr 60vw 1fr; + grid-template-areas: ". main ."; + } } -@media (any-hover: hover){ - :root{ - scrollbar-width: thin; +@media (any-hover: hover) { + :root { + scrollbar-width: thin; + } + ::-webkit-scrollbar { + width: 0.7rem; + height: 0.7rem; + } + + ::-webkit-scrollbar-track { + border-radius: 10px; + } + + ::-webkit-scrollbar-thumb { + border-radius: 10px; + background: rgba(var(--text-color), 0.2); + &:hover { + background: rgba(var(--text-color), 0.4); } - ::-webkit-scrollbar { - width: 0.7rem; - height: 0.7rem; - } - - ::-webkit-scrollbar-track { - border-radius: 10px; - } - - ::-webkit-scrollbar-thumb { - border-radius: 10px; - background: rgba(var(--text-color), 0.2); - &:hover{ - background: rgba(var(--text-color), 0.4); - } - } - #people_container::-webkit-scrollbar{ - width: 0.4rem; - } - #right{ - z-index: 1; - box-shadow: -0.5rem 0 0.5rem #00000010; - } -} \ No newline at end of file + } + #people_container::-webkit-scrollbar { + width: 0.4rem; + } + #right { + z-index: 1; + box-shadow: -0.5rem 0 0.5rem #00000010; + } +} +.hidden { + display: none; +} diff --git a/index.html b/index.html index 83cc429..86def48 100644 --- a/index.html +++ b/index.html @@ -5,10 +5,11 @@ FLO LogSheet - - + + + + + - - - + + + +

- Cancel - OK + Cancel + OK
- -

Some input required

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

Loading RanchiMall FLO LogSheet

Sign Out
- - - - -
-

My FLO address

-
-

- - Copy - - - -
- Sign out -
-
-

Theme

-
-

Turn dark theme on/off.

- -
-
-
- - - - - - -
-
-

Additional details

-

Add more details about a person. Specify type of information and actual detail.

-
-
-
- - - - Add detail - - -
-
-
- - - - - -
-
-

Add Columns

-

Columns will be added as the order you added them.

-
-
-
- - - Add this column - - -
-
-
- Make sheet private - -
-
-
-

Add editors

-

Only specified editors will be able to update this sheet.

-
-
-
- - - Add this editor - - -
-
-
- - - - -
- - Count - Total - Avg - Max - Min - - -
-
-
- -
+ @@ -271,69 +106,62 @@

LogSheet

Open • Distributed • Reliable

-
- - Sign In - Sign Up - - - +
-
-
+
+
RanchiMall

FLO LogSheet

- - user - - - + +
-
+ -
+ + + + +
+
+
+ My FLO address + +
+ +
+
+
+ + + + + +
+ + +
+
+
+

Additional details

+

Add more details about a person. Specify type of information and actual detail.

+
+
+
+ + + +
+
+ +
+
+ + + + + + +
+
+

Add Columns

+

Columns will be added as the order you added them.

+
+
+
+ + +
+
+
+ Make sheet private + +
+ + +
+
+ + + + +
+ + Count + Total + Avg + Max + Min + + +
+
+
+ diff --git a/scripts/logsheet.js b/scripts/logsheet.js index a361074..205511e 100644 --- a/scripts/logsheet.js +++ b/scripts/logsheet.js @@ -1,9 +1,9 @@ -(function() { +(function () { 'use strict'; const logSheet = window.logSheet = {}; const TYPE_SHEET_ENTRY = "sheet_entry"; - logSheet.init = function() { + logSheet.init = function () { return new Promise((resolve, reject) => { floCloudAPI.requestObjectData("logSheet").then(result => { if (!floGlobals.appObjects.logSheet || typeof floGlobals.appObjects.logSheet !== "object") @@ -16,7 +16,7 @@ }).catch(error => reject(error)) }) } - logSheet.addPerson = function(floID, name, otherDetails = {}) { + logSheet.addPerson = function (floID, name, otherDetails = {}) { if (floGlobals.appObjects.logSheet.personDetails[floID]) throw ("floID already exist") floGlobals.appObjects.logSheet.personDetails[floID] = {}; @@ -29,13 +29,13 @@ } } - logSheet.rmPerson = function(floID) { + logSheet.rmPerson = function (floID) { if (!floGlobals.appObjects.logSheet.personDetails[floID]) throw ("floID not found") delete floGlobals.appObjects.logSheet.personDetails[floID] } - logSheet.editPerson = function(floID, details) { + logSheet.editPerson = function (floID, details) { if (!floGlobals.appObjects.logSheet.personDetails[floID]) throw ("floID not found") for (d in details) { @@ -48,17 +48,17 @@ } } - logSheet.listPersons = function() { + logSheet.listPersons = function () { return floGlobals.appObjects.logSheet.personDetails } - logSheet.viewPerson = function(floID) { + logSheet.viewPerson = function (floID) { if (!floGlobals.appObjects.logSheet.personDetails[floID]) throw ("floID not found") return floGlobals.appObjects.logSheet.personDetails[floID] } - logSheet.createNewSheet = function(title, description, attributes, editors = floGlobals.subAdmins) { + logSheet.createNewSheet = function (title, description, attributes, editors = floGlobals.subAdmins) { let sheet_id = floCrypto.tmpID; floGlobals.appObjects.logSheet.sheetList[sheet_id] = { title: title, @@ -69,7 +69,7 @@ return sheet_id; } - logSheet.manageSheetControl = function(sheet_id, addList, rmList) { + logSheet.manageSheetControl = function (sheet_id, addList, rmList) { if (addList === null && rmList === null) { floGlobals.appObjects.logSheet.sheetList[sheet_id].editors = null return @@ -82,15 +82,15 @@ floGlobals.appObjects.logSheet.sheetList[sheet_id].editors = editorList } - logSheet.editSheetDescription = function(sheet_id, description) { + logSheet.editSheetDescription = function (sheet_id, description) { floGlobals.appObjects.logSheet.sheetList[sheet_id].description = description } - logSheet.listSheets = function() { + logSheet.listSheets = function () { return floGlobals.appObjects.logSheet.sheetList } - logSheet.commitUpdates = function() { + logSheet.commitUpdates = function () { return new Promise((resolve, reject) => { if (!floGlobals.subAdmins.includes(floDapps.user.id)) reject("Access Denied! only subAdmins can commit") @@ -100,7 +100,7 @@ }) } - logSheet.enterLog = function(sheet_id, floID, log) { + logSheet.enterLog = function (sheet_id, floID, log) { return new Promise((resolve, reject) => { if (floGlobals.appObjects.logSheet.sheetList[sheet_id].editors) { if (!floGlobals.appObjects.logSheet.sheetList[sheet_id].editors.includes(floDapps.user.id)) @@ -110,16 +110,16 @@ } else if (!floGlobals.subAdmins.includes(floDapps.user.id) && floID != floDapps.user.id) return reject("Public authorized to log their own floID only"); floCloudAPI.sendGeneralData({ - floID, - log - }, TYPE_SHEET_ENTRY, { - receiverID: sheet_id - }).then(result => resolve(result)) + floID, + log + }, TYPE_SHEET_ENTRY, { + receiverID: sheet_id + }).then(result => resolve(result)) .catch(error => reject(error)) }) } - logSheet.gradeLog = function(sheet_id, vc, grade) { + logSheet.gradeLog = function (sheet_id, vc, grade) { return new Promise((resolve, reject) => { //reject if user is not subAdmin or editor if (!floGlobals.subAdmins.includes(floDapps.user.id) || @@ -136,27 +136,27 @@ return reject("Cannot grade own log") floCloudAPI.tagApplicationData(vc, grade, { - receiverID: sheet_id - }).then(result => resolve(result)) + receiverID: sheet_id + }).then(result => resolve(result)) .catch(error => reject(error)) }) } - logSheet.refreshLogs = function(sheet_id) { + logSheet.refreshLogs = function (sheet_id) { return new Promise((resolve, reject) => { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) reject("Sheet not found") else { floCloudAPI.requestGeneralData(TYPE_SHEET_ENTRY, { - senderIDs: floGlobals.appObjects.logSheet.sheetList[sheet_id].editors, - receiverID: sheet_id - }).then(result => resolve(result)) + senderIDs: floGlobals.appObjects.logSheet.sheetList[sheet_id].editors, + receiverID: sheet_id + }).then(result => resolve(result)) .catch(error => reject(error)) } }) } - logSheet.viewLogs = function(sheet_id) { + logSheet.viewLogs = function (sheet_id) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let sheet = [], @@ -191,7 +191,7 @@ } const groupBy = logSheet.groupBy = {}; - groupBy.count = function(sheet_id, sheet) { + groupBy.count = function (sheet_id, sheet) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let group = {}; @@ -204,7 +204,7 @@ return group; } - groupBy.total = function(sheet_id, sheet, attribute) { + groupBy.total = function (sheet_id, sheet, attribute) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let group = {}; @@ -221,7 +221,7 @@ return group; } - groupBy.avg = function(sheet_id, sheet, attribute) { + groupBy.avg = function (sheet_id, sheet, attribute) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let group = {}; @@ -240,12 +240,12 @@ } } }) - for (floID in group) + for (const floID in group) group[floID] = group[floID].total / group[floID].count return group; } - groupBy.min = function(sheet_id, sheet, attribute) { + groupBy.min = function (sheet_id, sheet, attribute) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let group = {}; @@ -262,7 +262,7 @@ return group; } - groupBy.max = function(sheet_id, sheet, attribute) { + groupBy.max = function (sheet_id, sheet, attribute) { if (!(sheet_id in floGlobals.appObjects.logSheet.sheetList)) throw ("Sheet not found") let group = {};