diff --git a/components.js b/components.js index ed0f281..8d184c5 100644 --- a/components.js +++ b/components.js @@ -1,3545 +1,4058 @@ -//Button -const smButton = document.createElement('template') -smButton.innerHTML = ` - -`; -customElements.define('sm-button', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smButton.content.cloneNode(true)) - } - - get disabled() { - return this.isDisabled - } - - set disabled(value) { - if (value && !this.isDisabled) { - this.isDisabled = true - this.setAttribute('disabled', '') - this.button.removeAttribute('tabindex') - } else if (!value && this.isDisabled) { - this.isDisabled = false - this.removeAttribute('disabled') - } - } - - dispatch() { - if (this.isDisabled) { - this.dispatchEvent(new CustomEvent('disabled', { - bubbles: true, - composed: true - })) - } else { - this.dispatchEvent(new CustomEvent('clicked', { - bubbles: true, - composed: true - })) - } - } - - connectedCallback() { - this.isDisabled = false - this.button = this.shadowRoot.querySelector('.button') - if (this.hasAttribute('disabled') && !this.isDisabled) - this.isDisabled = true - this.addEventListener('click', (e) => { - this.dispatch() - }) - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - -
- -
-
-`; -customElements.define('sm-input', - class extends HTMLElement { - - static formAssociated = true; - - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smInput.content.cloneNode(true)) - } - - static get observedAttributes() { - return ['placeholder'] - } - - get value() { - return this.shadowRoot.querySelector('input').value - } - - set value(val) { - this.shadowRoot.querySelector('input').value = val; - this.checkInput() - this.fireEvent() - } - - get placeholder() { - return this.getAttribute('placeholder') - } - - set placeholder(val) { - this.setAttribute('placeholder', val) - } - - get type() { - return this.getAttribute('type') - } - - get isValid() { - return this.shadowRoot.querySelector('input').checkValidity() - } - - get validity() { - return this.shadowRoot.querySelector('input').validity - } - - set disabled(value) { - if (value) - this.shadowRoot.querySelector('.input').classList.add('disabled') - else - this.shadowRoot.querySelector('.input').classList.remove('disabled') - } - set readOnly(value) { - if (value) { - this.shadowRoot.querySelector('input').setAttribute('readonly', '') - this.shadowRoot.querySelector('.input').classList.add('readonly') - } else { - this.shadowRoot.querySelector('input').removeAttribute('readonly') - this.shadowRoot.querySelector('.input').classList.remove('readonly') - } - } - - setValidity = (message) => { - this.feedbackText.textContent = message - } - - showValidity = () => { - this.feedbackText.classList.remove('hide-completely') - } - - hideValidity = () => { - this.feedbackText.classList.add('hide-completely') - } - - focusIn = () => { - this.input.focus() - } - - focusOut = () => { - this.input.blur() - } - - fireEvent = () => { - let event = new Event('input', { - bubbles: true, - cancelable: true, - composed: true - }); - this.dispatchEvent(event); - } - - checkInput = (e) => { - if (!this.readonly) { - if (this.input.value !== '') { - this.clearBtn.classList.remove('hide') - } else { - this.clearBtn.classList.add('hide') - } - } - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') return; - if (this.input.value !== '') { - if (this.animate) - this.inputParent.classList.add('animate-label') - else - this.label.classList.add('hide') - } else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - } - } - - - connectedCallback() { - this.inputParent = this.shadowRoot.querySelector('.input') - this.clearBtn = this.shadowRoot.querySelector('.clear') - this.label = this.shadowRoot.querySelector('.label') - this.feedbackText = this.shadowRoot.querySelector('.feedback-text') - this.valueChanged = false; - this.readonly = false - this.isNumeric = false - this.min - this.max - this.animate = this.hasAttribute('animate') - this.input = this.shadowRoot.querySelector('input') - this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') - if (this.hasAttribute('value')) { - this.input.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('required')) { - this.input.setAttribute('required', '') - } - if (this.hasAttribute('min')) { - let minValue = this.getAttribute('min') - this.input.setAttribute('min', minValue) - this.min = parseInt(minValue) - } - if (this.hasAttribute('max')) { - let maxValue = this.getAttribute('max') - this.input.setAttribute('max', maxValue) - this.max = parseInt(maxValue) - } - if (this.hasAttribute('minlength')) { - const minValue = this.getAttribute('minlength') - this.input.setAttribute('minlength', minValue) - } - if (this.hasAttribute('maxlength')) { - const maxValue = this.getAttribute('maxlength') - this.input.setAttribute('maxlength', maxValue) - } - if (this.hasAttribute('step')) { - const steps = this.getAttribute('step') - this.input.setAttribute('step', steps) - } - if (this.hasAttribute('pattern')) { - this.input.setAttribute('pattern', this.getAttribute('pattern')) - } - if (this.hasAttribute('readonly')) { - this.input.setAttribute('readonly', '') - this.readonly = true - } - if (this.hasAttribute('disabled')) { - this.inputParent.classList.add('disabled') - } - if (this.hasAttribute('error-text')) { - this.feedbackText.textContent = this.getAttribute('error-text') - } - if (this.hasAttribute('type')) { - if (this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric') - this.input.setAttribute('type', 'number') - this.isNumeric = true - } else - this.input.setAttribute('type', this.getAttribute('type')) - } else - this.input.setAttribute('type', 'text') - this.input.addEventListener('input', e => { - this.checkInput(e) - }) - this.clearBtn.addEventListener('click', e => { - this.value = '' - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'placeholder') { - this.shadowRoot.querySelector('.label').textContent = newValue; - this.setAttribute('aria-label', newValue); - } - } - } - }) - -//textarea -const smTextarea = document.createElement('template') -smTextarea.innerHTML = ` - - -`; -customElements.define('sm-textarea', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smTextarea.content.cloneNode(true)) - this.textarea = this.shadowRoot.querySelector('textarea') - } - get value() { - return this.textarea.value - } - set value(val) { - this.textarea.value = val; - this.textareaBox.dataset.value = val - this.checkInput() - this.fireEvent() - } - focusIn = () => { - this.textarea.focus() - } - fireEvent() { - let event = new Event('input', { - bubbles: true, - cancelable: true, - composed: true - }); - this.dispatchEvent(event); - } - checkInput = () => { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; - if (this.textarea.value !== '') { - this.placeholder.classList.add('hide') - } else { - this.placeholder.classList.remove('hide') - } - } - connectedCallback() { - this.textareaBox = this.shadowRoot.querySelector('.textarea') - this.placeholder = this.shadowRoot.querySelector('.placeholder') - - if(this.hasAttribute('placeholder')) - this.placeholder.textContent = this.getAttribute('placeholder') - - if (this.hasAttribute('value')) { - this.textarea.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('required')) { - this.textarea.setAttribute('required', '') - } - if (this.hasAttribute('readonly')) { - this.textarea.setAttribute('readonly', '') - } - if (this.hasAttribute('rows')) { - this.textarea.setAttribute('rows', this.getAttribute('rows')) - } - this.textarea.addEventListener('input', e => { - this.textareaBox.dataset.value = this.textarea.value - this.checkInput() - }) - } - }) - -// tab -const smTab = document.createElement('template') -smTab.innerHTML = ` - -
- -
-`; - -customElements.define('sm-tab', class extends HTMLElement { - constructor() { - super() - this.shadow = this.attachShadow({ - mode: 'open' - }).append(smTab.content.cloneNode(true)) - } -}) - -//chcekbox - -const smCheckbox = document.createElement('template') -smCheckbox.innerHTML = ` - -` -customElements.define('sm-checkbox', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smCheckbox.content.cloneNode(true)) - - this.checkbox = this.shadowRoot.querySelector('.checkbox'); - this.input = this.shadowRoot.querySelector('input') - - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.isDisabled - } - - set disabled(val) { - if (val) { - this.setAttribute('disabled', '') - } else { - this.removeAttribute('disabled') - } - } - - get checked() { - return this.isChecked - } - - set checked(value) { - if (value) { - this.setAttribute('checked', '') - } - else { - this.removeAttribute('checked') - } - } - - set value(val) { - this.val = val - this.setAttribute('value', value) - } - - get value() { - return getAttribute('value') - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - handleKeyup = e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - if (this.hasAttribute('checked')) { - this.input.checked = false - this.removeAttribute('checked') - } - else { - this.input.checked = true - this.setAttribute('checked', '') - } - } - } - handleChange = e => { - if (this.input.checked) { - this.setAttribute('checked', '') - } - else { - this.removeAttribute('checked') - } - } - - connectedCallback() { - this.val = '' - this.addEventListener('keyup', this.handleKeyup) - this.input.addEventListener('change', this.handleChange) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.isDisabled = true - } else { - this.isDisabled = false - } - } - else if (name === 'checked') { - if (this.hasAttribute('checked')) { - this.isChecked = true - this.input.checked = true - } - else { - this.input.checked = false - this.isChecked = false - } - this.dispatch() - } - } - } - disconnectedCallback() { - this.removeEventListener('keyup', this.handleKeyup) - this.removeEventListener('change', this.handleChange) - } -}) - -//switch - -const smSwitch = document.createElement('template') -smSwitch.innerHTML = ` - -` - -customElements.define('sm-switch', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smSwitch.content.cloneNode(true)) - this.switch = this.shadowRoot.querySelector('.switch'); - this.input = this.shadowRoot.querySelector('input') - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.isDisabled - } - - set disabled(val) { - if (val) { - this.setAttribute('disabled', '') - } else { - this.removeAttribute('disabled') - } - } - - get checked() { - return this.isChecked - } - - set checked(value) { - if (value) { - this.setAttribute('checked', '') - } else { - this.removeAttribute('checked') - } - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && !this.isDisabled) { - this.input.click() - } - }) - this.input.addEventListener('click', e => { - if (this.input.checked) - this.checked = true - else - this.checked = false - this.dispatch() - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (this.hasAttribute('disabled')) { - this.disabled = true - } - else { - this.disabled = false - } - } - else if (name === 'checked') { - if (this.hasAttribute('checked')) { - this.isChecked = true - this.input.checked = true - } - else { - this.isChecked = false - this.input.checked = false - } - } - } - } - -}) - -// select -const smSelect = document.createElement('template') -smSelect.innerHTML = ` - -
-
-
- - - -
-
- -
-
`; -customElements.define('sm-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - - collapse() { - this.optionList.animate(this.slideUp, this.animationOptions) - this.optionList.classList.add('hide') - this.chevron.classList.remove('rotate') - this.open = false - } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [{ - transform: `translateY(-0.5rem)` - }, - { - transform: `translateY(0)` - } - ], - this.slideUp = [{ - transform: `translateY(0)` - }, - { - transform: `translateY(-0.5rem)` - } - ], - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' - } - selection.addEventListener('click', e => { - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { - this.setAttribute('value', e.detail.value) - this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true, - detail: { - value: e.detail.value - } - })) - if (previousOption) { - previousOption.classList.remove('check-selected') - } - previousOption = e.target; - } - if (!e.detail.switching) - this.collapse() - - e.target.classList.add('check-selected') - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); - document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { - this.collapse() - } - }) - } -}) - -// option -const smOption = document.createElement('template') -smOption.innerHTML = ` - -
- - - - -
`; -customElements.define('sm-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smOption.content.cloneNode(true)) - } - - sendDetails(switching) { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value'), - switching: switching - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - let validKey = [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight' - ] - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - if (validKey.includes(e.code)) { - e.preventDefault() - this.sendDetails(true) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -// select -const smStripSelect = document.createElement('template') -smStripSelect.innerHTML = ` - -
-
- - Previous - - -
- -
- - Next - - -
-
`; -customElements.define('sm-strip-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smStripSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - scrollLeft = () => { - this.select.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.select.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - connectedCallback() { - let previousOption, - slot = this.shadowRoot.querySelector('slot'); - this.selectContainer = this.shadowRoot.querySelector('.select-container') - this.select = this.shadowRoot.querySelector('.select') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.selectOptions - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.previousArrow.classList.add('hide') - this.previousGradient.classList.add('hide') - } else { - this.previousArrow.classList.remove('hide') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.nextArrow.classList.add('hide') - this.nextGradient.classList.add('hide') - } else { - this.nextArrow.classList.remove('hide') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - - const selectObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - } - }) - - selectObserver.observe(this.selectContainer) - this.addEventListener('optionSelected', e => { - if (previousOption === e.target) return; - if (previousOption) - previousOption.classList.remove('active') - e.target.classList.add('active') - e.target.scrollIntoView({ - behavior: 'smooth', - inline: 'center', - block: 'nearest' - }) - this.setAttribute('value', e.detail.value) - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - previousOption = e.target; - }) - slot.addEventListener('slotchange', e => { - this.selectOptions = slot.assignedElements() - firstElementObserver.observe(this.selectOptions[0]) - lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) - if (this.selectOptions[0]) { - let firstElement = this.selectOptions[0]; - this.setAttribute('value', firstElement.getAttribute('value')) - firstElement.classList.add('active') - previousOption = firstElement; - } - }); - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -// option -const smStripOption = document.createElement('template') -smStripOption.innerHTML = ` - -
- -
`; -customElements.define('sm-strip-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smStripOption.content.cloneNode(true)) - } - sendDetails() { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value') - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -//popup -const smPopup = document.createElement('template') -smPopup.innerHTML = ` - - -`; -customElements.define('sm-popup', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smPopup.content.cloneNode(true)) - - this.allowClosing = false - } - - resumeScrolling = () => { - const scrollY = document.body.style.top; - window.scrollTo(0, parseInt(scrollY || '0') * -1); - setTimeout(() => { - document.body.style.overflow = 'auto'; - document.body.style.top= 'initial' - }, 300); - } - - show = (pinned, popupStack) => { - if (popupStack) - this.popupStack = popupStack - if (this.popupStack && !this.hasAttribute('open')) { - this.popupStack.push({ - popup: this, - permission: pinned - }) - if (this.popupStack.items.length > 1) { - this.popupStack.items[this.popupStack.items.length - 2].popup.classList.add('stacked') - } - this.dispatchEvent( - new CustomEvent("popupopened", { - bubbles: true, - detail: { - popup: this, - popupStack: this.popupStack - } - }) - ) - this.setAttribute('open', '') - this.pinned = pinned - } - this.popupContainer.classList.remove('hide') - this.popup.style.transform = 'none'; - document.body.style.overflow = 'hidden'; - document.body.style.top= `-${window.scrollY}px` - return this.popupStack - } - hide = () => { - if (window.innerWidth < 640) - this.popup.style.transform = 'translateY(100%)'; - else - this.popup.style.transform = 'translateY(3rem)'; - this.popupContainer.classList.add('hide') - this.removeAttribute('open') - if (typeof this.popupStack !== 'undefined') { - this.popupStack.pop() - if (this.popupStack.items.length) { - this.popupStack.items[this.popupStack.items.length - 1].popup.classList.remove('stacked') - } else { - this.resumeScrolling() - } - } else { - this.resumeScrolling() - } - - if (this.inputFields.length) { - setTimeout(() => { - this.inputFields.forEach(field => { - if (field.type === 'radio' || field.tagName === 'SM-CHECKBOX') - field.checked = false - if (field.tagName === 'SM-INPUT' || field.tagName === 'TEXTAREA'|| field.tagName === 'SM-TEXTAREA') - field.value = '' - }) - }, 300); - } - setTimeout(() => { - this.dispatchEvent( - new CustomEvent("popupclosed", { - bubbles: true, - detail: { - popup: this, - popupStack: this.popupStack - } - }) - ) - }, 300); - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.1s' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartY < e.changedTouches[0].clientY) { - this.offset = e.changedTouches[0].clientY - this.touchStartY; - this.touchEndAnimataion = window.requestAnimationFrame(() => this.movePopup()) - } - /*else { - this.offset = this.touchStartY - e.changedTouches[0].clientY; - this.popup.style.transform = `translateY(-${this.offset}px)` - }*/ - } - - handleTouchEnd = (e) => { - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.3s' - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndY - this.touchStartY > this.threshold) { - if (this.pinned) { - this.show() - return - } else - this.hide() - } else { - this.show() - } - } else { - if (this.touchEndY > this.touchStartY) - if (this.pinned) { - this.show() - return - } - else - this.hide() - } - } - - movePopup = () => { - this.popup.style.transform = `translateY(${this.offset}px)` - } - - connectedCallback() { - this.pinned = false - this.popupStack - this.popupContainer = this.shadowRoot.querySelector('.popup-container') - this.popup = this.shadowRoot.querySelector('.popup') - this.popupBodySlot = this.shadowRoot.querySelector('.popup-body slot') - this.offset - this.popupHeader = this.shadowRoot.querySelector('.popup-top') - this.touchStartY = 0 - this.touchEndY = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.touchEndAnimataion; - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - - if (this.hasAttribute('open')) - this.show() - this.popupContainer.addEventListener('mousedown', e => { - if (e.target === this.popupContainer && !this.pinned) { - if (this.pinned) { - this.show() - return - } else - this.hide() - } - }) - - this.popupBodySlot.addEventListener('slotchange', () => { - setTimeout(() => { - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - }, 200); - this.inputFields = this.querySelectorAll('sm-input', 'sm-checkbox', 'textarea', 'sm-textarea', 'radio') - }) - - this.popupHeader.addEventListener('touchstart', (e) => { this.handleTouchStart(e) }, {passive: true}) - this.popupHeader.addEventListener('touchmove', (e) => {this.handleTouchMove(e)}, {passive: true}) - this.popupHeader.addEventListener('touchend', (e) => {this.handleTouchEnd(e)}, {passive: true}) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart, {passive: true}) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove, {passive: true}) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd, {passive: true}) - } -}) - -//carousel - -const smCarousel = document.createElement('template') -smCarousel.innerHTML = ` - - -`; - -customElements.define('sm-carousel', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smCarousel.content.cloneNode(true)) - } - - static get observedAttributes() { - return ['indicator'] - } - - scrollLeft = () => { - this.carousel.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.carousel.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - - 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') - this.availableOptions.forEach(option => { - option.setAttribute('tabindex', '0') - }) - } - } - collapse() { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - this.availableOptions.forEach(option => { - option.removeAttribute('tabindex') - }) - } - } - connectedCallback() { - this.availableOptions - this.containerDimensions - this.optionList = this.shadowRoot.querySelector('.options') - let slot = this.shadowRoot.querySelector('.options slot'), - menu = this.shadowRoot.querySelector('.menu') - this.icon = this.shadowRoot.querySelector('.icon') - this.open = false; - menu.addEventListener('click', e => { - if (!this.open) { - this.expand() - } else { - this.collapse() - } - }) - menu.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - if (!this.open) { - this.expand() - } else { - this.collapse() - } - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.optionList.addEventListener('click', e => { - this.collapse() - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - this.containerDimensions = this.optionList.getBoundingClientRect() - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - } -}) - -// option -const smMenuOption = document.createElement('template') -smMenuOption.innerHTML = ` - -
- -
`; -customElements.define('sm-menu-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smMenuOption.content.cloneNode(true)) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.click() - } - }) - } -}) - -// tab-header - -const smTabHeader = document.createElement('template') -smTabHeader.innerHTML = ` - -
-
- -
-
-
-`; - -customElements.define('sm-tab-header', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smTabHeader.content.cloneNode(true)) - - this.indicator = this.shadowRoot.querySelector('.indicator'); - this.tabSlot = this.shadowRoot.querySelector('slot'); - this.tabHeader = this.shadowRoot.querySelector('.tab-header'); - } - - sendDetails(element) { - this.dispatchEvent( - new CustomEvent("switchtab", { - bubbles: true, - detail: { - target: this.target, - rank: parseInt(element.getAttribute('rank')) - } - }) - ) - } - - moveIndiactor(tabDimensions) { - //if(this.isTab) - this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - //else - //this.indicator.setAttribute('style', `width: calc(${tabDimensions.width}px - 1.6rem); transform: translateX(calc(${ tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px + 0.8rem)`) - } - - connectedCallback() { - if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return; - this.prevTab - this.allTabs - this.activeTab - this.isTab = false - this.target = this.getAttribute('target') - - if (this.hasAttribute('variant') && this.getAttribute('variant') === 'tab') { - this.isTab = true - } - - this.tabSlot.addEventListener('slotchange', () => { - this.tabSlot.assignedElements().forEach((tab, index) => { - tab.setAttribute('rank', index) - }) - }) - this.allTabs = this.tabSlot.assignedElements(); - - this.tabSlot.addEventListener('click', e => { - if (e.target === this.prevTab || !e.target.closest('sm-tab')) - return - if (this.prevTab) - this.prevTab.classList.remove('active') - e.target.classList.add('active') - - e.target.scrollIntoView({ - behavior: 'smooth', - block: 'nearest', - inline: 'center' - }) - this.moveIndiactor(e.target.getBoundingClientRect()) - this.sendDetails(e.target) - this.prevTab = e.target; - this.activeTab = e.target; - }) - let resizeObserver = new ResizeObserver(entries => { - entries.forEach((entry) => { - if (this.prevTab) { - let tabDimensions = this.activeTab.getBoundingClientRect(); - this.moveIndiactor(tabDimensions) - } - }) - }) - resizeObserver.observe(this) - let observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - this.indicator.style.transition = 'none' - if (this.activeTab) { - let tabDimensions = this.activeTab.getBoundingClientRect(); - this.moveIndiactor(tabDimensions) - } else { - this.allTabs[0].classList.add('active') - let tabDimensions = this.allTabs[0].getBoundingClientRect(); - this.moveIndiactor(tabDimensions) - this.sendDetails(this.allTabs[0]) - this.prevTab = this.tabSlot.assignedElements()[0]; - this.activeTab = this.prevTab; - } - } - }) - }, { - threshold: 1.0 - }) - observer.observe(this) - } -}) - -// tab-panels - -const smTabPanels = document.createElement('template') -smTabPanels.innerHTML = ` - -
- Nothing to see here. -
-`; - -customElements.define('sm-tab-panels', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ - mode: 'open' - }).append(smTabPanels.content.cloneNode(true)) - this.panelSlot = this.shadowRoot.querySelector('slot'); - } - connectedCallback() { - - //animations - let flyInLeft = [{ - opacity: 0, - transform: 'translateX(-1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyInRight = [{ - opacity: 0, - transform: 'translateX(1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyOutLeft = [{ - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(-1rem)' - } - ], - flyOutRight = [{ - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(1rem)' - } - ], - animationOptions = { - duration: 300, - fill: 'forwards', - easing: 'ease' - } - this.prevPanel - this.allPanels - this.previousRank - - this.panelSlot.addEventListener('slotchange', () => { - this.panelSlot.assignedElements().forEach((panel) => { - panel.classList.add('hide-completely') - }) - }) - this.allPanels = this.panelSlot.assignedElements() - this._targetBodyFlyRight = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInRight, animationOptions) - } - this._targetBodyFlyLeft = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInLeft, animationOptions) - } - document.addEventListener('switchtab', e => { - if (e.detail.target !== this.id) - return - - if (this.prevPanel) { - let targetBody = this.allPanels[e.detail.rank], - currentBody = this.prevPanel; - if (this.previousRank < e.detail.rank) { - if (currentBody && !targetBody) - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyRight(targetBody) - } else if (currentBody && targetBody) { - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyRight(targetBody) - } - } - } else { - if (currentBody && !targetBody) - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyLeft(targetBody) - } else if (currentBody && targetBody) { - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyLeft(targetBody) - } - } - } - } else { - this.allPanels[e.detail.rank].classList.remove('hide-completely') - } - this.previousRank = e.detail.rank - this.prevPanel = this.allPanels[e.detail.rank]; - }) - } -}) +/*jshint esversion: 6 */ +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)); + } + static get observedAttributes() { + return ['disabled']; + } + + get disabled() { + return this.hasAttribute('disabled'); + } + + set disabled(value) { + if (value) { + this.setAttribute('disabled', ''); + } else { + this.removeAttribute('disabled'); + } + } + focusIn() { + this.focus(); + } + + handleKeyDown(e) { + if (!this.hasAttribute('disabled') && (e.key === 'Enter' || e.code === 'Space')) { + e.preventDefault(); + this.click(); + } + } + + connectedCallback() { + if (!this.hasAttribute('disabled')) { + this.setAttribute('tabindex', '0'); + } + this.setAttribute('role', 'button'); + this.addEventListener('keydown', this.handleKeyDown); + } + attributeChangedCallback(name) { + if (name === 'disabled') { + if (this.hasAttribute('disabled')) { + this.removeAttribute('tabindex'); + } else { + this.setAttribute('tabindex', '0'); + } + this.setAttribute('aria-disabled', this.hasAttribute('disabled')); + } + } + }) +const smForm = document.createElement('template'); +smForm.innerHTML = ` + +
+ +
+`; + +customElements.define('sm-form', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smForm.content.cloneNode(true)) + + this.form = this.shadowRoot.querySelector('form'); + this.formElements + this.requiredElements + this.submitButton + this.resetButton + this.allRequiredValid = false; + + 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(callback, wait) { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; + } + _checkValidity() { + this.allRequiredValid = this.requiredElements.every(elem => elem.isValid) + if (!this.submitButton) return; + if (this.allRequiredValid) { + this.submitButton.disabled = false; + } + else { + this.submitButton.disabled = true; + } + } + handleKeydown(e) { + if (e.key === 'Enter' && e.target.tagName !== 'SM-TEXTAREA') { + if (this.allRequiredValid) { + if (this.submitButton && this.submitButton.tagName === 'SM-BUTTON') { + this.submitButton.click() + } + this.dispatchEvent(new CustomEvent('submit', { + bubbles: true, + composed: true, + })) + } + else { + this.requiredElements.find(elem => !elem.isValid).vibrate() + } + } + } + reset() { + this.formElements.forEach(elem => elem.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(elem => elem.hasAttribute('required')); + this.submitButton = this.querySelector('[variant="primary"], [type="submit"]'); + this.resetButton = this.querySelector('[type="reset"]'); + if (this.resetButton) { + this.resetButton.addEventListener('click', this.reset); + } + this._checkValidity() + } + connectedCallback() { + const slot = this.shadowRoot.querySelector('slot') + slot.addEventListener('slotchange', this.elementsChanged) + this.addEventListener('input', this.debounce(this._checkValidity, 100)); + this.addEventListener('keydown', this.debounce(this.handleKeydown, 100)); + } + disconnectedCallback() { + this.removeEventListener('input', this.debounce(this._checkValidity, 100)); + this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100)); + } +}) + +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)); + + 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 = false; + this.hideRequired = false; + this.validationFunction = undefined; + this.reflectedAttributes = ['value', 'required', 'disabled', 'type', 'inputmode', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step']; + + this.reset = this.reset.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.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(val) { + this.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'); + } + + set type(val) { + this.setAttribute('type', val); + } + + get validity() { + return this.input.validity; + } + + get disabled() { + return this.hasAttribute('disabled'); + } + set disabled(value) { + if (value) + this.inputParent.classList.add('disabled'); + else + this.inputParent.classList.remove('disabled'); + } + get readOnly() { + return this.hasAttribute('readonly'); + } + set readOnly(value) { + if (value) { + this.setAttribute('readonly', ''); + } else { + this.removeAttribute('readonly'); + } + } + set customValidation(val) { + this.validationFunction = val; + } + set errorText(val) { + this._errorText = val; + } + set helperText(val) { + this._helperText = val; + } + get isValid() { + if (this.input.value !== '') { + const _isValid = this.input.checkValidity(); + let _customValid = true; + if (this.validationFunction) { + _customValid = Boolean(this.validationFunction(this.input.value)); + } + if (_isValid && _customValid) { + this.feedbackText.classList.remove('error'); + this.feedbackText.classList.add('success'); + this.feedbackText.textContent = ''; + } else { + if (this._errorText) { + this.feedbackText.classList.add('error'); + this.feedbackText.classList.remove('success'); + this.feedbackText.innerHTML = ` + + ${this._errorText} + `; + } + } + return (_isValid && _customValid); + } + } + reset() { + this.value = ''; + } + + 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('readonly')) { + if (this.input.value.trim() !== '') { + this.clearBtn.classList.remove('hide'); + } else { + this.clearBtn.classList.add('hide'); + if (this.isRequired && !this.hideRequired) { + this.feedbackText.textContent = '*required'; + } + } + } + if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder').trim() === '') return; + if (this.input.value !== '') { + if (this.animate) + this.inputParent.classList.add('animate-label'); + else + this.label.classList.add('hide'); + } else { + if (this.animate) + this.inputParent.classList.remove('animate-label'); + else + this.label.classList.remove('hide'); + } + } + 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.reset); + } + + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (this.reflectedAttributes.includes(name)) { + if (this.hasAttribute(name)) { + this.input.setAttribute(name, this.getAttribute(name) ? this.getAttribute(name) : ''); + } + else { + this.input.removeAttribute(name); + } + } + if (name === 'placeholder') { + this.label.textContent = newValue; + this.setAttribute('aria-label', newValue); + } + else if (this.hasAttribute('value')) { + this.checkInput(); + } + else if (name === 'type') { + if (this.hasAttribute('type') && this.getAttribute('type') === 'number') { + this.input.setAttribute('inputmode', 'numeric'); + } + } + else if (name === 'helper-text') { + this._helperText = this.getAttribute('helper-text'); + } + else if (name === 'error-text') { + this._errorText = this.getAttribute('error-text'); + } + else if (name === 'required') { + this.isRequired = this.hasAttribute('required'); + if (this.isRequired && !this.hideRequired) { + this.feedbackText.textContent = ''; + } else { + this.feedbackText.textContent = '*required'; + } + if (this.isRequired) { + this.setAttribute('aria-required', 'true'); + } + else { + this.setAttribute('aria-required', 'false'); + } + } + else if (name === 'hiderequired') { + this.hideRequired = this.hasAttribute('hiderequired') + } + else if (name === 'readonly') { + if (this.hasAttribute('readonly')) { + this.inputParent.classList.add('readonly'); + } else { + this.inputParent.classList.remove('readonly'); + } + } + else if (name === 'disabled') { + if (this.hasAttribute('disabled')) { + this.inputParent.classList.add('disabled'); + } + else { + this.inputParent.classList.remove('disabled'); + } + } + } + } + disconnectedCallback() { + this.input.removeEventListener('input', this.checkInput); + this.clearBtn.removeEventListener('click', this.reset); + } + }) +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)) + + 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) + + } + + randString(length) { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < length; i++) + result += characters.charAt(Math.floor(Math.random() * characters.length)); + return result; + } + + createNotification(message, options = {}) { + const { pinned = false, icon = '' } = options; + const notification = document.createElement('div') + notification.id = this.randString(8) + notification.classList.add('notification'); + let composition = ``; + composition += ` +
${icon}
+

${message}

+ `; + if (pinned) { + notification.classList.add('pinned'); + composition += ` + + `; + } + notification.innerHTML = composition; + return notification; + } + + push(message, options = {}) { + const notification = this.createNotification(message, options); + this.notificationPanel.append(notification); + notification.animate([ + { + transform: `translateY(1rem)`, + opacity: '0' + }, + { + transform: `none`, + opacity: '1' + }, + ], this.animationOptions); + return notification.id; + } + + removeNotification(notification) { + notification.animate([ + { + transform: `none`, + opacity: '1' + }, + { + transform: `translateY(0.5rem)`, + opacity: '0' + } + ], this.animationOptions).onfinish = () => { + notification.remove(); + }; + } + + clearAll() { + Array.from(this.notificationPanel.children).forEach(child => { + this.removeNotification(child); + }); + } + + connectedCallback() { + 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 && !mutation.addedNodes[0].classList.contains('pinned')) { + setTimeout(() => { + this.removeNotification(mutation.addedNodes[0]); + }, 5000); + } + } + }); + }); + observer.observe(this.notificationPanel, { + childList: true, + }); + } +}); + + +class Stack { + constructor() { + this.items = []; + } + push(element) { + this.items.push(element); + } + pop() { + if (this.items.length == 0) + return "Underflow"; + return this.items.pop(); + } + peek() { + return this.items[this.items.length - 1]; + } +} +const popupStack = new Stack(); + +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; + this.isOpen = false; + this.pinned = false; + this.offset = 0; + this.touchStartY = 0; + this.touchEndY = 0; + this.touchStartTime = 0; + this.touchEndTime = 0; + this.touchEndAnimation = undefined; + this.focusable + this.autoFocus + this.mutationObserver + + this.popupContainer = this.shadowRoot.querySelector('.popup-container'); + this.backdrop = this.shadowRoot.querySelector('.background'); + this.popup = 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(element, keyframes, options) { + const anime = element.animate(keyframes, { ...options, fill: 'both' }) + anime.finished.then(() => { + anime.commitStyles() + anime.cancel() + }) + return anime + } + + resumeScrolling() { + const scrollY = document.body.style.top; + window.scrollTo(0, parseInt(scrollY || '0') * -1); + document.body.style.overflow = 'auto'; + document.body.style.top = 'initial'; + } + + setStateOpen() { + if (!this.isOpen || this.offset) { + const animOptions = { + duration: 300, + easing: 'ease' + } + const initialAnimation = (window.innerWidth > 640) ? 'scale(1.1)' : `translateY(${this.offset ? `${this.offset}px` : '100%'})` + this.animateTo(this.popup, [ + { + opacity: this.offset ? 1 : 0, + transform: initialAnimation + }, + { + opacity: 1, + transform: 'none' + }, + ], animOptions) + + } + } + + show(options = {}) { + const { pinned = false } = options; + if (!this.isOpen) { + const animOptions = { + duration: 300, + easing: 'ease' + } + popupStack.push({ + popup: this, + permission: pinned + }); + if (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)' }, + ], animOptions) + } + this.popupContainer.classList.remove('hide'); + if (!this.offset) + this.backdrop.animate([ + { opacity: 0 }, + { opacity: 1 }, + ], animOptions) + this.setStateOpen() + this.dispatchEvent( + new CustomEvent("popupopened", { + bubbles: true, + detail: { + popup: this, + } + }) + ); + this.pinned = pinned; + this.isOpen = true; + document.body.style.overflow = 'hidden'; + document.body.style.top = `-${window.scrollY}px`; + const elementToFocus = this.autoFocus || this.focusable[0]; + elementToFocus.tagName.includes('SM-') ? elementToFocus.focusIn() : elementToFocus.focus(); + if (!this.hasAttribute('open')) + this.setAttribute('open', ''); + } + } + hide() { + const animOptions = { + duration: 150, + easing: 'ease' + } + this.backdrop.animate([ + { opacity: 1 }, + { opacity: 0 } + ], animOptions) + this.animateTo(this.popup, [ + { + 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%)' + }, + ], animOptions).finished + .finally(() => { + this.popupContainer.classList.add('hide'); + this.popup.style = '' + this.removeAttribute('open'); + + if (this.forms.length) { + this.forms.forEach(form => form.reset()); + } + this.dispatchEvent( + new CustomEvent("popupclosed", { + bubbles: true, + detail: { + popup: this, + } + }) + ); + this.isOpen = false; + }) + popupStack.pop(); + if (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' }, + ], animOptions) + + } else { + this.resumeScrolling(); + } + } + + handleTouchStart(e) { + this.offset = 0 + this.popupHeader.addEventListener('touchmove', this.handleTouchMove, { passive: true }); + this.popupHeader.addEventListener('touchend', this.handleTouchEnd, { passive: true }); + this.touchStartY = e.changedTouches[0].clientY; + this.touchStartTime = e.timeStamp; + } + + handleTouchMove(e) { + if (this.touchStartY < e.changedTouches[0].clientY) { + this.offset = e.changedTouches[0].clientY - this.touchStartY; + this.touchEndAnimation = window.requestAnimationFrame(() => { + this.popup.style.transform = `translateY(${this.offset}px)`; + }); + } + } + + handleTouchEnd(e) { + this.touchEndTime = e.timeStamp; + cancelAnimationFrame(this.touchEndAnimation); + this.touchEndY = e.changedTouches[0].clientY; + this.threshold = this.popup.getBoundingClientRect().height * 0.3; + if (this.touchEndTime - this.touchStartTime > 200) { + if (this.touchEndY - this.touchStartY > this.threshold) { + if (this.pinned) { + this.setStateOpen(); + return; + } else + this.hide(); + } else { + this.setStateOpen(); + } + } else { + if (this.touchEndY > this.touchStartY) + if (this.pinned) { + this.setStateOpen(); + return; + } + else + this.hide(); + } + this.popupHeader.removeEventListener('touchmove', this.handleTouchMove, { passive: true }); + this.popupHeader.removeEventListener('touchend', this.handleTouchEnd, { passive: true }); + } + + + detectFocus(e) { + if (e.code === 'Tab') { + const lastElement = this.focusable[this.focusable.length - 1]; + const firstElement = this.focusable[0]; + if (e.shiftKey && document.activeElement === firstElement) { + e.preventDefault(); + lastElement.tagName.includes('SM-') ? lastElement.focusIn() : lastElement.focus(); + } else if (!e.shiftKey && document.activeElement === lastElement) { + e.preventDefault(); + firstElement.tagName.includes('SM-') ? firstElement.focusIn() : firstElement.focus(); + } + } + } + + updateFocusableList() { + this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input, 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', e => { + if (e.target === this.popupContainer && !this.pinned) { + if (this.pinned) { + this.setStateOpen(); + } else + this.hide(); + } + }); + + const resizeObserver = new ResizeObserver(entries => { + for (let entry of entries) { + if (entry.contentBoxSize) { + // Firefox implements `contentBoxSize` as a single content rect, rather than an array + const contentBoxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize; + this.threshold = contentBoxSize.blockSize.height * 0.3; + } else { + this.threshold = entry.contentRect.height * 0.3; + } + } + }); + resizeObserver.observe(this); + + this.mutationObserver = new MutationObserver(entries => { + this.updateFocusableList() + }) + this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true }) + + this.addEventListener('keydown', this.detectFocus); + this.popupHeader.addEventListener('touchstart', this.handleTouchStart, { passive: true }); + } + disconnectedCallback() { + this.removeEventListener('keydown', this.detectFocus); + resizeObserver.unobserve(); + this.mutationObserver.disconnect() + this.popupHeader.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); + } + attributeChangedCallback(name) { + if (name === 'open') { + if (this.hasAttribute('open')) { + this.show(); + } + } + } +}); +const spinner = document.createElement('template'); +spinner.innerHTML = ` + + + +`; +class SquareLoader extends HTMLElement { + constructor() { + super(); + this.attachShadow({ + mode: 'open' + }).append(spinner.content.cloneNode(true)); + } +} +window.customElements.define('sm-spinner', SquareLoader); + +const themeToggle = document.createElement('template'); +themeToggle.innerHTML = ` + + +`; + +class ThemeToggle extends HTMLElement { + constructor() { + super(); + + this.attachShadow({ + mode: 'open' + }).append(themeToggle.content.cloneNode(true)); + + this.isChecked = false; + 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) { + if (e.code === 'Space') { + this.toggleState(); + } + } + handleThemeChange(e) { + if (e.detail.theme !== this.hasTheme) { + if (e.detail.theme === 'dark') { + this.setAttribute('checked', ''); + } + else { + this.removeAttribute('checked'); + } + } + } + + fireEvent() { + this.dispatchEvent( + new CustomEvent('themechange', { + bubbles: true, + composed: true, + detail: { + theme: this.hasTheme + } + }) + ); + } + + connectedCallback() { + this.setAttribute('role', 'switch'); + this.setAttribute('aria-label', 'theme toggle'); + if (localStorage.getItem(`${window.location.hostname}-theme`) === "dark") { + this.nightlight(); + this.setAttribute('checked', ''); + } else if (localStorage.getItem(`${window.location.hostname}-theme`) === "light") { + this.daylight(); + this.removeAttribute('checked'); + } + else { + if (window.matchMedia(`(prefers-color-scheme: dark)`).matches) { + this.nightlight(); + this.setAttribute('checked', ''); + } else { + 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(name, oldVal, newVal) { + if (name === 'checked') { + if (this.hasAttribute('checked')) { + this.nightlight(); + localStorage.setItem(`${window.location.hostname}-theme`, "dark"); + } else { + this.daylight(); + localStorage.setItem(`${window.location.hostname}-theme`, "light"); + } + } + } +} + +window.customElements.define('theme-toggle', ThemeToggle); + +const smCopy = document.createElement('template'); +smCopy.innerHTML = ` + +
+

+ +
+`; +customElements.define('sm-copy', + class extends HTMLElement { + constructor() { + super(); + this.attachShadow({ + mode: 'open' + }).append(smCopy.content.cloneNode(true)); + + 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(val) { + this.setAttribute('value', val); + } + get value() { + return this.getAttribute('value'); + } + fireEvent() { + this.dispatchEvent( + new CustomEvent('copy', { + composed: true, + bubbles: true, + cancelable: true, + }) + ); + } + copy() { + navigator.clipboard.writeText(this.copyContent.textContent) + .then(res => this.fireEvent()) + .catch(err => console.error(err)); + } + connectedCallback() { + this.copyButton.addEventListener('click', this.copy); + } + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'value') { + this.copyContent.textContent = newValue; + } + } + disconnectedCallback() { + this.copyButton.removeEventListener('click', this.copy); + } + }); +const stripSelect = document.createElement('template'); +stripSelect.innerHTML = ` + +
+
+ +
+ +
+ +
+
+ +`; +customElements.define('strip-select', class extends HTMLElement { + constructor() { + super(); + this.attachShadow({ + mode: 'open' + }).append(stripSelect.content.cloneNode(true)); + this.stripSelect = this.shadowRoot.querySelector('.strip-select'); + this.slottedOptions = undefined; + this._value = undefined; + this.scrollDistance = 0; + + this.scrollLeft = this.scrollLeft.bind(this); + this.scrollRight = this.scrollRight.bind(this); + this.fireEvent = this.fireEvent.bind(this); + } + get value() { + return this._value; + } + scrollLeft() { + this.stripSelect.scrollBy({ + left: -this.scrollDistance, + behavior: 'smooth' + }); + } + + scrollRight() { + this.stripSelect.scrollBy({ + left: this.scrollDistance, + behavior: 'smooth' + }); + } + fireEvent() { + this.dispatchEvent( + new CustomEvent("change", { + bubbles: true, + composed: true, + detail: { + value: this._value + } + }) + ); + } + connectedCallback() { + this.setAttribute('role', 'listbox'); + + const slot = this.shadowRoot.querySelector('slot'); + const coverLeft = this.shadowRoot.querySelector('.cover--left'); + const coverRight = this.shadowRoot.querySelector('.cover--right'); + const navButtonLeft = this.shadowRoot.querySelector('.nav-button--left'); + const navButtonRight = this.shadowRoot.querySelector('.nav-button--right'); + slot.addEventListener('slotchange', e => { + const assignedElements = slot.assignedElements(); + assignedElements.forEach(elem => { + if (elem.hasAttribute('selected')) { + elem.setAttribute('active', ''); + this._value = elem.value; + } + }); + if (!this.hasAttribute('multiline')) { + if (assignedElements.length > 0) { + firstOptionObserver.observe(slot.assignedElements()[0]); + lastOptionObserver.observe(slot.assignedElements()[slot.assignedElements().length - 1]); + } + else { + navButtonLeft.classList.add('hide'); + navButtonRight.classList.add('hide'); + coverLeft.classList.add('hide'); + coverRight.classList.add('hide'); + firstOptionObserver.disconnect(); + lastOptionObserver.disconnect(); + } + } + }); + const resObs = new ResizeObserver(entries => { + entries.forEach(entry => { + if (entry.contentBoxSize) { + // Firefox implements `contentBoxSize` as a single content rect, rather than an array + const contentBoxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize; + + this.scrollDistance = contentBoxSize.inlineSize * 0.6; + } else { + this.scrollDistance = entry.contentRect.width * 0.6; + } + }); + }); + resObs.observe(this); + this.stripSelect.addEventListener('option-clicked', e => { + if (this._value !== e.target.value) { + this._value = e.target.value; + slot.assignedElements().forEach(elem => elem.removeAttribute('active')); + e.target.setAttribute('active', ''); + e.target.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" }); + this.fireEvent(); + } + }); + const firstOptionObserver = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + navButtonLeft.classList.add('hide'); + coverLeft.classList.add('hide'); + } + else { + navButtonLeft.classList.remove('hide'); + coverLeft.classList.remove('hide'); + } + }); + }, + { + threshold: 0.9, + root: this + }); + const lastOptionObserver = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + navButtonRight.classList.add('hide'); + coverRight.classList.add('hide'); + } + else { + navButtonRight.classList.remove('hide'); + coverRight.classList.remove('hide'); + } + }); + }, + { + threshold: 0.9, + root: this + }); + navButtonLeft.addEventListener('click', this.scrollLeft); + navButtonRight.addEventListener('click', this.scrollRight); + } + disconnectedCallback() { + navButtonLeft.removeEventListener('click', this.scrollLeft); + navButtonRight.removeEventListener('click', this.scrollRight); + } +}); + +//Strip option +const stripOption = document.createElement('template'); +stripOption.innerHTML = ` + + +`; +customElements.define('strip-option', class extends HTMLElement { + constructor() { + super(); + this.attachShadow({ + mode: 'open' + }).append(stripOption.content.cloneNode(true)); + this._value = undefined; + 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: true, + composed: true, + detail: { + value: this._value + } + }) + ); + } + handleKeyDown(e) { + if (e.key === 'Enter' || e.key === 'Space') { + 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 slideButton = document.createElement('template') +slideButton.innerHTML = ` + +
+
+ + + +
+

Slide to confirm

+
+`; +class SlideButton extends HTMLElement { + constructor() { + super(); + this.attachShadow({ + mode: 'open' + }).append(slideButton.content.cloneNode(true)); + + this.handleTouchStart = this.handleTouchStart.bind(this); + this.handleTouchMove = this.handleTouchMove.bind(this); + this.handleTouchEnd = this.handleTouchEnd.bind(this); + this.reset = this.reset.bind(this); + this.fireEvent = this.fireEvent.bind(this); + this.thumb = this.shadowRoot.querySelector('.slide-thumb'); + + this.startX = 0; + this.threshold = 0; + this.bound = 0; + } + get disabled() { + return this.hasAttribute('disabled'); + } + + set disabled(value) { + if (value) { + this.setAttribute('disabled', ''); + } else { + this.removeAttribute('disabled'); + } + } + + reset() { + this.thumb.setAttribute('style', `transform: translateX(0)`); + } + + fireEvent() { + this.dispatchEvent(new CustomEvent('confirmed', { + bubbles: true, + composed: true, + })); + } + + handleTouchStart(e) { + this.thumb.classList.remove('transition') + const thumbDimensions = this.thumb.getBoundingClientRect(); + const buttonDimensions = this.getBoundingClientRect(); + this.bound = buttonDimensions.width - thumbDimensions.width; + this.startX = e.clientX; + this.threshold = this.bound / 2; + this.thumb.setPointerCapture(e.pointerId); + this.thumb.addEventListener('pointermove', this.handleTouchMove); + this.thumb.addEventListener('pointerup', this.handleTouchEnd); + } + handleTouchMove(e) { + requestAnimationFrame(() => { + this.thumb.setAttribute('style', `transform: translateX(${Math.max(0, Math.min((this.bound), e.clientX - this.startX))}px)`); + }) + } + handleTouchEnd(e) { + this.thumb.classList.add('transition'); + if (e.clientX > this.threshold) { + this.fireEvent(); + this.thumb.setAttribute('style', `transform: translateX(${this.bound}px)`); + } else { + this.reset(); + } + this.thumb.releasePointerCapture(e.pointerId); + this.thumb.removeEventListener('pointermove', this.handleTouchMove); + this.thumb.removeEventListener('pointerup', this.handleTouchEnd); + } + + connectedCallback() { + this.thumb.addEventListener('pointerdown', this.handleTouchStart); + } + + disconnectedCallback() { + this.thumb.removeEventListener('pointerdown', this.handleTouchStart); + } +} + +window.customElements.define('slide-button', SlideButton); + +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)) + + 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.availableOptions + this.previousOption + this.isOpen = false; + 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.chevron = this.shadowRoot.querySelector('.toggle') + 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(val) { + const selectedOption = this.availableOptions.find(option => option.getAttribute('value') === val) + if (selectedOption) { + this.setAttribute('value', val) + this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`; + if (this.previousOption) { + this.previousOption.classList.remove('check-selected') + } + selectedOption.classList.add('check-selected') + this.previousOption = selectedOption + } else { + console.warn(`There is no option with ${val} as value`) + } + } + + reset(fire = true) { + if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) { + const firstElement = this.availableOptions[0]; + if (this.previousOption) { + this.previousOption.classList.remove('check-selected') + } + firstElement.classList.add('check-selected') + this.value = firstElement.getAttribute('value') + this.selectedOptionText.textContent = `${this.label}${firstElement.textContent}` + this.previousOption = firstElement; + if (fire) { + this.fireEvent() + } + } + } + + focusIn() { + this.selection.focus() + } + + open() { + this.optionList.classList.remove('hide') + this.optionList.animate(this.slideDown, this.animationOptions) + this.chevron.classList.add('rotate') + this.isOpen = true + } + collapse() { + this.chevron.classList.remove('rotate') + this.optionList.animate(this.slideUp, this.animationOptions) + .onfinish = () => { + this.optionList.classList.add('hide') + this.isOpen = false + } + } + toggle() { + if (!this.isOpen && !this.hasAttribute('disabled')) { + this.open() + } else { + this.collapse() + } + } + + fireEvent() { + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true, + detail: { + value: this.value + } + })) + } + + handleOptionsNavigation(e) { + if (e.code === 'ArrowUp') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } else { + this.availableOptions[this.availableOptions.length - 1].focus() + } + } + else if (e.code === 'ArrowDown') { + e.preventDefault() + if (document.activeElement.nextElementSibling) { + document.activeElement.nextElementSibling.focus() + } else { + this.availableOptions[0].focus() + } + } + } + handleOptionSelection(e) { + if (this.previousOption !== document.activeElement) { + this.value = document.activeElement.getAttribute('value') + this.fireEvent() + } + } + handleClick(e) { + if (e.target === this) { + this.toggle() + } + else { + this.handleOptionSelection() + this.collapse() + } + } + handleKeydown(e) { + if (e.target === this) { + if (this.isOpen && e.code === 'ArrowDown') { + e.preventDefault() + this.availableOptions[0].focus() + this.handleOptionSelection(e) + } + else if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.toggle() + } + } + else { + this.handleOptionsNavigation(e) + this.handleOptionSelection(e) + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.collapse() + } + } + } + handleClickOutside(e) { + if (this.isOpen && !this.contains(e.target)) { + this.collapse() + } + } + connectedCallback() { + this.setAttribute('role', 'listbox') + if (!this.hasAttribute('disabled')) { + this.selection.setAttribute('tabindex', '0') + } + let slot = this.shadowRoot.querySelector('slot') + slot.addEventListener('slotchange', e => { + this.availableOptions = slot.assignedElements() + this.reset(false) + }); + this.addEventListener('click', this.handleClick) + this.addEventListener('keydown', this.handleKeydown) + document.addEventListener('mousedown', this.handleClickOutside) + } + disconnectedCallback() { + this.removeEventListener('click', this.toggle) + this.removeEventListener('keydown', this.handleKeydown) + document.removeEventListener('mousedown', this.handleClickOutside) + } + attributeChangedCallback(name) { + if (name === "disabled") { + if (this.hasAttribute('disabled')) { + this.selection.removeAttribute('tabindex') + } else { + this.selection.setAttribute('tabindex', '0') + } + } else if (name === 'label') { + this.label = this.hasAttribute('label') ? `${this.getAttribute('label')} ` : '' + } + } +}) + +// 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)) + } + + connectedCallback() { + this.setAttribute('role', 'option') + this.setAttribute('tabindex', '0') + } +}) + +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.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(val) { + if (val) { + this.setAttribute('disabled', '') + } else { + this.removeAttribute('disabled') + } + } + + get checked() { + return this.hasAttribute('checked') + } + + set checked(value) { + if (value) { + this.setAttribute('checked', '') + } + else { + this.removeAttribute('checked') + } + } + + set value(val) { + this.setAttribute('value', val) + } + + get value() { + return this.getAttribute('value') + } + + focusIn() { + this.focus() + } + + reset() { + this.value = this.defaultState + } + + dispatch() { + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true + })) + } + handleKeyDown(e) { + if (e.code === "Space") { + e.preventDefault() + this.click() + } + } + handleClick(e) { + this.toggleAttribute('checked') + } + + connectedCallback() { + if (!this.hasAttribute('disabled')) { + this.setAttribute('tabindex', '0') + } + this.setAttribute('role', 'checkbox') + this.defaultState = this.hasAttribute('checked') + if (!this.hasAttribute('checked')) { + this.setAttribute('aria-checked', 'false') + } + this.addEventListener('keydown', this.handleKeyDown) + this.addEventListener('click', this.handleClick) + } + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'checked') { + this.setAttribute('aria-checked', this.hasAttribute('checked')) + this.dispatch() + } + else if (name === 'disabled') { + if (this.hasAttribute('disabled')) { + this.removeAttribute('tabindex') + } + else { + this.setAttribute('tabindex', '0') + } + } + } + } + disconnectedCallback() { + this.removeEventListener('keydown', this.handleKeyDown) + this.removeEventListener('change', this.handleClick) + } +}) +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.prevTab + this.allTabs + this.activeTab + + this.indicator = this.shadowRoot.querySelector('.indicator'); + this.tabSlot = this.shadowRoot.querySelector('slot'); + this.tabHeader = this.shadowRoot.querySelector('.tab-header'); + + this.changeTab = this.changeTab.bind(this) + this.handleClick = this.handleClick.bind(this) + this.handlePanelChange = this.handlePanelChange.bind(this) + this.moveIndiactor = this.moveIndiactor.bind(this) + } + + fireEvent(index) { + this.dispatchEvent( + new CustomEvent(`switchedtab${this.target}`, { + bubbles: true, + detail: { + index: parseInt(index) + } + }) + ) + } + + moveIndiactor(tabDimensions) { + this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) + } + + + changeTab(target) { + if (target === this.prevTab || !target.closest('sm-tab')) + return + if (this.prevTab) + this.prevTab.classList.remove('active') + target.classList.add('active') + + this.tabHeader.scrollTo({ + behavior: 'smooth', + left: target.getBoundingClientRect().left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft + }) + this.moveIndiactor(target.getBoundingClientRect()) + this.prevTab = target; + this.activeTab = target; + } + handleClick(e) { + if (e.target.closest('sm-tab')) { + this.changeTab(e.target) + this.fireEvent(e.target.dataset.index) + } + } + + handlePanelChange(e) { + this.changeTab(this.allTabs[e.detail.index]) + } + + connectedCallback() { + if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return; + this.target = this.getAttribute('target') + + this.tabSlot.addEventListener('slotchange', () => { + this.allTabs = this.tabSlot.assignedElements(); + this.allTabs.forEach((tab, index) => { + tab.dataset.index = index + }) + }) + + this.addEventListener('click', this.handleClick) + document.addEventListener(`switchedpanel${this.target}`, this.handlePanelChange) + + 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.fireEvent(0) + this.prevTab = this.tabSlot.assignedElements()[0]; + this.activeTab = this.prevTab; + } + } + }) + }, { + threshold: 1.0 + }) + observer.observe(this) + } + disconnectedCallback() { + this.removeEventListener('click', this.handleClick) + document.removeEventListener(`switchedpanel${this.target}`, this.handlePanelChange) + } +}) + +// 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)) + } +}) + +// 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.isTransitioning = false + + this.panelContainer = this.shadowRoot.querySelector('.panel-container'); + this.handleTabChange = this.handleTabChange.bind(this) + } + handleTabChange(e) { + this.isTransitioning = true + this.panelContainer.scrollTo({ + left: this.allPanels[e.detail.index].getBoundingClientRect().left - this.panelContainer.getBoundingClientRect().left + this.panelContainer.scrollLeft, + behavior: 'smooth' + }) + setTimeout(() => { + this.isTransitioning = false + }, 300); + } + fireEvent(index) { + this.dispatchEvent( + new CustomEvent(`switchedpanel${this.id}`, { + bubbles: true, + detail: { + index: parseInt(index) + } + }) + ) + } + connectedCallback() { + const slot = this.shadowRoot.querySelector('slot'); + slot.addEventListener('slotchange', (e) => { + this.allPanels = e.target.assignedElements() + this.allPanels.forEach((panel, index) => { + panel.dataset.index = index + intersectionObserver.observe(panel) + }) + }) + document.addEventListener(`switchedtab${this.id}`, this.handleTabChange) + + const intersectionObserver = new IntersectionObserver(entries => { + + entries.forEach(entry => { + if (!this.isTransitioning && entry.isIntersecting) { + this.fireEvent(entry.target.dataset.index) + } + }) + }, { + threshold: 0.6 + }) + } + disconnectedCallback() { + intersectionObserver.disconnect() + document.removeEventListener(`switchedtab${this.id}`, this.handleTabChange) + } +}) + +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 + + this.dispatch = this.dispatch.bind(this) + } + + static get observedAttributes() { + return ['disabled', 'checked'] + } + + get disabled() { + return this.isDisabled + } + + set disabled(val) { + if (val) { + this.setAttribute('disabled', '') + } else { + this.removeAttribute('disabled') + } + } + + get checked() { + return this.isChecked + } + + set checked(value) { + if (value) { + this.setAttribute('checked', '') + } else { + this.removeAttribute('checked') + } + } + + reset() { + + } + + dispatch() { + this.dispatchEvent(new CustomEvent('change', { + bubbles: true, + composed: true, + detail: { + value: this.isChecked + } + })) + } + + connectedCallback() { + this.addEventListener('keydown', e => { + if (e.code === "Space" && !this.isDisabled) { + e.preventDefault() + this.input.click() + } + }) + this.input.addEventListener('click', e => { + if (this.input.checked) + this.checked = true + else + this.checked = false + this.dispatch() + }) + } + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'disabled') { + if (this.hasAttribute('disabled')) { + this.disabled = true + } + else { + this.disabled = false + } + } + else if (name === 'checked') { + if (this.hasAttribute('checked')) { + this.isChecked = true + this.input.checked = true + } + else { + this.isChecked = false + this.input.checked = false + } + } + } + } + +}) + +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)) + + this.isOpen = false; + this.availableOptions + this.containerDimensions + this.animOptions = { + duration: 200, + easing: 'ease' + } + + this.optionList = this.shadowRoot.querySelector('.options') + this.menu = this.shadowRoot.querySelector('.menu') + this.icon = this.shadowRoot.querySelector('.icon') + + this.expand = this.expand.bind(this) + this.collapse = this.collapse.bind(this) + this.toggle = this.toggle.bind(this) + this.handleKeyDown = this.handleKeyDown.bind(this) + this.handleClickOutside = this.handleClickOutside.bind(this) + + } + static get observedAttributes() { + return ['value'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + expand() { + if (!this.isOpen) { + this.optionList.classList.remove('hide') + this.optionList.animate([ + { + transform: window.innerWidth < 640 ? 'translateY(1.5rem)' : 'translateY(-1rem)', + opacity: '0' + }, + { + transform: 'none', + opacity: '1' + }, + ], this.animOptions) + .onfinish = () => { + this.isOpen = true + this.icon.classList.add('focused') + } + } + } + collapse() { + if (this.isOpen) { + this.optionList.animate([ + { + transform: 'none', + opacity: '1' + }, + { + transform: window.innerWidth < 640 ? 'translateY(1.5rem)' : 'translateY(-1rem)', + opacity: '0' + }, + ], this.animOptions) + .onfinish = () => { + this.isOpen = false + this.icon.classList.remove('focused') + this.optionList.classList.add('hide') + } + } + } + toggle() { + if (!this.isOpen) { + this.expand() + } else { + this.collapse() + } + } + handleKeyDown(e) { + // If key is pressed on menu button + if (e.target === this) { + if (e.code === 'ArrowDown') { + e.preventDefault() + this.availableOptions[0].focus() + } + else if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.toggle() + } + } else { // If key is pressed over menu options + if (e.code === 'ArrowUp') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } else { + this.availableOptions[this.availableOptions.length - 1].focus() + } + } + else if (e.code === 'ArrowDown') { + e.preventDefault() + if (document.activeElement.nextElementSibling) { + document.activeElement.nextElementSibling.focus() + } else { + this.availableOptions[0].focus() + } + } + else if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + e.target.click() + } + } + } + handleClickOutside(e) { + if (!this.contains(e.target) && e.button !== 2) { + this.collapse() + } + } + connectedCallback() { + this.setAttribute('role', 'listbox') + this.setAttribute('aria-label', 'dropdown menu') + const slot = this.shadowRoot.querySelector('.options slot') + slot.addEventListener('slotchange', e => { + this.availableOptions = e.target.assignedElements() + this.containerDimensions = this.optionList.getBoundingClientRect() + }); + this.addEventListener('click', this.toggle) + this.addEventListener('keydown', this.handleKeyDown) + document.addEventListener('mousedown', this.handleClickOutside) + } + disconnectedCallback() { + this.removeEventListener('click', this.toggle) + this.removeEventListener('keydown', this.handleKeyDown) + document.removeEventListener('mousedown', this.handleClickOutside) + } +}) + +// option +const menuOption = document.createElement('template') +menuOption.innerHTML = ` + +
+ +
`; +customElements.define('menu-option', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(menuOption.content.cloneNode(true)) + } + + connectedCallback() { + this.setAttribute('role', 'option') + this.setAttribute('tabindex', '0') + this.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.click() + } + }) + } +}) +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() + } + } + }) diff --git a/css/main.css b/css/main.css index 3519ced..eac73d4 100644 --- a/css/main.css +++ b/css/main.css @@ -1,1048 +1,1249 @@ -@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap"); -* { - padding: 0; - margin: 0; - -webkit-box-sizing: border-box; - box-sizing: border-box; - font-family: "Roboto", sans-serif; -} - -html { - scroll-behavior: smooth; -} - -body { - --accent-color: #00a566; - --light-shade: rgba(var(--text-color), 0.06); - --text-color: 17, 17, 17; - --text-color-light: 100, 100, 100; - --foreground-color: 255, 255, 255; - --background-color: #efefef; - --error-color: red; - color: rgba(var(--text-color), 1); - height: calc(100%); - font-size: clamp(1rem, 1.2vmax, 3rem); - background: rgba(var(--foreground-color), 1); -} - -body[data-theme=dark] { - --accent-color:#00fa9a; - --text-color: 240, 240, 240; - --text-color-light: 170, 170, 170; - --foreground-color: 20, 20, 20; - --error-color: rgb(255, 106, 106); -} - -button { - position: relative; - overflow: hidden; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - border: none; - background: none; - cursor: pointer; - outline: none; - color: inherit; - font-weight: 500; - -webkit-tap-highlight-color: transparent; -} - -.button { - border-radius: 0.2rem; - padding: 0.5rem 0.6rem; -} - -.button--primary { - background: var(--accent-color); - color: rgba(var(--foreground-color), 1); -} -.button--primary .icon { - fill: rgba(var(--foreground-color), 1); -} - -button:focus-visible { - outline: rgba(var(--text-color), 1) 0.1rem solid; -} - -sm-input, -sm-textarea { - --border-radius: 0.2rem; - --background: rgba(var(--text-color), 0.06); -} - -sm-button { - --border-radius: 0.2rem; -} - -ul { - list-style: none; -} - -.flex { - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} - -.grid { - display: grid; -} - -.flow-column { - grid-auto-flow: column; -} - -.gap-1r { - gap: 1rem; -} - -.align-center { - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -.justify-right { - margin-left: auto; -} - -.direction-column { - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; -} - -.space-between { - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; -} - -.full-width { - width: 100%; -} - -.margin-top-1-5 { - margin-top: 1.5rem; -} - -.margin-bottom-1-5 { - margin-bottom: 1.5rem; -} - -.margin-left-0-5 { - margin-left: 0.5rem; -} - -.margin-right-0-5 { - margin-right: 0.5rem; -} - -.hide { - opacity: 0; - pointer-events: none; -} - -.hide-completely { - display: none !important; -} - -.no-transformations { - -webkit-transform: none !important; - transform: none !important; -} - -.overflow-ellipsis { - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.ripple { - position: absolute; - border-radius: 50%; - -webkit-transform: scale(0); - transform: scale(0); - background: rgba(var(--text-color), 0.16); - pointer-events: none; -} - -.interact { - position: relative; - overflow: hidden; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} - -.observe-empty-state:empty { - display: none; -} - -.observe-empty-state:not(:empty) ~ .empty-state { - display: none; -} - -.icon { - width: 1.5rem; - height: 1.5rem; - fill: rgba(var(--text-color), 0.9); -} - -.icon-only { - height: 2.6rem; - width: 2.6rem; - padding: 0.6rem; -} - -.close-icon { - padding: 0.3rem; -} - -.close-button { - left: -0.5rem; -} - -.option__icon { - height: 1.2rem; - width: 1.2rem; - margin-right: 0.8rem; -} - -.option__label { - font-size: 1rem; -} - -#confirmation_popup, -#prompt_popup { - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; -} -#confirmation_popup h4, -#prompt_popup h4 { - font-weight: 500; - margin-bottom: 0.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: 0.6rem; - margin-left: auto; -} - -.popup__header { - padding: 0.5rem 1.5rem 0 1rem; - display: grid; - grid-template-columns: auto 1fr auto; - gap: 0.5rem; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - width: 100%; -} - -.popup__header__close { - padding: 0.5rem; - cursor: pointer; -} - -h1, -h2, -h3, -h4, -h5 { - font-family: "Roboto Slab", sans-serif; -} - -p { - line-height: 1.6; -} - -button:focus { - outline: none; -} - -button:focus-visible { - outline: auto; -} - -button:first-of-type { - margin-left: auto; -} - -button[disabled] { - opacity: 0.5 !important; - cursor: default; - color: rgba(var(--text-color), 1); -} - -textarea { - background: var(--light-shade); - color: rgba(var(--text-color), 1); - padding: 1.5rem; - max-width: 100%; - font-size: 1rem; -} - -.checkbox__label { - margin-left: 1rem; -} - -.spacer { - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.solid-background { - background: var(--background-color); -} - -#context_menu { - display: none; -} - -.article__header { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - width: 100%; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - margin-bottom: 2rem; -} - -#article__title { - font-size: 1.2rem; -} - -#articles_list__button { - width: 3rem; - height: 3rem; - margin-left: -0.8rem; - margin-right: 0.5rem; - fill: rgba(var(--text-color), 1); - cursor: pointer; -} -#articles_list__button .icon-only { - height: 4rem; - width: 4rem; -} - -.gallery-name { - padding: 0.2rem 0; - margin: 1rem 0; - font-size: 1.1rem; - color: rgba(var(--text-color), 1); - font-weight: 500; - line-height: 1.5; -} - -.edit-article { - margin-left: auto; -} - -#edit_article_popup label { - font-size: 0.9rem; -} - -#edit_article_popup input:not([type=checkbox]) { - margin-bottom: 2rem; - margin-top: 0.5rem; - width: 100%; -} - -#edit_section_container { - gap: 1.5rem; - padding: 1rem 0; -} - -.gallery-container { - position: relative; - overflow: hidden; -} - -.navigation-arrows { - -webkit-transition: opacity 0.2s ease; - transition: opacity 0.2s ease; - cursor: pointer; - padding: 1rem; - height: 4rem; - width: 4rem; - z-index: 2; - position: absolute; - top: 50%; - fill: rgba(var(--text-color), 1); - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; - background: rgba(var(--foreground-color), 0.9); - -webkit-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.16); - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.16); -} - -.navigation-arrows:nth-of-type(1) { - border-radius: 0 50% 50% 0; - -webkit-transform: translate(-1rem, -50%); - transform: translate(-1rem, -50%); -} -.navigation-arrows:nth-of-type(1):hover { - -webkit-transform: translate(0, -50%); - transform: translate(0, -50%); -} - -.navigation-arrows:nth-of-type(2) { - right: 0; - border-radius: 50% 0 0 50%; - -webkit-transform: translate(1rem, -50%); - transform: translate(1rem, -50%); -} -.navigation-arrows:nth-of-type(2):hover { - -webkit-transform: translate(0, -50%); - transform: translate(0, -50%); -} - -.gallery { - position: relative; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - overflow-x: auto; - -ms-scroll-snap-type: x mandatory; - scroll-snap-type: x mandatory; - margin-bottom: 4rem !important; -} - -.article-body { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - scroll-snap-align: start; - min-width: 30%; - background-color: rgba(var(--text-color), 0.06); - color: rgba(var(--text-color), 1); - margin: 0 1rem 1rem 0; - border-radius: 0.2rem; -} - -.article-body .article-header { - padding: 1.5rem; - word-break: break-all; -} - -.article__author { - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - font-weight: normal; - font-size: 0.8rem; - color: #a7c5eb; -} - -.article-body .card-body { - position: relative; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.article-body .card-body .content-div { - padding: 0 1.5rem 4rem 1.5rem; - min-height: 16rem; - line-height: 1.7; - max-height: 50vh; - overflow-y: auto; - font-weight: 400; - overflow-wrap: break-word; -} - -.article-body .card-body .content-div * { - overflow-wrap: break-word; -} - -.article-body .card-body button { - position: absolute; - bottom: 0; - right: 0; - margin-right: 1rem; -} - -.article-body .card-body .submit-btn { - background: var(--light-shade); -} - -.article-body .card-footer { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - padding: 1rem 1.5rem; -} - -.article-body .card-footer h5 { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - font-weight: normal; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - color: var(--accent-color); - cursor: pointer; -} - -.article-body .card-footer h5:nth-of-type(2) { - margin-left: auto; -} - -.article-body .card-footer h5:nth-of-type(2):hover svg { - fill: var(--accent-color); -} - -.article-body .card-footer h5 svg { - stroke: var(--accent-color); - width: 1.2rem; - margin-right: 0.5rem; -} - -.show { - opacity: 1; - pointer-events: all; -} - -.hide { - opacity: 0; - pointer-events: none; -} - -#article_container { - padding: 1rem 2rem; - width: 100%; -} - -.select-for-export { - padding: 0.2rem 0.4rem; - border-radius: 0.1rem; -} - -.snippet-selected { - -webkit-box-shadow: 0 0 0 0.1rem var(--accent-color); - box-shadow: 0 0 0 0.1rem var(--accent-color); -} - -.no-transformations { - -webkit-transform: none !important; - transform: none !important; -} - -:-webkit-any-link { - color: var(--accent-color); - text-decoration: none; -} - -:-moz-any-link { - color: var(--accent-color); - text-decoration: none; -} - -:any-link { - color: var(--accent-color); - text-decoration: none; -} - -#sign_in { - --backdrop: rgba(var(--foreground-color), 1); -} - -#sign_in h2 { - margin-bottom: 1rem; - z-index: 3; -} - -#sign_in p:first-of-type { - margin-bottom: 4rem; - z-index: 3; - color: rgba(var(--text-color), 0.8); -} - -#sign_in .back-btn { - margin-bottom: 2rem; - padding-left: 0; - color: rgba(var(--text-color), 1); -} - -.sign-in-mode__button { - height: 8rem; - width: 8rem; -} - -.big-icon { - fill: none; - stroke: rgba(var(--text-color), 1); -} - -#sign_in div:first-of-type { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - margin-bottom: 4rem; - z-index: 3; -} - -#sign_in div:first-of-type .icon { - height: 3rem; - width: 3rem; - stroke-width: 4; - margin-bottom: 1rem; - margin-right: 0; -} - -#sign_in div:first-of-type button { - margin: initial; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - margin: 0.5rem; - width: 8rem; - color: rgba(var(--text-color), 1); - background: rgba(var(--foreground), 1); -} - -#sign_in div:first-of-type button:hover { - color: var(--accent-color); -} - -#sign_in div:first-of-type button:hover .icon { - stroke: var(--accent-color); -} - -#sign_in #priv_key_sign_in { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-flow: column wrap; - flex-flow: column wrap; - z-index: 3; -} - -#sign_in_button { - margin: 1rem 0 2rem 0; - width: 100%; - background: rgba(var(--text-color), 0.06); - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; -} - -#navbar { - position: -webkit-sticky; - position: sticky; - top: 0; - width: 100%; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - color: rgba(var(--text-color), 1); - background: rgba(var(--foreground-color), 1); - padding: 1rem; - z-index: 5; -} - -#navbar h5 { - font-size: 0.8rem; - font-weight: normal; - margin-bottom: 0.2rem; -} - -.app-name { - font-size: 1rem; - font-weight: 700; -} - -#icon { - width: 2rem; - height: 2rem; - margin: 0 0.5rem; -} - -#export_option_list { - gap: 1rem; - grid-auto-flow: column; - margin-right: 1rem; -} - -.floating-btn { - display: none; -} - -#loader_container { - position: fixed; - height: 100vh; - width: 100vw; - top: 0; - background: rgba(var(--foreground-color), 1); - -webkit-transition: opacity 0.6s ease; - transition: opacity 0.6s ease; - display: -ms-grid; - display: grid; - place-content: center; - z-index: 8; - text-align: center; -} - -#loader_container #spinner { - position: relative; - height: 2rem; - fill: teal; - overflow: visible; - -ms-grid-column-align: center; - justify-self: center; - margin-bottom: 2rem; -} - -#loader_container h4 { - font-weight: normal; - color: rgba(var(--text-color), 1); -} - -#loader_container button { - margin: 1rem auto auto auto; -} - -.pulse .first-orb { - -webkit-animation: pulse 1s infinite ease; - animation: pulse 1s infinite ease; -} - -.pulse .second-orb { - -webkit-animation: pulse 1s 0.1s infinite ease; - animation: pulse 1s 0.1s infinite ease; -} - -.pulse .third-orb { - -webkit-animation: pulse 1s 0.2s infinite ease; - animation: pulse 1s 0.2s infinite ease; -} - -@-webkit-keyframes pulse { - 0% { - -webkit-transform: scale(1); - transform: scale(1); - } - 60% { - -webkit-transform: scale(1.5); - transform: scale(1.5); - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - } -} -@keyframes pulse { - 0% { - -webkit-transform: scale(1); - transform: scale(1); - } - 60% { - -webkit-transform: scale(1.5); - transform: scale(1.5); - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - } -} -.spin svg { - -webkit-animation: spin 0.6s ease infinite; - animation: spin 0.6s ease infinite; - -webkit-transform-origin: center; - transform-origin: center; -} - -@-webkit-keyframes spin { - 0% { - -webkit-transform: rotate(0); - transform: rotate(0); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes spin { - 0% { - -webkit-transform: rotate(0); - transform: rotate(0); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -#section_plot_popup p { - margin: 1rem 0; - font-weight: 400; -} - -#section_plot_popup details { - margin-bottom: 1rem; - cursor: pointer; -} - -#section_plot_popup summary { - outline: none; -} - -#inc_section { - gap: 1rem; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; -} - -#article_list_popup { - --height: 80vh; - --min-height: 80vh; - --body-padding: 0; -} - -#article_list__header { - grid-template-columns: auto 1fr; -} - -#article_list { - display: grid; - margin-bottom: 1.5rem; - list-style: none; - grid-template-columns: repeat(auto-fill, minmax(30ch, 1fr)); -} - -.article-list__item { - width: 100%; - height: 100%; - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; - font-size: 1rem; - text-transform: none; - text-align: left; - font-weight: 400; - border-radius: 0.3rem; - line-height: 1.6; - letter-spacing: normal; - word-spacing: normal; - padding: 1rem 1.5rem; - color: rgba(var(--text-color), 0.9); -} - -.search__icon { - height: 1.2rem; - width: 1.2rem; -} - -#article_list__empty-state { - width: 100%; - padding: 3rem 0; - font-size: 1.2rem; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; -} - -@media screen and (min-width: 640px) { - sm-popup { - --width: 24rem; - } - - #sign_in { - width: 24rem; - height: auto; - border-radius: 0.4rem; - } - - #edit_article_popup { - --width: 32rem; - } - - #article__title { - width: 100%; - text-align: center; - font-size: 2rem; - } - - .gallery-name { - max-width: 40rem; - } - - #section_plot_popup { - --width: 42rem; - } - - #article_list__header { - grid-template-columns: auto 1fr auto; - padding: 1rem 1.5rem; - } - - #article_list_popup { - --width: 80vw; - } -} -@media screen and (min-width: 1920px) { - .article-body { - min-width: 20%; - } -} -.label { - margin-bottom: 0.4rem; - font-weight: 500; -} - -@media only screen and (max-width: 640px) { - .hide-on-mobile { - display: none; - } - - .article-body { - min-width: calc(100% - 2em) !important; - } - - #export_option_list { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - padding: 0.5rem; - z-index: 2; - background: rgba(var(--foreground-color), 1); - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - } - - .floating-btn { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - margin: 2rem; - background: rgba(var(--foreground-color), 1); - position: fixed; - -webkit-box-shadow: 0.2rem 0.4rem 0.6rem rgba(0, 0, 0, 0.24), -0.1rem -0.2rem 0.4rem rgba(0, 0, 0, 0.16); - box-shadow: 0.2rem 0.4rem 0.6rem rgba(0, 0, 0, 0.24), -0.1rem -0.2rem 0.4rem rgba(0, 0, 0, 0.16); - z-index: 3; - } - - .floating-btn button { - width: 100%; - } - - .floating-btn { - background: #282828; - bottom: 0; - right: 0; - border-radius: 5rem; - overflow: hidden; - } - - .floating-btn button { - padding: 1rem; - } - - .floating-btn button .icon { - margin-right: 0; - } - - #article_container { - padding: 1.5rem 1.5rem 6rem 1.5rem; - } - - .navigation-arrows { - opacity: 0; - pointer-events: none; - } - - #article_list__header { - padding-bottom: 1rem; - } - - #article_list__search { - width: 100%; - grid-column: 1/3; - } -} -@media only screen and (max-width: 1280px) { - .article-body { - min-width: 50%; - } - - .hide-on-medium { - display: none; - } -} -@media (any-hover: hover) { - ::-webkit-scrollbar { - width: 0.5rem; - height: 0.5rem; - } - - ::-webkit-scrollbar-thumb { - background: rgba(var(--text-color), 0.3); - border-radius: 1rem; - } - ::-webkit-scrollbar-thumb:hover { - background: rgba(var(--text-color), 0.5); - } - - .gallery { - overflow-x: hidden; - } +* { + 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%; + scroll-behavior: smooth; +} + +body { + color: rgba(var(--text-color), 1); + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: rgb(0, 156, 78); + --text-color: 36, 36, 36; + --background-color: 248, 248, 248; + --foreground-color: rgb(255, 255, 255); + --danger-color: rgb(255, 75, 75); + --green: #1cad59; + --yellow: #f3a600; + scrollbar-width: thin; +} + +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: rgb(14, 230, 122); + --text-color: 230, 230, 230; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --foreground-color: rgb(24, 24, 24); + --danger-color: rgb(255, 106, 106); + --green: #00e676; + --yellow: #ffd13a; +} +body[data-theme=dark] sm-popup::part(popup) { + background-color: var(--foreground-color); +} + +p, +strong { + font-size: 0.9rem; + max-width: 70ch; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); +} +p:not(:last-of-type), +strong:not(:last-of-type) { + margin-bottom: 1.5rem; +} + +a { + color: var(--accent-color); + text-decoration: none; + overflow: hidden; +} +a:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +button, +.button { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + cursor: pointer; + transition: transform 0.3s; + -webkit-tap-highlight-color: transparent; + align-items: center; + font-size: 0.9rem; + font-weight: 500; + overflow: hidden; +} + +.button { + white-space: nowrap; + padding: 0.5rem 0.8rem; + border-radius: 0.3rem; + background-color: rgba(var(--text-color), 0.06); + color: rgba(var(--text-color), 0.8); + justify-content: center; +} +.button--primary { + background-color: var(--accent-color); + color: rgba(var(--background-color), 1); +} + +.icon-only { + padding: 0.5rem; + border-radius: 0.3rem; +} + +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; +} + +sm-input, +sm-textarea, +tags-input { + font-size: 0.9rem; + --border-radius: 0.3rem; +} + +sm-button { + --padding: 0.5rem 0.8rem; + transition: transform 0.3s; + overflow: hidden; +} +sm-button[variant=primary] { + --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.uppercase { + letter-spacing: 0.05em; +} +sm-button.danger { + --background: var(--danger-color); + color: rgba(var(--background-color), 1); +} + +ul { + list-style: none; +} + +.hide-completely { + display: none !important; +} + +.overflow-ellipsis { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/-1; +} + +.h1 { + font-size: 1.5rem; +} + +.h2 { + font-size: 1.2rem; +} + +.h3 { + font-size: 1rem; +} + +.h4 { + font-size: 0.9rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.flow-column { + grid-auto-flow: column; +} + +.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; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.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; +} + +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.empty-state { + display: grid; + width: 100%; + padding: 1.5rem 1rem; +} + +.observe-empty-state:empty { + display: none !important; +} + +.observe-empty-state:not(:empty) + .empty-state { + display: none !important; +} + +.icon { + width: 1.2rem; + height: 1.2rem; + fill: rgba(var(--text-color), 0.8); + flex-shrink: 0; +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +.icon-button { + padding: 0.6rem; + border-radius: 0.8rem; + background-color: rgba(var(--text-color), 0.1); + height: -webkit-max-content; + height: -moz-max-content; + height: max-content; +} +.icon-button .icon { + fill: var(--accent-color); +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; +} +#confirmation_popup h4, +#prompt_popup h4 { + font-weight: 500; + margin-bottom: 0.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: 0.6rem; + margin-left: auto; +} + +#prompt_message { + margin-bottom: 1.5rem; +} + +.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; +} + +.logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.3rem; +} +.logo h4 { + text-transform: capitalize; + font-size: 0.9rem; +} +.logo .main-logo { + height: 1.4rem; + width: 1.4rem; + fill: rgba(var(--text-color), 1); + stroke: none; +} + +details summary { + display: flex; + justify-content: space-between; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; +} +details[open] > summary { + margin-bottom: 1rem; +} +details[open] > summary .icon { + transform: rotate(180deg); +} + +sm-select, +sm-option, +strip-option { + font-size: 0.9rem; +} + +strip-select { + --gap: 0; +} + +strip-option { + font-weight: 500; + --border-radius: 0.3rem; + --active-option-color: var(--accent-color); +} + +sm-checkbox { + --height: 1rem; + --width: 1rem; + -webkit-tap-highlight-color: transparent; +} + +sm-menu { + --background: var(--foreground-color); +} + +menu-option { + font-size: 0.9rem; +} + +sm-copy { + font-size: 0.9rem; + --button-border-radius: 0.2rem; +} + +.warning { + background-color: khaki; + color: rgba(0, 0, 0, 0.7); + padding: 1rem; + border-radius: 0.5rem; + line-height: 1.5; +} + +.page { + height: 100%; +} + +.page-layout, +#preview_page { + display: grid; + grid-template-columns: 1rem minmax(0, 1fr) 1rem; +} +.page-layout > *, +#preview_page > * { + grid-column: 2/3; +} + +#landing { + grid-template-rows: auto 1fr; +} +#landing header { + padding: 1.5rem 0; +} +#landing > section { + align-items: center; + text-align: center; +} +#landing h1 { + margin-top: -2ch; + font-size: clamp(2rem, 5vw, 5rem); +} +#landing p { + max-width: 100%; +} + +#sign_in, +#sign_up { + grid-template-rows: auto 1fr; + align-items: center; +} +#sign_in section, +#sign_up section { + margin-top: -6rem; + justify-self: center; + width: min(24rem, 100%); +} +#sign_in sm-form, +#sign_up sm-form { + margin: 2rem 0; +} +#sign_in header, +#sign_up header { + padding: 1.5rem 0; +} + +#sign_up .h2 { + margin-bottom: 0.5rem; +} +#sign_up .card { + margin: 1.5rem 0; +} +#sign_up h5 { + font-weight: 500; + color: rgba(var(--text-color), 0.8); +} +#sign_up .warning { + margin-top: 2rem; +} + +#loading { + place-content: center; + text-align: center; +} +#loading sm-spinner { + margin-bottom: 1.5rem; +} + +#main_header { + position: -webkit-sticky; + position: sticky; + top: 0; + display: grid; + gap: 1rem; + padding: 1rem; + align-items: center; + grid-template-columns: 1fr auto auto; + grid-column: 1/-1; + background-color: var(--foreground-color); + z-index: 2; +} + +#options_panel { + position: -webkit-sticky; + position: sticky; + top: 6.5rem; + z-index: 1; + padding: 0.5rem 1.5rem; + grid-column: 1/-1; + background-color: var(--foreground-color); + overflow-x: auto; + min-height: 3.2rem; +} + +.outline-button { + position: relative; + white-space: nowrap; + justify-content: center; + padding: 0.5rem 0; +} +.outline-button::after { + position: absolute; + content: ""; + width: 1rem; + border-radius: 0.5rem; + height: 0.2rem; + transition: transform 0.3s, opacity 0.1s; + bottom: 0; + background-color: rgba(var(--text-color), 0.5); + opacity: 0; +} +.outline-button:hover:not(.outline-button--active)::after { + opacity: 1; + background-color: rgba(var(--text-color), 0.5); +} +.outline-button:active::after { + opacity: 1; + transform: scaleX(2); +} +.outline-button--active::after { + opacity: 1; + background-color: var(--accent-color); +} + +.label { + font-size: 0.8rem; + color: rgba(var(--text-color), 0.8); + margin-bottom: 0.2rem; +} + +.icon--success { + fill: var(--green); +} + +.icon--failure, +.icon--error { + fill: var(--danger-color); +} + +#main_page { + -ms-scroll-chaining: none; + overscroll-behavior: contain; + height: 100%; + overflow-y: hidden; + grid-template-columns: minmax(0, 1fr); + align-content: flex-start; +} + +#article_list_popup { + --width: min(64rem, 100%); + --min-height: 70vh; +} +#article_list_popup .popup__header { + padding: 1rem; + gap: 1rem; + padding-bottom: 0; + grid-template-columns: minmax(0, 1fr); +} + +#article_list { + grid-template-columns: repeat(auto-fill, minmax(30ch, 1fr)); +} + +.article-link { + position: relative; + padding: 1rem; + color: rgba(var(--text-color), 0.8); + font-weight: 500; + border-radius: 0.3rem; +} +.article-link::first-letter { + text-transform: uppercase; +} + +.default-article::before { + content: ""; + font-size: 0.7rem; + background-color: var(--accent-color); + height: 2em; + width: 0.3em; + border-radius: 0.5rem; + font-weight: 500; + margin-right: 0.5rem; + align-self: center; + color: var(--foreground-color); +} + +#edit_sections_popup { + --body-padding: 1.2rem; +} + +#section_list_container { + gap: 0.5rem; +} + +.section-card { + font-weight: 500; + font-size: 0.9rem; +} +.section-card input { + background-color: rgba(var(--text-color), 0.06); + padding: 0.8rem; + border-radius: 0.3rem; + border: none; + font-size: inherit; + color: inherit; + font-weight: inherit; + width: 100%; +} +.section-card input:focus { + outline: var(--accent-color) solid; +} +.section-card .remove { + padding: 0.3rem; +} + +#insert_section_button { + align-self: flex-start; +} + +#article_wrapper { + display: flex; + flex-direction: column; + padding: 1rem; + gap: 1rem 0; + height: 100%; + overflow-y: auto; + scroll-padding-top: 1.5rem; +} + +.heading { + font-weight: 700; +} +.heading::before { + content: ""; + width: 0.3rem; + height: 100%; + margin-right: 0.7rem; + border-radius: 0.5rem; + background-color: var(--accent-color); +} +.heading button { + margin-left: auto; +} + +.article-section { + gap: 1rem; +} +.article-section:not(:last-of-type) { + margin-bottom: 1.5rem; +} +.article-section::-webkit-scrollbar { + display: none; +} + +.content-card { + border-radius: 0.5rem; + background-color: var(--foreground-color); + box-shadow: 0 0 0 1px rgba(var(--text-color), 0.16) inset; +} +.content-card.selected { + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; +} +.content-card--empty { + display: flex; + flex-direction: column; +} +.content-card--empty .content__area { + min-height: calc(60vh + 3rem); + height: 100%; + max-height: calc(60vh + 3rem); +} +.content-card .submit-entry { + border-radius: 0.2rem; + padding: 0.4rem 0.8rem; + color: var(--accent-color); +} +.content-card .submit-entry sm-spinner { + --height: 0.8rem; + --width: 0.8rem; +} + +.content__header { + padding: 0.5rem; +} + +.content__area { + border-radius: inherit; + padding: 1rem; + white-space: pre-line; + font-size: 0.9rem; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + background-color: rgba(var(--text-color), 0.02); + border-radius: 0.5rem; + transition: box-shadow 0.1s; + height: 60vh; + overflow-y: auto; +} +.content__area:empty::before { + content: attr(placeholder); + opacity: 0.6; + pointer-events: none; +} +.content__area:focus-within { + outline: none; + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; +} + +.content__options { + gap: 0.5rem; + padding: 0.5rem 1rem; + grid-template-columns: auto auto 1fr auto; +} + +.content__contributors { + font-size: 0.7rem; + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.3rem; + padding: 0.2rem 0.3rem; + color: rgba(var(--text-color), 0.8); + margin-right: 0.5rem; +} + +.content__author { + display: grid; + gap: 0.3rem; + grid-template-columns: auto -webkit-max-content; + grid-template-columns: auto max-content; +} +.content__author div:first-of-type { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.content__author div:last-of-type { + flex: 1; +} + +.content__score { + font-size: 0.8rem; + margin-left: 0.2rem; + line-height: 100%; +} + +.score-button--filled .icon { + fill: var(--yellow); +} + +.actionable-button { + padding: 0.5rem 0.8rem; + background-color: rgba(var(--text-color), 0.1); + border-radius: 2rem; + border: solid thin rgba(var(--text-color), 0.3); +} +.actionable-button__title { + font-size: 0.8rem; + margin-left: 0.3rem; +} + +#text_toolbar { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: fixed; + z-index: 10; + left: 0; + right: 0; + bottom: 0; + transition: transform 0.1s; + background-color: var(--foreground-color); + border: solid thin rgba(var(--text-color), 0.2); + padding: 0.2rem; + border-radius: 0.3rem; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.06), 0 1rem 1.5rem -0.5rem rgba(0, 0, 0, 0.2); +} + +.formatting-button { + padding: 0.3rem; + border-radius: 0.3rem; + transition: background-color 0.1s; +} +.formatting-button.active:hover { + background-color: var(--accent-color); +} + +.active { + background-color: var(--accent-color); +} +.active .icon { + fill: var(--foreground-color); +} + +.quote-template { + position: relative; + padding: 1rem; + margin: 1rem 0; + border-radius: 0.2rem; + border: solid thin rgba(var(--text-color), 0.3); + box-shadow: 0.1rem 0.2rem 0 0.1rem rgba(var(--text-color), 0.8); + overflow: hidden; + justify-self: center; + padding-left: 1.3rem figcaption; + padding-left-margin-top: 0.5rem; + padding-left-color: rgba(var(--text-color), 0.8); + padding-left-font-size: 0.8rem; + padding-left-margin-left: auto; +} + +#version_history_panel { + border-radius: 0.5rem; + width: min(24rem, 100%); + background-color: var(--foreground-color); + overflow-y: auto; +} +#version_history_panel > :first-child { + padding: 1rem; +} + +#version_timeline { + padding: 1rem; + height: 100%; + overflow-y: auto; +} + +.history-entry { + grid-template-columns: minmax(0, 1fr); +} +.history-entry:not(:last-of-type) { + padding-bottom: 1rem; + border-bottom: thin solid rgba(var(--text-color), 0.3); +} +.history-entry:last-of-type::before { + content: "CREATED"; + letter-spacing: 0.03em; + display: inline-flex; + justify-self: flex-start; + font-weight: 500; + padding: 0.2rem 0.3rem; + font-size: 0.7rem; + border-radius: 0.2rem; + border: solid thin rgba(var(--text-color), 0.5); +} + +.entry__time, +.entry__author { + font-size: 0.8rem; + font-weight: 500; +} + +.entry__changes { + font-size: 0.9rem; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + overflow-wrap: break-word; + white-space: pre-line; +} +.entry__changes .added > *, +.entry__changes .removed > * { + background-color: transparent; +} +.entry__changes .added, +.entry__changes .added > * { + overflow-wrap: break-word; + background-color: #00e67650; +} +.entry__changes .removed, +.entry__changes .removed > * { + overflow-wrap: break-word; + color: var(--danger-color); + -webkit-text-decoration-color: var(--danger-color); + text-decoration-color: var(--danger-color); +} + +.contributor { + gap: 0.5rem; + grid-template-columns: auto 1fr; +} +.contributor .icon { + grid-row: span 2; +} +.contributor__id { + font-size: 0.8rem; + font-weight: 700; +} +.contributor__time { + font-size: 0.8rem; +} + +#preview_page { + padding-bottom: 3rem; + grid-template-columns: 1.5rem minmax(0, 1fr) 1.5rem; + overflow-y: auto; + height: 100%; + align-content: flex-start; +} +#preview_page header { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1; + padding: 1.5rem 0 1rem 0; + background-color: rgba(var(--background-color), 1); +} +#preview_page h1, +#preview_page h2, +#preview_page h3, +#preview_page h4, +#preview_page h5, +#preview_page h6 { + font-weight: 400; + font-family: "Calistoga", cursive; +} +#preview_page h3 { + margin-bottom: 1rem; +} +#preview_page h3:not(:first-of-type) { + margin-top: 3rem; +} +#preview_page p { + font-size: 1rem; +} +#preview_page p * { + font-size: inherit; + font-family: inherit; +} + +#preview__body { + padding: 1.5rem 0; +} + +.preview-group:not(:last-of-type) { + margin-bottom: 1.5rem; +} + +.preview-group__buttons { + display: inline-flex; + background-color: var(--foreground-color); + border: solid thin rgba(var(--text-color), 0.2); + padding: 0.2rem; + border-radius: 0.3rem; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.06), 0 1rem 1.5rem -0.5rem rgba(0, 0, 0, 0.2); +} +.preview-group__buttons button { + padding: 0.5rem; +} +.preview-group__buttons button .icon { + height: 1rem; + width: 1rem; +} + +#publish_article_popup { + --min-height: 50vh; +} + +@media screen and (max-width: 40rem) { + #article_name_wrapper, +#selected_content_options { + grid-row: 2/3; + grid-column: 1/-1; + } + #article_name_wrapper #article_outline_button, +#selected_content_options #article_outline_button { + margin-left: auto; + } + + #article_name_wrapper { + justify-content: flex-start; + } + + .article-section { + display: flex; + -ms-scroll-snap-type: x mandatory; + scroll-snap-type: x mandatory; + overflow-x: auto; + flex-shrink: 0; + } + + .content-card { + scroll-snap-align: start; + flex-shrink: 0; + width: min(45ch, 100% - 2rem); + } + + .formatting-button { + padding: 0.5rem; + } + + .hide-on-mobile { + display: none; + } +} +@media screen and (min-width: 40rem) { + sm-popup { + --width: 24rem; + } + + .h1 { + font-size: 2rem; + } + + .h2 { + font-size: 1.8rem; + } + + .h3 { + font-size: 1.3rem; + } + + .h4 { + font-size: 1rem; + } + + .popup__header { + grid-column: 1/-1; + padding: 1rem 1.5rem 0 0.5rem; + } + + #confirmation_popup { + --width: 24rem; + } + + .page-layout { + grid-template-columns: 1fr 90vw 1fr; + } + + .hide-on-desktop { + display: none; + } + + #main_header { + padding: 1rem 1.5rem; + grid-template-columns: auto 1fr auto auto; + } + + #options_panel { + top: 4.2rem; + } + + #main_page.active-sidebar { + grid-template-rows: auto 1fr; + grid-template-columns: minmax(0, 1fr) 24rem; + } + #main_page.active-outline { + grid-template-rows: auto 1fr; + grid-template-columns: 20rem minmax(0, 1fr); + } + #main_page.active-sidebar.active-outline { + grid-template-rows: auto 1fr; + grid-template-columns: 20rem minmax(0, 1fr) 24rem; + } + + #version_history_panel, +#article_outline_panel, +#article_wrapper { + -ms-scroll-chaining: none; + overscroll-behavior: contain; + } + + #article_wrapper { + padding: 1.5rem; + } + + .article-section { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(40ch, 1fr)); + } + + #article_list_popup .popup__header { + grid-template-columns: auto 1fr auto; + padding-bottom: 1rem; + } + + #article_list_search { + width: 16rem; + } + + #preview_page { + grid-template-columns: 1fr 60ch 1fr; + } + + .preview-group { + position: relative; + } + + .preview-group__buttons { + position: absolute; + right: 0; + bottom: 100%; + } + + #text_toolbar { + position: absolute; + z-index: 1; + left: 0; + top: 0; + right: auto; + bottom: auto; + } + + #create_article_popup { + --width: 28rem; + } + + #user_popup { + --width: 25rem; + } +} +@media (any-hover: hover) { + ::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; + } + + ::-webkit-scrollbar-thumb { + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(var(--text-color), 0.5); + } + + .interact, +button:not(.button--primary) { + transition: background-color 0.3s; + } + .interact:hover, +button:not(.button--primary):hover { + background-color: rgba(var(--text-color), 0.06); + } + + .button--primary { + transition: filter 0.3s; + } + .button--primary:hover { + filter: brightness(120%); + } + + .content-card:not(.selected) sm-checkbox { + opacity: 0; + transition: opacity 0.2s; + } + .content-card:hover sm-checkbox, .content-card:focus-within sm-checkbox { + opacity: 1; + } + + .preview-group__buttons { + transition: opacity 0.1s; + opacity: 0; + } + + .preview-group { + border-radius: 0.3rem; + } + .preview-group:hover { + background-color: rgba(var(--text-color), 0.06); + } + .preview-group:hover .preview-group__buttons { + opacity: 1; + } + .preview-group .preview-group__buttons:focus-within { + opacity: 1; + } } \ No newline at end of file diff --git a/css/main.min.css b/css/main.min.css index 2d38acb..68a6b0a 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -@import"https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap";*{padding:0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:"Roboto",sans-serif}html{scroll-behavior:smooth}body{--accent-color: #00a566;--light-shade: rgba(var(--text-color), 0.06);--text-color: 17, 17, 17;--text-color-light: 100, 100, 100;--foreground-color: 255, 255, 255;--background-color: #efefef;--error-color: red;color:rgba(var(--text-color), 1);height:calc(100%);font-size:clamp(1rem, 1.2vmax, 3rem);background:rgba(var(--foreground-color), 1)}body[data-theme=dark]{--accent-color:#00fa9a;--text-color: 240, 240, 240;--text-color-light: 170, 170, 170;--foreground-color: 20, 20, 20;--error-color: rgb(255, 106, 106)}button{position:relative;overflow:hidden;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:none;background:none;cursor:pointer;outline:none;color:inherit;font-weight:500;-webkit-tap-highlight-color:transparent}.button{border-radius:.2rem;padding:.5rem .6rem}.button--primary{background:var(--accent-color);color:rgba(var(--foreground-color), 1)}.button--primary .icon{fill:rgba(var(--foreground-color), 1)}button:focus-visible{outline:rgba(var(--text-color), 1) .1rem solid}sm-input,sm-textarea{--border-radius: 0.2rem;--background: rgba(var(--text-color), 0.06)}sm-button{--border-radius: 0.2rem}ul{list-style:none}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-1r{gap:1rem}.align-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-right{margin-left:auto}.direction-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.full-width{width:100%}.margin-top-1-5{margin-top:1.5rem}.margin-bottom-1-5{margin-bottom:1.5rem}.margin-left-0-5{margin-left:.5rem}.margin-right-0-5{margin-right:.5rem}.hide{opacity:0;pointer-events:none}.hide-completely{display:none !important}.no-transformations{-webkit-transform:none !important;transform:none !important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ripple{position:absolute;border-radius:50%;-webkit-transform:scale(0);transform:scale(0);background:rgba(var(--text-color), 0.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color), 0.9)}.icon-only{height:2.6rem;width:2.6rem;padding:.6rem}.close-icon{padding:.3rem}.close-button{left:-0.5rem}.option__icon{height:1.2rem;width:1.2rem;margin-right:.8rem}.option__label{font-size:1rem}#confirmation_popup,#prompt_popup{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;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{padding:.5rem 1.5rem 0 1rem;display:grid;grid-template-columns:auto 1fr auto;gap:.5rem;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.popup__header__close{padding:.5rem;cursor:pointer}h1,h2,h3,h4,h5{font-family:"Roboto Slab",sans-serif}p{line-height:1.6}button:focus{outline:none}button:focus-visible{outline:auto}button:first-of-type{margin-left:auto}button[disabled]{opacity:.5 !important;cursor:default;color:rgba(var(--text-color), 1)}textarea{background:var(--light-shade);color:rgba(var(--text-color), 1);padding:1.5rem;max-width:100%;font-size:1rem}.checkbox__label{margin-left:1rem}.spacer{-webkit-box-flex:1;-ms-flex:1;flex:1}.solid-background{background:var(--background-color)}#context_menu{display:none}.article__header{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;margin-bottom:2rem}#article__title{font-size:1.2rem}#articles_list__button{width:3rem;height:3rem;margin-left:-0.8rem;margin-right:.5rem;fill:rgba(var(--text-color), 1);cursor:pointer}#articles_list__button .icon-only{height:4rem;width:4rem}.gallery-name{padding:.2rem 0;margin:1rem 0;font-size:1.1rem;color:rgba(var(--text-color), 1);font-weight:500;line-height:1.5}.edit-article{margin-left:auto}#edit_article_popup label{font-size:.9rem}#edit_article_popup input:not([type=checkbox]){margin-bottom:2rem;margin-top:.5rem;width:100%}#edit_section_container{gap:1.5rem;padding:1rem 0}.gallery-container{position:relative;overflow:hidden}.navigation-arrows{-webkit-transition:opacity .2s ease;transition:opacity .2s ease;cursor:pointer;padding:1rem;height:4rem;width:4rem;z-index:2;position:absolute;top:50%;fill:rgba(var(--text-color), 1);-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s, -webkit-transform .3s;background:rgba(var(--foreground-color), 0.9);-webkit-box-shadow:0 .5rem 1rem rgba(0,0,0,.16);box-shadow:0 .5rem 1rem rgba(0,0,0,.16)}.navigation-arrows:nth-of-type(1){border-radius:0 50% 50% 0;-webkit-transform:translate(-1rem, -50%);transform:translate(-1rem, -50%)}.navigation-arrows:nth-of-type(1):hover{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.navigation-arrows:nth-of-type(2){right:0;border-radius:50% 0 0 50%;-webkit-transform:translate(1rem, -50%);transform:translate(1rem, -50%)}.navigation-arrows:nth-of-type(2):hover{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.gallery{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;overflow-x:auto;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;margin-bottom:4rem !important}.article-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;scroll-snap-align:start;min-width:30%;background-color:rgba(var(--text-color), 0.06);color:rgba(var(--text-color), 1);margin:0 1rem 1rem 0;border-radius:.2rem}.article-body .article-header{padding:1.5rem;word-break:break-all}.article__author{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;font-weight:normal;font-size:.8rem;color:#a7c5eb}.article-body .card-body{position:relative;-webkit-box-flex:1;-ms-flex:1;flex:1}.article-body .card-body .content-div{padding:0 1.5rem 4rem 1.5rem;min-height:16rem;line-height:1.7;max-height:50vh;overflow-y:auto;font-weight:400;overflow-wrap:break-word}.article-body .card-body .content-div *{overflow-wrap:break-word}.article-body .card-body button{position:absolute;bottom:0;right:0;margin-right:1rem}.article-body .card-body .submit-btn{background:var(--light-shade)}.article-body .card-footer{display:-webkit-box;display:-ms-flexbox;display:flex;padding:1rem 1.5rem}.article-body .card-footer h5{display:-webkit-box;display:-ms-flexbox;display:flex;font-weight:normal;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--accent-color);cursor:pointer}.article-body .card-footer h5:nth-of-type(2){margin-left:auto}.article-body .card-footer h5:nth-of-type(2):hover svg{fill:var(--accent-color)}.article-body .card-footer h5 svg{stroke:var(--accent-color);width:1.2rem;margin-right:.5rem}.show{opacity:1;pointer-events:all}.hide{opacity:0;pointer-events:none}#article_container{padding:1rem 2rem;width:100%}.select-for-export{padding:.2rem .4rem;border-radius:.1rem}.snippet-selected{-webkit-box-shadow:0 0 0 .1rem var(--accent-color);box-shadow:0 0 0 .1rem var(--accent-color)}.no-transformations{-webkit-transform:none !important;transform:none !important}:-webkit-any-link{color:var(--accent-color);text-decoration:none}:-moz-any-link{color:var(--accent-color);text-decoration:none}:any-link{color:var(--accent-color);text-decoration:none}#sign_in{--backdrop: rgba(var(--foreground-color), 1)}#sign_in h2{margin-bottom:1rem;z-index:3}#sign_in p:first-of-type{margin-bottom:4rem;z-index:3;color:rgba(var(--text-color), 0.8)}#sign_in .back-btn{margin-bottom:2rem;padding-left:0;color:rgba(var(--text-color), 1)}.sign-in-mode__button{height:8rem;width:8rem}.big-icon{fill:none;stroke:rgba(var(--text-color), 1)}#sign_in div:first-of-type{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:4rem;z-index:3}#sign_in div:first-of-type .icon{height:3rem;width:3rem;stroke-width:4;margin-bottom:1rem;margin-right:0}#sign_in div:first-of-type button{margin:initial;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;text-align:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:.5rem;width:8rem;color:rgba(var(--text-color), 1);background:rgba(var(--foreground), 1)}#sign_in div:first-of-type button:hover{color:var(--accent-color)}#sign_in div:first-of-type button:hover .icon{stroke:var(--accent-color)}#sign_in #priv_key_sign_in{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column wrap;flex-flow:column wrap;z-index:3}#sign_in_button{margin:1rem 0 2rem 0;width:100%;background:rgba(var(--text-color), 0.06);-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}#navbar{position:-webkit-sticky;position:sticky;top:0;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:rgba(var(--text-color), 1);background:rgba(var(--foreground-color), 1);padding:1rem;z-index:5}#navbar h5{font-size:.8rem;font-weight:normal;margin-bottom:.2rem}.app-name{font-size:1rem;font-weight:700}#icon{width:2rem;height:2rem;margin:0 .5rem}#export_option_list{gap:1rem;grid-auto-flow:column;margin-right:1rem}.floating-btn{display:none}#loader_container{position:fixed;height:100vh;width:100vw;top:0;background:rgba(var(--foreground-color), 1);-webkit-transition:opacity .6s ease;transition:opacity .6s ease;display:-ms-grid;display:grid;place-content:center;z-index:8;text-align:center}#loader_container #spinner{position:relative;height:2rem;fill:teal;overflow:visible;-ms-grid-column-align:center;justify-self:center;margin-bottom:2rem}#loader_container h4{font-weight:normal;color:rgba(var(--text-color), 1)}#loader_container button{margin:1rem auto auto auto}.pulse .first-orb{-webkit-animation:pulse 1s infinite ease;animation:pulse 1s infinite ease}.pulse .second-orb{-webkit-animation:pulse 1s .1s infinite ease;animation:pulse 1s .1s infinite ease}.pulse .third-orb{-webkit-animation:pulse 1s .2s infinite ease;animation:pulse 1s .2s infinite ease}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);transform:scale(1)}60%{-webkit-transform:scale(1.5);transform:scale(1.5)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);transform:scale(1)}60%{-webkit-transform:scale(1.5);transform:scale(1.5)}100%{-webkit-transform:scale(1);transform:scale(1)}}.spin svg{-webkit-animation:spin .6s ease infinite;animation:spin .6s ease infinite;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}#section_plot_popup p{margin:1rem 0;font-weight:400}#section_plot_popup details{margin-bottom:1rem;cursor:pointer}#section_plot_popup summary{outline:none}#inc_section{gap:1rem;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}#article_list_popup{--height: 80vh;--min-height: 80vh;--body-padding: 0}#article_list__header{grid-template-columns:auto 1fr}#article_list{display:grid;margin-bottom:1.5rem;list-style:none;grid-template-columns:repeat(auto-fill, minmax(30ch, 1fr))}.article-list__item{width:100%;height:100%;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;font-size:1rem;text-transform:none;text-align:left;font-weight:400;border-radius:.3rem;line-height:1.6;letter-spacing:normal;word-spacing:normal;padding:1rem 1.5rem;color:rgba(var(--text-color), 0.9)}.search__icon{height:1.2rem;width:1.2rem}#article_list__empty-state{width:100%;padding:3rem 0;font-size:1.2rem;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}@media screen and (min-width: 640px){sm-popup{--width: 24rem}#sign_in{width:24rem;height:auto;border-radius:.4rem}#edit_article_popup{--width: 32rem}#article__title{width:100%;text-align:center;font-size:2rem}.gallery-name{max-width:40rem}#section_plot_popup{--width: 42rem}#article_list__header{grid-template-columns:auto 1fr auto;padding:1rem 1.5rem}#article_list_popup{--width: 80vw}}@media screen and (min-width: 1920px){.article-body{min-width:20%}}.label{margin-bottom:.4rem;font-weight:500}@media only screen and (max-width: 640px){.hide-on-mobile{display:none}.article-body{min-width:calc(100% - 2em) !important}#export_option_list{position:absolute;top:0;left:0;width:100%;height:100%;padding:.5rem;z-index:2;background:rgba(var(--foreground-color), 1);-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.floating-btn{display:-webkit-box;display:-ms-flexbox;display:flex;margin:2rem;background:rgba(var(--foreground-color), 1);position:fixed;-webkit-box-shadow:.2rem .4rem .6rem rgba(0,0,0,.24),-0.1rem -0.2rem .4rem rgba(0,0,0,.16);box-shadow:.2rem .4rem .6rem rgba(0,0,0,.24),-0.1rem -0.2rem .4rem rgba(0,0,0,.16);z-index:3}.floating-btn button{width:100%}.floating-btn{background:#282828;bottom:0;right:0;border-radius:5rem;overflow:hidden}.floating-btn button{padding:1rem}.floating-btn button .icon{margin-right:0}#article_container{padding:1.5rem 1.5rem 6rem 1.5rem}.navigation-arrows{opacity:0;pointer-events:none}#article_list__header{padding-bottom:1rem}#article_list__search{width:100%;grid-column:1/3}}@media only screen and (max-width: 1280px){.article-body{min-width:50%}.hide-on-medium{display:none}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}.gallery{overflow-x:hidden}} \ 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%;scroll-behavior:smooth}body{color:rgba(var(--text-color), 1);background:rgba(var(--background-color), 1)}body,body *{--accent-color: rgb(0, 156, 78);--text-color: 36, 36, 36;--background-color: 248, 248, 248;--foreground-color: rgb(255, 255, 255);--danger-color: rgb(255, 75, 75);--green: #1cad59;--yellow: #f3a600;scrollbar-width:thin}body[data-theme=dark],body[data-theme=dark] *{--accent-color: rgb(14, 230, 122);--text-color: 230, 230, 230;--text-color-light: 170, 170, 170;--background-color: 10, 10, 10;--foreground-color: rgb(24, 24, 24);--danger-color: rgb(255, 106, 106);--green: #00e676;--yellow: #ffd13a}body[data-theme=dark] sm-popup::part(popup){background-color:var(--foreground-color)}p,strong{font-size:.9rem;max-width:70ch;line-height:1.7;color:rgba(var(--text-color), 0.8)}p:not(:last-of-type),strong:not(:last-of-type){margin-bottom:1.5rem}a{color:var(--accent-color);text-decoration:none;overflow:hidden}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color), 1) inset}button,.button{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:relative;display:inline-flex;border:none;background-color:transparent;overflow:hidden;color:inherit;cursor:pointer;transition:transform .3s;-webkit-tap-highlight-color:transparent;align-items:center;font-size:.9rem;font-weight:500;overflow:hidden}.button{white-space:nowrap;padding:.5rem .8rem;border-radius:.3rem;background-color:rgba(var(--text-color), 0.06);color:rgba(var(--text-color), 0.8);justify-content:center}.button--primary{background-color:var(--accent-color);color:rgba(var(--background-color), 1)}.icon-only{padding:.5rem;border-radius:.3rem}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}sm-input,sm-textarea,tags-input{font-size:.9rem;--border-radius: 0.3rem}sm-button{--padding: 0.5rem 0.8rem;transition:transform .3s;overflow:hidden}sm-button[variant=primary]{--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.uppercase{letter-spacing:.05em}sm-button.danger{--background: var(--danger-color);color:rgba(var(--background-color), 1)}ul{list-style:none}.hide-completely{display:none !important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/-1}.h1{font-size:1.5rem}.h2{font-size:1.2rem}.h3{font-size:1rem}.h4{font-size:.9rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.direction-column{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.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}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.empty-state{display:grid;width:100%;padding:1.5rem 1rem}.observe-empty-state:empty{display:none !important}.observe-empty-state:not(:empty)+.empty-state{display:none !important}.icon{width:1.2rem;height:1.2rem;fill:rgba(var(--text-color), 0.8);flex-shrink:0}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}.icon-button{padding:.6rem;border-radius:.8rem;background-color:rgba(var(--text-color), 0.1);height:-webkit-max-content;height:-moz-max-content;height:max-content}.icon-button .icon{fill:var(--accent-color)}#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}#prompt_message{margin-bottom:1.5rem}.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}.logo{display:grid;align-items:center;width:100%;grid-template-columns:auto 1fr;gap:0 .3rem}.logo h4{text-transform:capitalize;font-size:.9rem}.logo .main-logo{height:1.4rem;width:1.4rem;fill:rgba(var(--text-color), 1);stroke:none}details summary{display:flex;justify-content:space-between;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer}details[open]>summary{margin-bottom:1rem}details[open]>summary .icon{transform:rotate(180deg)}sm-select,sm-option,strip-option{font-size:.9rem}strip-select{--gap: 0}strip-option{font-weight:500;--border-radius: 0.3rem;--active-option-color: var(--accent-color)}sm-checkbox{--height: 1rem;--width: 1rem;-webkit-tap-highlight-color:transparent}sm-menu{--background: var(--foreground-color)}menu-option{font-size:.9rem}sm-copy{font-size:.9rem;--button-border-radius: 0.2rem}.warning{background-color:khaki;color:rgba(0,0,0,.7);padding:1rem;border-radius:.5rem;line-height:1.5}.page{height:100%}.page-layout,#preview_page{display:grid;grid-template-columns:1rem minmax(0, 1fr) 1rem}.page-layout>*,#preview_page>*{grid-column:2/3}#landing{grid-template-rows:auto 1fr}#landing header{padding:1.5rem 0}#landing>section{align-items:center;text-align:center}#landing h1{margin-top:-2ch;font-size:clamp(2rem,5vw,5rem)}#landing p{max-width:100%}#sign_in,#sign_up{grid-template-rows:auto 1fr;align-items:center}#sign_in section,#sign_up section{margin-top:-6rem;justify-self:center;width:min(24rem,100%)}#sign_in sm-form,#sign_up sm-form{margin:2rem 0}#sign_in header,#sign_up header{padding:1.5rem 0}#sign_up .h2{margin-bottom:.5rem}#sign_up .card{margin:1.5rem 0}#sign_up h5{font-weight:500;color:rgba(var(--text-color), 0.8)}#sign_up .warning{margin-top:2rem}#loading{place-content:center;text-align:center}#loading sm-spinner{margin-bottom:1.5rem}#main_header{position:-webkit-sticky;position:sticky;top:0;display:grid;gap:1rem;padding:1rem;align-items:center;grid-template-columns:1fr auto auto;grid-column:1/-1;background-color:var(--foreground-color);z-index:2}#options_panel{position:-webkit-sticky;position:sticky;top:6.5rem;z-index:1;padding:.5rem 1.5rem;grid-column:1/-1;background-color:var(--foreground-color);overflow-x:auto;min-height:3.2rem}.outline-button{position:relative;white-space:nowrap;justify-content:center;padding:.5rem 0}.outline-button::after{position:absolute;content:"";width:1rem;border-radius:.5rem;height:.2rem;transition:transform .3s,opacity .1s;bottom:0;background-color:rgba(var(--text-color), 0.5);opacity:0}.outline-button:hover:not(.outline-button--active)::after{opacity:1;background-color:rgba(var(--text-color), 0.5)}.outline-button:active::after{opacity:1;transform:scaleX(2)}.outline-button--active::after{opacity:1;background-color:var(--accent-color)}.label{font-size:.8rem;color:rgba(var(--text-color), 0.8);margin-bottom:.2rem}.icon--success{fill:var(--green)}.icon--failure,.icon--error{fill:var(--danger-color)}#main_page{-ms-scroll-chaining:none;overscroll-behavior:contain;height:100%;overflow-y:hidden;grid-template-columns:minmax(0, 1fr);align-content:flex-start}#article_list_popup{--width: min(64rem, 100%);--min-height: 70vh}#article_list_popup .popup__header{padding:1rem;gap:1rem;padding-bottom:0;grid-template-columns:minmax(0, 1fr)}#article_list{grid-template-columns:repeat(auto-fill, minmax(30ch, 1fr))}.article-link{position:relative;padding:1rem;color:rgba(var(--text-color), 0.8);font-weight:500;border-radius:.3rem}.article-link::first-letter{text-transform:uppercase}.default-article::before{content:"";font-size:.7rem;background-color:var(--accent-color);height:2em;width:.3em;border-radius:.5rem;font-weight:500;margin-right:.5rem;align-self:center;color:var(--foreground-color)}#edit_sections_popup{--body-padding: 1.2rem}#section_list_container{gap:.5rem}.section-card{font-weight:500;font-size:.9rem}.section-card input{background-color:rgba(var(--text-color), 0.06);padding:.8rem;border-radius:.3rem;border:none;font-size:inherit;color:inherit;font-weight:inherit;width:100%}.section-card input:focus{outline:var(--accent-color) solid}.section-card .remove{padding:.3rem}#insert_section_button{align-self:flex-start}#article_wrapper{display:flex;flex-direction:column;padding:1rem;gap:1rem 0;height:100%;overflow-y:auto;scroll-padding-top:1.5rem}.heading{font-weight:700}.heading::before{content:"";width:.3rem;height:100%;margin-right:.7rem;border-radius:.5rem;background-color:var(--accent-color)}.heading button{margin-left:auto}.article-section{gap:1rem}.article-section:not(:last-of-type){margin-bottom:1.5rem}.article-section::-webkit-scrollbar{display:none}.content-card{border-radius:.5rem;background-color:var(--foreground-color);box-shadow:0 0 0 1px rgba(var(--text-color), 0.16) inset}.content-card.selected{box-shadow:0 0 0 .1rem var(--accent-color) inset}.content-card--empty{display:flex;flex-direction:column}.content-card--empty .content__area{min-height:calc(60vh + 3rem);height:100%;max-height:calc(60vh + 3rem)}.content-card .submit-entry{border-radius:.2rem;padding:.4rem .8rem;color:var(--accent-color)}.content-card .submit-entry sm-spinner{--height: 0.8rem;--width: 0.8rem}.content__header{padding:.5rem}.content__area{border-radius:inherit;padding:1rem;white-space:pre-line;font-size:.9rem;line-height:1.7;color:rgba(var(--text-color), 0.8);background-color:rgba(var(--text-color), 0.02);border-radius:.5rem;transition:box-shadow .1s;height:60vh;overflow-y:auto}.content__area:empty::before{content:attr(placeholder);opacity:.6;pointer-events:none}.content__area:focus-within{outline:none;box-shadow:0 0 0 .1rem var(--accent-color) inset}.content__options{gap:.5rem;padding:.5rem 1rem;grid-template-columns:auto auto 1fr auto}.content__contributors{font-size:.7rem;background-color:rgba(var(--text-color), 0.06);border-radius:.3rem;padding:.2rem .3rem;color:rgba(var(--text-color), 0.8);margin-right:.5rem}.content__author{display:grid;gap:.3rem;grid-template-columns:auto -webkit-max-content;grid-template-columns:auto max-content}.content__author div:first-of-type{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.content__author div:last-of-type{flex:1}.content__score{font-size:.8rem;margin-left:.2rem;line-height:100%}.score-button--filled .icon{fill:var(--yellow)}.actionable-button{padding:.5rem .8rem;background-color:rgba(var(--text-color), 0.1);border-radius:2rem;border:solid thin rgba(var(--text-color), 0.3)}.actionable-button__title{font-size:.8rem;margin-left:.3rem}#text_toolbar{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:fixed;z-index:10;left:0;right:0;bottom:0;transition:transform .1s;background-color:var(--foreground-color);border:solid thin rgba(var(--text-color), 0.2);padding:.2rem;border-radius:.3rem;box-shadow:0 .1rem .2rem rgba(0,0,0,.06),0 1rem 1.5rem -0.5rem rgba(0,0,0,.2)}.formatting-button{padding:.3rem;border-radius:.3rem;transition:background-color .1s}.formatting-button.active:hover{background-color:var(--accent-color)}.active{background-color:var(--accent-color)}.active .icon{fill:var(--foreground-color)}.quote-template{position:relative;padding:1rem;margin:1rem 0;border-radius:.2rem;border:solid thin rgba(var(--text-color), 0.3);box-shadow:.1rem .2rem 0 .1rem rgba(var(--text-color), 0.8);overflow:hidden;justify-self:center;padding-left:1.3rem figcaption;padding-left-margin-top:.5rem;padding-left-color:rgba(var(--text-color), 0.8);padding-left-font-size:.8rem;padding-left-margin-left:auto}#version_history_panel{border-radius:.5rem;width:min(24rem,100%);background-color:var(--foreground-color);overflow-y:auto}#version_history_panel>:first-child{padding:1rem}#version_timeline{padding:1rem;height:100%;overflow-y:auto}.history-entry{grid-template-columns:minmax(0, 1fr)}.history-entry:not(:last-of-type){padding-bottom:1rem;border-bottom:thin solid rgba(var(--text-color), 0.3)}.history-entry:last-of-type::before{content:"CREATED";letter-spacing:.03em;display:inline-flex;justify-self:flex-start;font-weight:500;padding:.2rem .3rem;font-size:.7rem;border-radius:.2rem;border:solid thin rgba(var(--text-color), 0.5)}.entry__time,.entry__author{font-size:.8rem;font-weight:500}.entry__changes{font-size:.9rem;line-height:1.7;color:rgba(var(--text-color), 0.8);overflow-wrap:break-word;white-space:pre-line;}.entry__changes .added>*,.entry__changes .removed>*{background-color:transparent}.entry__changes .added,.entry__changes .added>*{overflow-wrap:break-word;background-color:#00e67650}.entry__changes .removed,.entry__changes .removed>*{overflow-wrap:break-word;color:var(--danger-color);-webkit-text-decoration-color:var(--danger-color);text-decoration-color:var(--danger-color)}.contributor{gap:.5rem;grid-template-columns:auto 1fr}.contributor .icon{grid-row:span 2}.contributor__id{font-size:.8rem;font-weight:700}.contributor__time{font-size:.8rem}#preview_page{padding-bottom:3rem;grid-template-columns:1.5rem minmax(0, 1fr) 1.5rem;overflow-y:auto;height:100%;align-content:flex-start}#preview_page header{position:-webkit-sticky;position:sticky;top:0;z-index:1;padding:1.5rem 0 1rem 0;background-color:rgba(var(--background-color), 1)}#preview_page h1,#preview_page h2,#preview_page h3,#preview_page h4,#preview_page h5,#preview_page h6{font-weight:400;font-family:"Calistoga",cursive}#preview_page h3{margin-bottom:1rem}#preview_page h3:not(:first-of-type){margin-top:3rem}#preview_page p{font-size:1rem}#preview_page p *{font-size:inherit;font-family:inherit}#preview__body{padding:1.5rem 0}.preview-group:not(:last-of-type){margin-bottom:1.5rem}.preview-group__buttons{display:inline-flex;background-color:var(--foreground-color);border:solid thin rgba(var(--text-color), 0.2);padding:.2rem;border-radius:.3rem;box-shadow:0 .1rem .2rem rgba(0,0,0,.06),0 1rem 1.5rem -0.5rem rgba(0,0,0,.2)}.preview-group__buttons button{padding:.5rem}.preview-group__buttons button .icon{height:1rem;width:1rem}#publish_article_popup{--min-height: 50vh}@media screen and (max-width: 40rem){#article_name_wrapper,#selected_content_options{grid-row:2/3;grid-column:1/-1}#article_name_wrapper #article_outline_button,#selected_content_options #article_outline_button{margin-left:auto}#article_name_wrapper{justify-content:flex-start}.article-section{display:flex;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;overflow-x:auto;flex-shrink:0}.content-card{scroll-snap-align:start;flex-shrink:0;width:min(45ch,100% - 2rem)}.formatting-button{padding:.5rem}.hide-on-mobile{display:none}}@media screen and (min-width: 40rem){sm-popup{--width: 24rem}.h1{font-size:2rem}.h2{font-size:1.8rem}.h3{font-size:1.3rem}.h4{font-size:1rem}.popup__header{grid-column:1/-1;padding:1rem 1.5rem 0 .5rem}#confirmation_popup{--width: 24rem}.page-layout{grid-template-columns:1fr 90vw 1fr}.hide-on-desktop{display:none}#main_header{padding:1rem 1.5rem;grid-template-columns:auto 1fr auto auto}#options_panel{top:4.2rem}#main_page.active-sidebar{grid-template-rows:auto 1fr;grid-template-columns:minmax(0, 1fr) 24rem}#main_page.active-outline{grid-template-rows:auto 1fr;grid-template-columns:20rem minmax(0, 1fr)}#main_page.active-sidebar.active-outline{grid-template-rows:auto 1fr;grid-template-columns:20rem minmax(0, 1fr) 24rem}#version_history_panel,#article_outline_panel,#article_wrapper{-ms-scroll-chaining:none;overscroll-behavior:contain}#article_wrapper{padding:1.5rem}.article-section{display:grid;grid-template-columns:repeat(auto-fill, minmax(40ch, 1fr))}#article_list_popup .popup__header{grid-template-columns:auto 1fr auto;padding-bottom:1rem}#article_list_search{width:16rem}#preview_page{grid-template-columns:1fr 60ch 1fr}.preview-group{position:relative}.preview-group__buttons{position:absolute;right:0;bottom:100%}#text_toolbar{position:absolute;z-index:1;left:0;top:0;right:auto;bottom:auto}#create_article_popup{--width: 28rem}#user_popup{--width: 25rem}}@media(any-hover: hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color), 0.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color), 0.5)}.interact,button:not(.button--primary){transition:background-color .3s}.interact:hover,button:not(.button--primary):hover{background-color:rgba(var(--text-color), 0.06)}.button--primary{transition:filter .3s}.button--primary:hover{filter:brightness(120%)}.content-card:not(.selected) sm-checkbox{opacity:0;transition:opacity .2s}.content-card:hover sm-checkbox,.content-card:focus-within sm-checkbox{opacity:1}.preview-group__buttons{transition:opacity .1s;opacity:0}.preview-group{border-radius:.3rem}.preview-group:hover{background-color:rgba(var(--text-color), 0.06)}.preview-group:hover .preview-group__buttons{opacity:1}.preview-group .preview-group__buttons:focus-within{opacity:1}} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss index 854ac07..3cfa03e 100644 --- a/css/main.scss +++ b/css/main.scss @@ -1,984 +1,1172 @@ -@import url('https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap'); - -* { - padding: 0; - margin: 0; - -webkit-box-sizing: border-box; - box-sizing: border-box; - font-family: 'Roboto', sans-serif; -} -html { - scroll-behavior: smooth; -} - -body { - --accent-color: #00a566; - --light-shade: rgba(var(--text-color), 0.06); - --text-color: 17, 17, 17; - --text-color-light: 100, 100, 100; - --foreground-color: 255, 255, 255; - --background-color: #efefef; - --error-color: red; - color: rgba(var(--text-color), 1); - height: calc(100%); - font-size: clamp(1rem, 1.2vmax, 3rem); - background: rgba(var(--foreground-color), 1); -} -body[data-theme='dark']{ - --accent-color:#00fa9a; - --text-color: 240, 240, 240; - --text-color-light: 170, 170, 170; - --foreground-color: 20, 20, 20; - --error-color: rgb(255, 106, 106); -} - -button{ - position: relative; - overflow: hidden; - display: inline-flex; - align-items: center; - border: none; - background: none; - cursor: pointer; - outline: none; - color: inherit; - font-weight: 500; - -webkit-tap-highlight-color: transparent; -} -.button{ - border-radius: 0.2rem; - padding: 0.5rem 0.6rem; -} -.button--primary{ - background: var(--accent-color); - color: rgba(var(--foreground-color), 1); - .icon{ - fill: rgba(var(--foreground-color), 1); - } -} -button:focus-visible{ - outline: rgba(var(--text-color), 1) 0.1rem solid; -} -sm-input, -sm-textarea{ - --border-radius: 0.2rem; - --background: rgba(var(--text-color), 0.06); -} -sm-button{ - --border-radius: 0.2rem; -} -ul{ - list-style: none; -} -.flex{ - display: flex; -} -.grid{ - display: grid; -} -.flow-column{ - grid-auto-flow: column; -} -.gap-1r{ - gap: 1rem; -} -.align-center{ - align-items: center; -} -.justify-right{ - margin-left: auto; -} -.direction-column{ - flex-direction: column; -} -.space-between{ - justify-content: space-between; -} -.full-width{ - width: 100%; -} -.margin-top-1-5{ - margin-top: 1.5rem; -} -.margin-bottom-1-5{ - margin-bottom: 1.5rem; -} -.margin-left-0-5{ - margin-left: 0.5rem; -} -.margin-right-0-5{ - margin-right: 0.5rem; -} -.hide{ - opacity: 0; - pointer-events: none; -} -.hide-completely{ - display: none !important; -} -.no-transformations{ - transform: none !important; -} -.overflow-ellipsis{ - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.ripple{ - position: absolute; - border-radius: 50%; - transform: scale(0); - background: rgba(var(--text-color), 0.16); - pointer-events: none; -} -.interact{ - position: relative; - overflow: hidden; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} -.observe-empty-state:empty{ - display: none; -} -.observe-empty-state:not(:empty) ~ .empty-state{ - display: none; -} -.icon{ - width: 1.5rem; - height: 1.5rem; - fill: rgba(var(--text-color), 0.9); -} -.icon-only{ - height: 2.6rem; - width: 2.6rem; - padding: 0.6rem; -} -.close-icon{ - padding: 0.3rem; -} -.close-button{ - left: -0.5rem; -} - -.option__icon{ - height: 1.2rem; - width: 1.2rem; - margin-right: 0.8rem; -} -.option__label{ - font-size: 1rem; -} - -#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{ - padding: 0.5rem 1.5rem 0 1rem; - display: grid; - grid-template-columns: auto 1fr auto; - gap: 0.5rem; - align-items: center; - width: 100%; -} -.popup__header__close{ - padding: 0.5rem; - cursor: pointer; -} - - -h1, -h2, -h3, -h4, -h5 { - font-family: 'Roboto Slab', sans-serif; -} - -p { - line-height: 1.6; -} - -button:focus { - outline: none; -} -button:focus-visible{ - outline: auto; -} - -button:first-of-type { - margin-left: auto; -} - - -button[disabled] { - opacity: 0.5 !important; - cursor: default; - color: rgba(var(--text-color), 1); -} - -textarea { - background: var(--light-shade); - color: rgba(var(--text-color), 1); - padding: 1.5rem; - max-width: 100%; - font-size: 1rem; -} - -.checkbox__label{ - margin-left: 1rem; -} - -.spacer { - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.solid-background { - background: var(--background-color); -} - -#context_menu { - display: none; -} - -.article__header { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - width: 100%; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - margin-bottom: 2rem; -} - -#article__title{ - font-size: 1.2rem; -} - -#articles_list__button{ - width: 3rem; - height: 3rem; - margin-left: -0.8rem; - margin-right: 0.5rem; - fill: rgba(var(--text-color), 1); - cursor: pointer; - .icon-only{ - height: 4rem; - width: 4rem; - } -} - -.gallery-name { - padding: 0.2rem 0; - margin: 1rem 0; - font-size: 1.1rem; - color: rgba(var(--text-color), 1); - font-weight: 500; - line-height: 1.5; -} - -.edit-article { - margin-left: auto; -} - -#edit_article_popup label { - font-size: 0.9rem; -} - -#edit_article_popup input:not([type="checkbox"]) { - margin-bottom: 2rem; - margin-top: 0.5rem; - width: 100%; -} - -#edit_section_container { - gap: 1.5rem; - padding: 1rem 0; -} - -.gallery-container { - position: relative; - overflow: hidden; -} - -.navigation-arrows { - -webkit-transition: opacity 0.2s ease; - transition: opacity 0.2s ease; - cursor: pointer; - padding: 1rem; - height: 4rem; - width: 4rem; - z-index: 2; - position: absolute; - top: 50%; - fill: rgba(var(--text-color), 1); - transition: transform 0.3s; - background: rgba(var(--foreground-color), 0.9); - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.16); -} - -.navigation-arrows:nth-of-type(1) { - border-radius: 0 50% 50% 0; - transform: translate(-1rem, -50%); - &:hover{ - transform: translate(0, -50%); - } -} - -.navigation-arrows:nth-of-type(2) { - right: 0; - border-radius: 50% 0 0 50%; - transform: translate(1rem, -50%); - &:hover{ - transform: translate(0, -50%); - } -} - -.gallery { - position: relative; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - overflow-x: auto; - -ms-scroll-snap-type: x mandatory; - scroll-snap-type: x mandatory; - margin-bottom: 4rem !important; -} - -.article-body { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - scroll-snap-align: start; - min-width: 30%; - background-color: rgba(var(--text-color), 0.06); - color: rgba(var(--text-color), 1); - margin: 0 1rem 1rem 0; - border-radius: 0.2rem; -} - -.article-body .article-header { - padding: 1.5rem; - word-break: break-all; -} - -.article__author { - display: inline-flex; - font-weight: normal; - font-size: 0.8rem; - color: #a7c5eb; -} - -.article-body .card-body { - position: relative; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.article-body .card-body .content-div { - padding: 0 1.5rem 4rem 1.5rem; - min-height: 16rem; - line-height: 1.7; - max-height: 50vh; - overflow-y: auto; - font-weight: 400; - overflow-wrap: break-word; -} - -.article-body .card-body .content-div * { - overflow-wrap: break-word; -} - -.article-body .card-body button { - position: absolute; - bottom: 0; - right: 0; - margin-right: 1rem; -} - -.article-body .card-body .submit-btn { - background: var(--light-shade); -} - -.article-body .card-footer { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - padding: 1rem 1.5rem; -} - -.article-body .card-footer h5 { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - font-weight: normal; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - color: var(--accent-color); - cursor: pointer; -} - -.article-body .card-footer h5:nth-of-type(2) { - margin-left: auto; -} - -.article-body .card-footer h5:nth-of-type(2):hover svg { - fill: var(--accent-color); -} - -.article-body .card-footer h5 svg { - stroke: var(--accent-color); - width: 1.2rem; - margin-right: 0.5rem; -} - -.show { - opacity: 1; - pointer-events: all; -} - -.hide { - opacity: 0; - pointer-events: none; -} - -#article_container { - padding: 1rem 2rem; - width: 100%; -} - -.select-for-export{ - padding: 0.2rem 0.4rem; - border-radius: 0.1rem; -} - -.snippet-selected { - box-shadow: 0 0 0 0.1rem var(--accent-color); -} - -.no-transformations { - -webkit-transform: none !important; - transform: none !important; -} - -:-webkit-any-link { - color: var(--accent-color); - text-decoration: none; -} - -:-moz-any-link { - color: var(--accent-color); - text-decoration: none; -} - -:any-link { - color: var(--accent-color); - text-decoration: none; -} - -#sign_in { - --backdrop: rgba(var(--foreground-color), 1); -} - -#sign_in h2 { - margin-bottom: 1rem; - z-index: 3; -} - -#sign_in p:first-of-type { - margin-bottom: 4rem; - z-index: 3; - color: rgba(var(--text-color), 0.8); -} - -#sign_in .back-btn { - margin-bottom: 2rem; - padding-left: 0; - color: rgba(var(--text-color), 1); -} -.sign-in-mode__button{ - height: 8rem; - width: 8rem; -} -.big-icon{ - fill: none; - stroke: rgba(var(--text-color), 1); -} - -#sign_in div:first-of-type { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - margin-bottom: 4rem; - z-index: 3; -} - -#sign_in div:first-of-type .icon { - height: 3rem; - width: 3rem; - stroke-width: 4; - margin-bottom: 1rem; - margin-right: 0; -} - -#sign_in div:first-of-type button { - margin: initial; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - margin: 0.5rem; - width: 8rem; - color: rgba(var(--text-color), 1); - background: rgba(var(--foreground), 1); -} - -#sign_in div:first-of-type button:hover { - color: var(--accent-color); -} - -#sign_in div:first-of-type button:hover .icon { - stroke: var(--accent-color); -} - -#sign_in #priv_key_sign_in { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-flow: column wrap; - flex-flow: column wrap; - z-index: 3; -} - - -#sign_in_button{ - margin: 1rem 0 2rem 0; - width: 100%; - background: rgba(var(--text-color), 0.06); - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; -} - -#navbar { - position: sticky; - top: 0; - width: 100%; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - color: rgba(var(--text-color), 1); - background: rgba(var(--foreground-color), 1); - padding: 1rem; - z-index: 5; -} - -#navbar h5 { - font-size: 0.8rem; - font-weight: normal; - margin-bottom: 0.2rem; -} - -.app-name{ - font-size: 1rem; - font-weight: 700; -} - -#icon { - width: 2rem; - height: 2rem; - margin: 0 0.5rem; -} - -#export_option_list{ - gap: 1rem; - grid-auto-flow: column; - margin-right: 1rem; -} - -.floating-btn { - display: none; -} - -#loader_container { - position: fixed; - height: 100vh; - width: 100vw; - top: 0; - background: rgba(var(--foreground-color), 1); - -webkit-transition: opacity 0.6s ease; - transition: opacity 0.6s ease; - display: -ms-grid; - display: grid; - place-content: center; - z-index: 8; - text-align: center; -} - -#loader_container #spinner { - position: relative; - height: 2rem; - fill: teal; - overflow: visible; - -ms-grid-column-align: center; - justify-self: center; - margin-bottom: 2rem; -} - -#loader_container h4 { - font-weight: normal; - color: rgba(var(--text-color), 1); -} - -#loader_container button { - margin: 1rem auto auto auto; -} - -.pulse .first-orb { - -webkit-animation: pulse 1s infinite ease; - animation: pulse 1s infinite ease; -} - -.pulse .second-orb { - -webkit-animation: pulse 1s 0.1s infinite ease; - animation: pulse 1s 0.1s infinite ease; -} - -.pulse .third-orb { - -webkit-animation: pulse 1s 0.2s infinite ease; - animation: pulse 1s 0.2s infinite ease; -} - -@-webkit-keyframes pulse { - 0% { - -webkit-transform: scale(1); - transform: scale(1); - } - - 60% { - -webkit-transform: scale(1.5); - transform: scale(1.5); - } - - 100% { - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes pulse { - 0% { - -webkit-transform: scale(1); - transform: scale(1); - } - - 60% { - -webkit-transform: scale(1.5); - transform: scale(1.5); - } - - 100% { - -webkit-transform: scale(1); - transform: scale(1); - } -} - -.spin svg { - -webkit-animation: spin 0.6s ease infinite; - animation: spin 0.6s ease infinite; - -webkit-transform-origin: center; - transform-origin: center; -} - -@-webkit-keyframes spin { - 0% { - -webkit-transform: rotate(0); - transform: rotate(0); - } - - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} - -@keyframes spin { - 0% { - -webkit-transform: rotate(0); - transform: rotate(0); - } - - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} - -#section_plot_popup p { - margin: 1rem 0; - font-weight: 400; -} - -#section_plot_popup details { - margin-bottom: 1rem; - cursor: pointer; -} - -#section_plot_popup summary { - outline: none; -} - -#scoring_popup{ - -} - -#inc_section{ - gap: 1rem; - justify-content: flex-start; -} - - -#article_list_popup { - --height: 80vh; - --min-height: 80vh; - --body-padding: 0; -} - -#article_list__header{ - grid-template-columns: auto 1fr; -} - -#article_list{ - display: grid; - margin-bottom: 1.5rem; - list-style: none; - grid-template-columns: repeat(auto-fill, minmax(30ch, 1fr)); -} - -.article-list__item{ - width: 100%; - height: 100%; - align-items: flex-start; - font-size: 1rem; - text-transform: none; - text-align: left; - font-weight: 400; - border-radius: 0.3rem; - line-height: 1.6; - letter-spacing: normal; - word-spacing: normal; - padding: 1rem 1.5rem; - color: rgba(var(--text-color), 0.9); -} - -.search__icon{ - height: 1.2rem; - width: 1.2rem; -} - -#article_list__empty-state{ - width: 100%; - padding: 3rem 0; - font-size: 1.2rem; - justify-content: center; -} - -@media screen and (min-width: 640px) { - sm-popup{ - --width: 24rem; - } - #sign_in { - width: 24rem; - height: auto; - border-radius: 0.4rem; - } - #edit_article_popup{ - --width: 32rem; - } - - #article__title{ - width: 100%; - text-align: center; - font-size: 2rem; - } - - .gallery-name { - max-width: 40rem; - } - - #section_plot_popup { - --width: 42rem; - } - - - #article_list__header{ - grid-template-columns: auto 1fr auto; - padding: 1rem 1.5rem; - } - #article_list_popup { - --width: 80vw; - } -} - -@media screen and (min-width: 1920px) { - .article-body { - min-width: 20%; - } -} -.label { - margin-bottom: 0.4rem; - font-weight: 500; -} - -@media only screen and (max-width: 640px) { - .hide-on-mobile { - display: none; - } - - .article-body { - min-width: calc(100% - 2em) !important; - } - - #export_option_list{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - padding: 0.5rem; - z-index: 2; - background: rgba(var(--foreground-color), 1); - justify-content: space-between; - } - - .floating-btn { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - margin: 2rem; - background: rgba(var(--foreground-color), 1); - position: fixed; - -webkit-box-shadow: 0.2rem 0.4rem 0.6rem rgba(0, 0, 0, 0.24), -0.1rem -0.2rem 0.4rem rgba(0, 0, 0, 0.16); - box-shadow: 0.2rem 0.4rem 0.6rem rgba(0, 0, 0, 0.24), -0.1rem -0.2rem 0.4rem rgba(0, 0, 0, 0.16); - z-index: 3; - } - - .floating-btn button { - width: 100%; - } - - .floating-btn { - background: #282828; - bottom: 0; - right: 0; - border-radius: 5rem; - overflow: hidden; - } - - .floating-btn button { - padding: 1rem; - } - - .floating-btn button .icon { - margin-right: 0; - } - - - #article_container { - padding: 1.5rem 1.5rem 6rem 1.5rem; - } - - .navigation-arrows { - opacity: 0; - pointer-events: none; - } - - #article_list__header{ - padding-bottom: 1rem; - } - #article_list__search{ - width: 100%; - grid-column: 1/3; - } -} - -@media only screen and (max-width: 1280px) { - .article-body { - min-width: 50%; - } - - .hide-on-medium { - display: none; - } -} - -@media (any-hover: hover){ - ::-webkit-scrollbar{ - width: 0.5rem; - height: 0.5rem; - } - - ::-webkit-scrollbar-thumb{ - background: rgba(var(--text-color), 0.3); - border-radius: 1rem; - &:hover{ - background: rgba(var(--text-color), 0.5); - } - } - .gallery { - overflow-x: hidden; - } -} \ 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%; + scroll-behavior: smooth; +} + +body { + &, + * { + --accent-color: rgb(0, 156, 78); + --text-color: 36, 36, 36; + --background-color: 248, 248, 248; + --foreground-color: rgb(255, 255, 255); + --danger-color: rgb(255, 75, 75); + --green: #1cad59; + --yellow: #f3a600; + scrollbar-width: thin; + } + + color: rgba(var(--text-color), 1); + background: rgba(var(--background-color), 1); +} + +body[data-theme="dark"] { + &, + * { + --accent-color: rgb(14, 230, 122); + --text-color: 230, 230, 230; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --foreground-color: rgb(24, 24, 24); + --danger-color: rgb(255, 106, 106); + --green: #00e676; + --yellow: #ffd13a; + } + sm-popup::part(popup) { + background-color: var(--foreground-color); + } +} + +p, +strong { + font-size: 0.9rem; + max-width: 70ch; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + + &:not(:last-of-type) { + margin-bottom: 1.5rem; + } +} + +a { + color: var(--accent-color); + text-decoration: none; + overflow: hidden; + &:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} + +button, +.button { + user-select: none; + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + cursor: pointer; + transition: transform 0.3s; + -webkit-tap-highlight-color: transparent; + align-items: center; + font-size: 0.9rem; + font-weight: 500; + overflow: hidden; +} +.button { + white-space: nowrap; + padding: 0.5rem 0.8rem; + border-radius: 0.3rem; + background-color: rgba(var(--text-color), 0.06); + color: rgba(var(--text-color), 0.8); + justify-content: center; + &--primary { + background-color: var(--accent-color); + color: rgba(var(--background-color), 1); + } +} +.icon-only { + padding: 0.5rem; + border-radius: 0.3rem; +} + +button:disabled { + opacity: 0.5; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-input, +sm-textarea, +tags-input { + font-size: 0.9rem; + --border-radius: 0.3rem; +} +sm-button { + --padding: 0.5rem 0.8rem; + transition: transform 0.3s; + overflow: hidden; + &[variant="primary"] { + --padding: 0.8rem; + .icon { + fill: rgba(var(--background-color), 1); + } + } + + &[disabled] { + .icon { + fill: rgba(var(--text-color), 0.6); + } + } + &.uppercase { + letter-spacing: 0.05em; + } + &.danger { + --background: var(--danger-color); + color: rgba(var(--background-color), 1); + } +} +ul { + list-style: none; +} + +.hide-completely { + display: none !important; +} + +.overflow-ellipsis { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/-1; +} + +.h1 { + font-size: 1.5rem; +} + +.h2 { + font-size: 1.2rem; +} + +.h3 { + font-size: 1rem; +} + +.h4 { + font-size: 0.9rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} +.flow-column { + grid-auto-flow: column; +} + +.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; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.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; +} +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.empty-state { + display: grid; + width: 100%; + padding: 1.5rem 1rem; +} + +.observe-empty-state:empty { + display: none !important; +} + +.observe-empty-state:not(:empty) + .empty-state { + display: none !important; +} + +.icon { + width: 1.2rem; + height: 1.2rem; + fill: rgba(var(--text-color), 0.8); + flex-shrink: 0; +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; + + &--left { + margin-right: 0.5rem; + } + + &--right { + margin-left: 0.5rem; + } +} + +.icon-button { + padding: 0.6rem; + border-radius: 0.8rem; + background-color: rgba(var(--text-color), 0.1); + height: max-content; + .icon { + fill: var(--accent-color); + } +} +#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; + } + } +} +#prompt_message { + margin-bottom: 1.5rem; +} + +.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; +} +.logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.3rem; + h4 { + text-transform: capitalize; + font-size: 0.9rem; + } + .main-logo { + height: 1.4rem; + width: 1.4rem; + fill: rgba(var(--text-color), 1); + stroke: none; + } +} +details { + summary { + display: flex; + justify-content: space-between; + user-select: none; + cursor: pointer; + } + + &[open] > summary { + margin-bottom: 1rem; + .icon { + transform: rotate(180deg); + } + } +} +sm-select, +sm-option, +strip-option { + font-size: 0.9rem; +} +strip-select { + --gap: 0; +} +strip-option { + font-weight: 500; + --border-radius: 0.3rem; + --active-option-color: var(--accent-color); +} +sm-checkbox { + --height: 1rem; + --width: 1rem; + -webkit-tap-highlight-color: transparent; +} +sm-menu { + --background: var(--foreground-color); +} +menu-option { + font-size: 0.9rem; +} +sm-copy { + font-size: 0.9rem; + --button-border-radius: 0.2rem; +} +.warning { + background-color: khaki; + color: rgba(0, 0, 0, 0.7); + padding: 1rem; + border-radius: 0.5rem; + line-height: 1.5; +} +.page { + height: 100%; +} +.page-layout, +#preview_page { + display: grid; + grid-template-columns: 1rem minmax(0, 1fr) 1rem; + & > * { + grid-column: 2/3; + } +} +#landing { + grid-template-rows: auto 1fr; + header { + padding: 1.5rem 0; + } + & > section { + align-items: center; + text-align: center; + } + h1 { + margin-top: -2ch; + font-size: clamp(2rem, 5vw, 5rem); + } + p { + max-width: 100%; + } +} + +#sign_in, +#sign_up { + grid-template-rows: auto 1fr; + align-items: center; + section { + margin-top: -6rem; + justify-self: center; + width: min(24rem, 100%); + } + sm-form { + margin: 2rem 0; + } + header { + padding: 1.5rem 0; + } +} +#sign_up { + .h2 { + margin-bottom: 0.5rem; + } + .card { + margin: 1.5rem 0; + } + h5 { + font-weight: 500; + color: rgba(var(--text-color), 0.8); + } + .warning { + margin-top: 2rem; + } +} +#loading { + place-content: center; + text-align: center; + sm-spinner { + margin-bottom: 1.5rem; + } +} + +#main_header { + position: sticky; + top: 0; + display: grid; + gap: 1rem; + padding: 1rem; + align-items: center; + grid-template-columns: 1fr auto auto; + grid-column: 1/-1; + background-color: var(--foreground-color); + z-index: 2; +} + +#options_panel { + position: sticky; + top: 6.5rem; + z-index: 1; + padding: 0.5rem 1.5rem; + grid-column: 1/-1; + background-color: var(--foreground-color); + overflow-x: auto; + min-height: 3.2rem; +} +.outline-button { + position: relative; + white-space: nowrap; + justify-content: center; + padding: 0.5rem 0; + &::after { + position: absolute; + content: ""; + width: 1rem; + border-radius: 0.5rem; + height: 0.2rem; + transition: transform 0.3s, opacity 0.1s; + bottom: 0; + background-color: rgba(var(--text-color), 0.5); + opacity: 0; + } + &:hover:not(.outline-button--active)::after { + opacity: 1; + background-color: rgba(var(--text-color), 0.5); + } + &:active::after { + opacity: 1; + transform: scaleX(2); + } + &--active { + &::after { + opacity: 1; + background-color: var(--accent-color); + } + } +} + +.label { + font-size: 0.8rem; + color: rgba(var(--text-color), 0.8); + margin-bottom: 0.2rem; +} +.icon--success { + fill: var(--green); +} +.icon--failure, +.icon--error { + fill: var(--danger-color); +} + +#main_page { + overscroll-behavior: contain; + height: 100%; + overflow-y: hidden; + grid-template-columns: minmax(0, 1fr); + align-content: flex-start; +} + +#article_list_popup { + --width: min(64rem, 100%); + --min-height: 70vh; + .popup__header { + padding: 1rem; + gap: 1rem; + padding-bottom: 0; + grid-template-columns: minmax(0, 1fr); + } +} +#article_list { + grid-template-columns: repeat(auto-fill, minmax(30ch, 1fr)); +} + +.article-link { + position: relative; + padding: 1rem; + color: rgba(var(--text-color), 0.8); + font-weight: 500; + border-radius: 0.3rem; + &::first-letter { + text-transform: uppercase; + } +} +.default-article { + &::before { + content: ""; + font-size: 0.7rem; + background-color: var(--accent-color); + height: 2em; + width: 0.3em; + border-radius: 0.5rem; + font-weight: 500; + margin-right: 0.5rem; + align-self: center; + color: var(--foreground-color); + } +} + +#edit_sections_popup { + --body-padding: 1.2rem; +} +#section_list_container { + gap: 0.5rem; +} +.section-card { + font-weight: 500; + font-size: 0.9rem; + input { + background-color: rgba(var(--text-color), 0.06); + padding: 0.8rem; + border-radius: 0.3rem; + border: none; + font-size: inherit; + color: inherit; + font-weight: inherit; + width: 100%; + &:focus { + outline: var(--accent-color) solid; + } + } + .remove { + padding: 0.3rem; + } +} +#insert_section_button { + align-self: flex-start; +} + +#article_wrapper { + display: flex; + flex-direction: column; + padding: 1rem; + gap: 1rem 0; + height: 100%; + overflow-y: auto; + scroll-padding-top: 1.5rem; +} + +.heading { + font-weight: 700; + &::before { + content: ""; + width: 0.3rem; + height: 100%; + margin-right: 0.7rem; + border-radius: 0.5rem; + background-color: var(--accent-color); + } + button { + margin-left: auto; + } +} + +.article-section { + gap: 1rem; + &:not(:last-of-type) { + margin-bottom: 1.5rem; + } + &::-webkit-scrollbar { + display: none; + } +} +.content-card { + border-radius: 0.5rem; + background-color: var(--foreground-color); + box-shadow: 0 0 0 1px rgba(var(--text-color), 0.16) inset; + &.selected { + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; + } + &--empty { + display: flex; + flex-direction: column; + .content__area { + min-height: calc(60vh + 3rem); + height: 100%; + max-height: calc(60vh + 3rem); + } + } + .submit-entry { + border-radius: 0.2rem; + padding: 0.4rem 0.8rem; + color: var(--accent-color); + sm-spinner { + --height: 0.8rem; + --width: 0.8rem; + } + } +} +.content__header { + padding: 0.5rem; +} +.content__area { + border-radius: inherit; + padding: 1rem; + white-space: pre-line; + font-size: 0.9rem; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + background-color: rgba(var(--text-color), 0.02); + border-radius: 0.5rem; + transition: box-shadow 0.1s; + height: 60vh; + overflow-y: auto; + &:empty::before { + content: attr(placeholder); + opacity: 0.6; + pointer-events: none; + } + &:focus-within { + outline: none; + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; + } +} +.content__options { + gap: 0.5rem; + padding: 0.5rem 1rem; + grid-template-columns: auto auto 1fr auto; +} +.content__contributors { + font-size: 0.7rem; + background-color: rgba(var(--text-color), 0.06); + border-radius: 0.3rem; + padding: 0.2rem 0.3rem; + color: rgba(var(--text-color), 0.8); + margin-right: 0.5rem; +} +.content__author { + display: grid; + gap: 0.3rem; + grid-template-columns: auto max-content; + div:first-of-type { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + div:last-of-type { + flex: 1; + } +} +.content__score { + font-size: 0.8rem; + margin-left: 0.2rem; + line-height: 100%; +} +.score-button--filled { + .icon { + fill: var(--yellow); + } +} + +.actionable-button { + padding: 0.5rem 0.8rem; + background-color: rgba(var(--text-color), 0.1); + border-radius: 2rem; + border: solid thin rgba(var(--text-color), 0.3); + &__title { + font-size: 0.8rem; + margin-left: 0.3rem; + } +} +#text_toolbar { + user-select: none; + position: fixed; + z-index: 10; + left: 0; + right: 0; + bottom: 0; + transition: transform 0.1s; + background-color: var(--foreground-color); + border: solid thin rgba(var(--text-color), 0.2); + padding: 0.2rem; + border-radius: 0.3rem; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.06), + 0 1rem 1.5rem -0.5rem rgba(0, 0, 0, 0.2); +} +.formatting-button { + padding: 0.3rem; + border-radius: 0.3rem; + transition: background-color 0.1s; + &.active:hover { + background-color: var(--accent-color); + } +} +.active { + background-color: var(--accent-color); + .icon { + fill: var(--foreground-color); + } +} + +.quote-template { + position: relative; + padding: 1rem; + margin: 1rem 0; + border-radius: 0.2rem; + border: solid thin rgba(var(--text-color), 0.3); + -webkit-box-shadow: 0.3rem 0.5rem 0 0.1rem rgba(var(--text-color), 0.8); + box-shadow: 0.1rem 0.2rem 0 0.1rem rgba(var(--text-color), 0.8); + overflow: hidden; + justify-self: center; + padding-left: 1.3rem figcaption { + margin-top: 0.5rem; + color: rgba(var(--text-color), 0.8); + font-size: 0.8rem; + margin-left: auto; + } +} + +#version_history_panel { + border-radius: 0.5rem; + width: min(24rem, 100%); + background-color: var(--foreground-color); + overflow-y: auto; + & > :first-child { + padding: 1rem; + } +} +#version_timeline { + padding: 1rem; + height: 100%; + overflow-y: auto; +} +.history-entry { + grid-template-columns: minmax(0, 1fr); + &:not(:last-of-type) { + padding-bottom: 1rem; + border-bottom: thin solid rgba(var(--text-color), 0.3); + } + &:last-of-type::before { + content: "CREATED"; + letter-spacing: 0.03em; + display: inline-flex; + justify-self: flex-start; + font-weight: 500; + padding: 0.2rem 0.3rem; + font-size: 0.7rem; + border-radius: 0.2rem; + border: solid thin rgba(var(--text-color), 0.5); + } +} +.entry__time, +.entry__author { + font-size: 0.8rem; + font-weight: 500; +} +.entry__changes { + font-size: 0.9rem; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + overflow-wrap: break-word; + white-space: pre-line; + .added > *, + .removed > * { + background-color: transparent; + } + .added, + .added > * { + overflow-wrap: break-word; + background-color: #00e67650; + } + .removed, + .removed > * { + overflow-wrap: break-word; + color: var(--danger-color); + text-decoration-color: var(--danger-color); + } +} + +.contributor { + gap: 0.5rem; + grid-template-columns: auto 1fr; + .icon { + grid-row: span 2; + } + &__id { + font-size: 0.8rem; + font-weight: 700; + } + &__time { + font-size: 0.8rem; + } +} + +#preview_page { + padding-bottom: 3rem; + grid-template-columns: 1.5rem minmax(0, 1fr) 1.5rem; + overflow-y: auto; + height: 100%; + align-content: flex-start; + header { + position: sticky; + top: 0; + z-index: 1; + padding: 1.5rem 0 1rem 0; + background-color: rgba(var(--background-color), 1); + } + h1, + h2, + h3, + h4, + h5, + h6 { + font-weight: 400; + font-family: "Calistoga", cursive; + } + h3 { + margin-bottom: 1rem; + &:not(:first-of-type) { + margin-top: 3rem; + } + } + p { + font-size: 1rem; + & * { + font-size: inherit; + font-family: inherit; + } + } +} +#preview__body { + padding: 1.5rem 0; +} + +.preview-group { + &:not(:last-of-type) { + margin-bottom: 1.5rem; + } +} +.preview-group__buttons { + display: inline-flex; + background-color: var(--foreground-color); + border: solid thin rgba(var(--text-color), 0.2); + padding: 0.2rem; + border-radius: 0.3rem; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.06), + 0 1rem 1.5rem -0.5rem rgba(0, 0, 0, 0.2); + button { + padding: 0.5rem; + .icon { + height: 1rem; + width: 1rem; + } + } +} + +#publish_article_popup { + --min-height: 50vh; +} + +@media screen and (max-width: 40rem) { + #article_name_wrapper, + #selected_content_options { + grid-row: 2/3; + grid-column: 1/-1; + #article_outline_button { + margin-left: auto; + } + } + #article_name_wrapper { + justify-content: flex-start; + } + .article-section { + display: flex; + scroll-snap-type: x mandatory; + overflow-x: auto; + flex-shrink: 0; + } + .content-card { + scroll-snap-align: start; + flex-shrink: 0; + width: min(45ch, calc(100% - 2rem)); + } + .formatting-button { + padding: 0.5rem; + } + .hide-on-mobile { + display: none; + } +} +@media screen and (min-width: 40rem) { + sm-popup { + --width: 24rem; + } + .h1 { + font-size: 2rem; + } + + .h2 { + font-size: 1.8rem; + } + + .h3 { + font-size: 1.3rem; + } + + .h4 { + font-size: 1rem; + } + .popup__header { + grid-column: 1/-1; + padding: 1rem 1.5rem 0 0.5rem; + } + #confirmation_popup { + --width: 24rem; + } + .page-layout { + grid-template-columns: 1fr 90vw 1fr; + } + .hide-on-desktop { + display: none; + } + #main_header { + padding: 1rem 1.5rem; + grid-template-columns: auto 1fr auto auto; + } + #options_panel { + top: 4.2rem; + } + #main_page { + &.active-sidebar { + grid-template-rows: auto 1fr; + grid-template-columns: minmax(0, 1fr) 24rem; + } + &.active-outline { + grid-template-rows: auto 1fr; + grid-template-columns: 20rem minmax(0, 1fr); + } + &.active-sidebar.active-outline { + grid-template-rows: auto 1fr; + grid-template-columns: 20rem minmax(0, 1fr) 24rem; + } + } + #version_history_panel, + #article_outline_panel, + #article_wrapper { + overscroll-behavior: contain; + } + #article_wrapper { + padding: 1.5rem; + } + .article-section { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(40ch, 1fr)); + } + #article_list_popup { + .popup__header { + grid-template-columns: auto 1fr auto; + padding-bottom: 1rem; + } + } + #article_list_search { + width: 16rem; + } + #preview_page { + grid-template-columns: 1fr 60ch 1fr; + } + .preview-group { + position: relative; + } + .preview-group__buttons { + position: absolute; + right: 0; + bottom: 100%; + } + #text_toolbar { + position: absolute; + z-index: 1; + left: 0; + top: 0; + right: auto; + bottom: auto; + } + #create_article_popup { + --width: 28rem; + } + #user_popup { + --width: 25rem; + } +} +@media (any-hover: hover) { + ::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; + } + + ::-webkit-scrollbar-thumb { + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + + &:hover { + background: rgba(var(--text-color), 0.5); + } + } + .interact, + button:not(.button--primary) { + transition: background-color 0.3s; + &:hover { + background-color: rgba(var(--text-color), 0.06); + } + } + .button--primary { + transition: filter 0.3s; + &:hover { + filter: brightness(120%); + } + } + .content-card { + &:not(.selected) sm-checkbox { + opacity: 0; + transition: opacity 0.2s; + } + &:hover sm-checkbox, + &:focus-within sm-checkbox { + opacity: 1; + } + } + .preview-group__buttons { + transition: opacity 0.1s; + opacity: 0; + } + .preview-group { + border-radius: 0.3rem; + &:hover { + background-color: rgba(var(--text-color), 0.06); + .preview-group__buttons { + opacity: 1; + } + } + .preview-group__buttons:focus-within { + opacity: 1; + } + } +} diff --git a/index.html b/index.html index 9132d17..dbfdca6 100644 --- a/index.html +++ b/index.html @@ -1,21764 +1,14643 @@ - - - - - Content Collaboration - - - - - - - - - - -

-

-
- Cancel - OK -
-
- -

-

- -
- Cancel - OK -
-
- - -
- -

Sign In

-
-

Welcome to Content Collaboration.
- Please enter your FLO private key to continue. -

-
- - -
-
- - continue -
-

Don't have a private key? get it here
or you can sign as guest.

-
- -
- -

Update score

-
- -
- + 0.1 - + 1 - + 5 -
-
- Update -
-
- -
- -

All Articles

- - - -
- - -
- No articles found -
-
-
-
-
- - -
- - - - - - - -

- Logout - Back -
- -
-
-
- - - - - - - - - - - - - - - - - - - + + + + + + + + Content Collaboration + + + + + + + + + + + + + + +

+

+
+ Cancel + OK +
+
+
+
+ + +
+
+
+

Create. Collaborate.
Publish.

+

Write something great... Together.

+
+
+
+
+
+ +
+
+

Sign In

+

Welcome back, glad to see you again

+ + + Sign In + +

+ New here? get your FLO login credentials +

+
+
+
+
+ +
+
+

FLO credentials

+

Get your FLO credentials to use RanchiMall CC and all RanchiMall FLO apps.

+
+
+
FLO ID
+ +
+
+
Private key
+ +
+
+ Sign in with these credentials + + Keep your private key secure and don't share with anyone. + Once lost there is no way to recover private key. + +
+
+
+ +

Loading RanchiMall CC

+
+
+
+ +
+ +

+ + + + + + + + + Create new article + + + + + + + + Edit title & sections + + + + + + + + + + + Make default article + + +
+
+ +
+ + +
+
+ + +
+
+
+
Sort by
+ + Most recent + Score + +
+
+
Sections
+
    +
    +
    +
    +
    + + + + + + + +
    + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    +
    +
    +
    + + +
    +

    + No related article +

    +
    + + + + + +
    + Set as default +

    + This article will be opened by default for everyone when CC is first loaded. +

    +
    +
    +
    +
    +

    Define plot (optional)

    +

    Create and name sections by writing section title encapsulated in '()' and each separated by a + '->'. +

    +
    + + +
    + + Create +
    +
    + + +
    +
    +
    Title
    + +
    +
    +
    Sections
    +
    +

    + There are no sections so far, you can add section with button below. +

    +
    +
    + + + + + + + + + + + + + + + + + Insert section + + Save +
    +
    +
    + + +
    +
    + + + Copy link + + + + +
    +
    +
    My FLO ID
    + +
    + Sign out +
    +
    + + + + +
    + + + + + Update +
    +
    +
    + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d2ceab3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "p2p-content-collaboration", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "tiny-editor": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tiny-editor/-/tiny-editor-0.2.5.tgz", + "integrity": "sha512-K4luWQbam/TrgjLst+Ztb7uPltXHwtFm+Oi1hs3xM6biI7N1X8HfyDtmROOEbyJM8+mMP5/FjsMnc96zJZoZCg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fb38828 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "p2p-content-collaboration", + "version": "1.0.0", + "description": "", + "main": "components.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ranchimall/p2p-content-collaboration.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/ranchimall/p2p-content-collaboration/issues" + }, + "homepage": "https://github.com/ranchimall/p2p-content-collaboration#readme", + "dependencies": { + "tiny-editor": "^0.2.5" + } +} diff --git a/purify.min.js b/purify.min.js new file mode 100644 index 0000000..d7f6b35 --- /dev/null +++ b/purify.min.js @@ -0,0 +1,3 @@ +/*! @license DOMPurify 2.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.3/LICENSE */ +!function (e, t) { "object" == typeof exports && "undefined" != typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define(t) : (e = e || self).DOMPurify = t() }(this, (function () { "use strict"; var e = Object.hasOwnProperty, t = Object.setPrototypeOf, n = Object.isFrozen, r = Object.getPrototypeOf, o = Object.getOwnPropertyDescriptor, i = Object.freeze, a = Object.seal, l = Object.create, c = "undefined" != typeof Reflect && Reflect, s = c.apply, u = c.construct; s || (s = function (e, t, n) { return e.apply(t, n) }), i || (i = function (e) { return e }), a || (a = function (e) { return e }), u || (u = function (e, t) { return new (Function.prototype.bind.apply(e, [null].concat(function (e) { if (Array.isArray(e)) { for (var t = 0, n = Array(e.length); t < e.length; t++)n[t] = e[t]; return n } return Array.from(e) }(t)))) }); var m, f = x(Array.prototype.forEach), d = x(Array.prototype.pop), p = x(Array.prototype.push), h = x(String.prototype.toLowerCase), g = x(String.prototype.match), y = x(String.prototype.replace), v = x(String.prototype.indexOf), b = x(String.prototype.trim), T = x(RegExp.prototype.test), A = (m = TypeError, function () { for (var e = arguments.length, t = Array(e), n = 0; n < e; n++)t[n] = arguments[n]; return u(m, t) }); function x(e) { return function (t) { for (var n = arguments.length, r = Array(n > 1 ? n - 1 : 0), o = 1; o < n; o++)r[o - 1] = arguments[o]; return s(e, t, r) } } function S(e, r) { t && t(e, null); for (var o = r.length; o--;) { var i = r[o]; if ("string" == typeof i) { var a = h(i); a !== i && (n(r) || (r[o] = a), i = a) } e[i] = !0 } return e } function w(t) { var n = l(null), r = void 0; for (r in t) s(e, t, [r]) && (n[r] = t[r]); return n } function E(e, t) { for (; null !== e;) { var n = o(e, t); if (n) { if (n.get) return x(n.get); if ("function" == typeof n.value) return x(n.value) } e = r(e) } return function (e) { return console.warn("fallback value for", e), null } } var R = i(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "shadow", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]), _ = i(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]), N = i(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]), D = i(["animate", "color-profile", "cursor", "discard", "fedropshadow", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]), k = i(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover"]), O = i(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]), M = i(["#text"]), L = i(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "noshade", "novalidate", "nowrap", "open", "optimum", "pattern", "placeholder", "playsinline", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "xmlns", "slot"]), F = i(["accent-height", "accumulate", "additive", "alignment-baseline", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "targetx", "targety", "transform", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]), I = i(["accent", "accentunder", "align", "bevelled", "close", "columnsalign", "columnlines", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lspace", "lquote", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]), C = i(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]), z = a(/\{\{[\s\S]*|[\s\S]*\}\}/gm), H = a(/<%[\s\S]*|[\s\S]*%>/gm), U = a(/^data-[\-\w.\u00B7-\uFFFF]/), P = a(/^aria-[\-\w]+$/), j = a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i), B = a(/^(?:\w+script|data):/i), W = a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g), G = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; function q(e) { if (Array.isArray(e)) { for (var t = 0, n = Array(e.length); t < e.length; t++)n[t] = e[t]; return n } return Array.from(e) } var Y = function () { return "undefined" == typeof window ? null : window }, K = function (e, t) { if ("object" !== (void 0 === e ? "undefined" : G(e)) || "function" != typeof e.createPolicy) return null; var n = null, r = "data-tt-policy-suffix"; t.currentScript && t.currentScript.hasAttribute(r) && (n = t.currentScript.getAttribute(r)); var o = "dompurify" + (n ? "#" + n : ""); try { return e.createPolicy(o, { createHTML: function (e) { return e } }) } catch (e) { return console.warn("TrustedTypes policy " + o + " could not be created."), null } }; return function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Y(), n = function (t) { return e(t) }; if (n.version = "2.3.3", n.removed = [], !t || !t.document || 9 !== t.document.nodeType) return n.isSupported = !1, n; var r = t.document, o = t.document, a = t.DocumentFragment, l = t.HTMLTemplateElement, c = t.Node, s = t.Element, u = t.NodeFilter, m = t.NamedNodeMap, x = void 0 === m ? t.NamedNodeMap || t.MozNamedAttrMap : m, V = t.Text, X = t.Comment, $ = t.DOMParser, Z = t.trustedTypes, J = s.prototype, Q = E(J, "cloneNode"), ee = E(J, "nextSibling"), te = E(J, "childNodes"), ne = E(J, "parentNode"); if ("function" == typeof l) { var re = o.createElement("template"); re.content && re.content.ownerDocument && (o = re.content.ownerDocument) } var oe = K(Z, r), ie = oe && ze ? oe.createHTML("") : "", ae = o, le = ae.implementation, ce = ae.createNodeIterator, se = ae.createDocumentFragment, ue = ae.getElementsByTagName, me = r.importNode, fe = {}; try { fe = w(o).documentMode ? o.documentMode : {} } catch (e) { } var de = {}; n.isSupported = "function" == typeof ne && le && void 0 !== le.createHTMLDocument && 9 !== fe; var pe = z, he = H, ge = U, ye = P, ve = B, be = W, Te = j, Ae = null, xe = S({}, [].concat(q(R), q(_), q(N), q(k), q(M))), Se = null, we = S({}, [].concat(q(L), q(F), q(I), q(C))), Ee = null, Re = null, _e = !0, Ne = !0, De = !1, ke = !1, Oe = !1, Me = !1, Le = !1, Fe = !1, Ie = !1, Ce = !0, ze = !1, He = !0, Ue = !0, Pe = !1, je = {}, Be = null, We = S({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]), Ge = null, qe = S({}, ["audio", "video", "img", "source", "image", "track"]), Ye = null, Ke = S({}, ["alt", "class", "for", "id", "label", "name", "pattern", "placeholder", "role", "summary", "title", "value", "style", "xmlns"]), Ve = "http://www.w3.org/1998/Math/MathML", Xe = "http://www.w3.org/2000/svg", $e = "http://www.w3.org/1999/xhtml", Ze = $e, Je = !1, Qe = void 0, et = ["application/xhtml+xml", "text/html"], tt = "text/html", nt = void 0, rt = null, ot = o.createElement("form"), it = function (e) { rt && rt === e || (e && "object" === (void 0 === e ? "undefined" : G(e)) || (e = {}), e = w(e), Ae = "ALLOWED_TAGS" in e ? S({}, e.ALLOWED_TAGS) : xe, Se = "ALLOWED_ATTR" in e ? S({}, e.ALLOWED_ATTR) : we, Ye = "ADD_URI_SAFE_ATTR" in e ? S(w(Ke), e.ADD_URI_SAFE_ATTR) : Ke, Ge = "ADD_DATA_URI_TAGS" in e ? S(w(qe), e.ADD_DATA_URI_TAGS) : qe, Be = "FORBID_CONTENTS" in e ? S({}, e.FORBID_CONTENTS) : We, Ee = "FORBID_TAGS" in e ? S({}, e.FORBID_TAGS) : {}, Re = "FORBID_ATTR" in e ? S({}, e.FORBID_ATTR) : {}, je = "USE_PROFILES" in e && e.USE_PROFILES, _e = !1 !== e.ALLOW_ARIA_ATTR, Ne = !1 !== e.ALLOW_DATA_ATTR, De = e.ALLOW_UNKNOWN_PROTOCOLS || !1, ke = e.SAFE_FOR_TEMPLATES || !1, Oe = e.WHOLE_DOCUMENT || !1, Fe = e.RETURN_DOM || !1, Ie = e.RETURN_DOM_FRAGMENT || !1, Ce = !1 !== e.RETURN_DOM_IMPORT, ze = e.RETURN_TRUSTED_TYPE || !1, Le = e.FORCE_BODY || !1, He = !1 !== e.SANITIZE_DOM, Ue = !1 !== e.KEEP_CONTENT, Pe = e.IN_PLACE || !1, Te = e.ALLOWED_URI_REGEXP || Te, Ze = e.NAMESPACE || $e, Qe = Qe = -1 === et.indexOf(e.PARSER_MEDIA_TYPE) ? tt : e.PARSER_MEDIA_TYPE, nt = "application/xhtml+xml" === Qe ? function (e) { return e } : h, ke && (Ne = !1), Ie && (Fe = !0), je && (Ae = S({}, [].concat(q(M))), Se = [], !0 === je.html && (S(Ae, R), S(Se, L)), !0 === je.svg && (S(Ae, _), S(Se, F), S(Se, C)), !0 === je.svgFilters && (S(Ae, N), S(Se, F), S(Se, C)), !0 === je.mathMl && (S(Ae, k), S(Se, I), S(Se, C))), e.ADD_TAGS && (Ae === xe && (Ae = w(Ae)), S(Ae, e.ADD_TAGS)), e.ADD_ATTR && (Se === we && (Se = w(Se)), S(Se, e.ADD_ATTR)), e.ADD_URI_SAFE_ATTR && S(Ye, e.ADD_URI_SAFE_ATTR), e.FORBID_CONTENTS && (Be === We && (Be = w(Be)), S(Be, e.FORBID_CONTENTS)), Ue && (Ae["#text"] = !0), Oe && S(Ae, ["html", "head", "body"]), Ae.table && (S(Ae, ["tbody"]), delete Ee.tbody), i && i(e), rt = e) }, at = S({}, ["mi", "mo", "mn", "ms", "mtext"]), lt = S({}, ["foreignobject", "desc", "title", "annotation-xml"]), ct = S({}, _); S(ct, N), S(ct, D); var st = S({}, k); S(st, O); var ut = function (e) { var t = ne(e); t && t.tagName || (t = { namespaceURI: $e, tagName: "template" }); var n = h(e.tagName), r = h(t.tagName); if (e.namespaceURI === Xe) return t.namespaceURI === $e ? "svg" === n : t.namespaceURI === Ve ? "svg" === n && ("annotation-xml" === r || at[r]) : Boolean(ct[n]); if (e.namespaceURI === Ve) return t.namespaceURI === $e ? "math" === n : t.namespaceURI === Xe ? "math" === n && lt[r] : Boolean(st[n]); if (e.namespaceURI === $e) { if (t.namespaceURI === Xe && !lt[r]) return !1; if (t.namespaceURI === Ve && !at[r]) return !1; var o = S({}, ["title", "style", "font", "a", "script"]); return !st[n] && (o[n] || !ct[n]) } return !1 }, mt = function (e) { p(n.removed, { element: e }); try { e.parentNode.removeChild(e) } catch (t) { try { e.outerHTML = ie } catch (t) { e.remove() } } }, ft = function (e, t) { try { p(n.removed, { attribute: t.getAttributeNode(e), from: t }) } catch (e) { p(n.removed, { attribute: null, from: t }) } if (t.removeAttribute(e), "is" === e && !Se[e]) if (Fe || Ie) try { mt(t) } catch (e) { } else try { t.setAttribute(e, "") } catch (e) { } }, dt = function (e) { var t = void 0, n = void 0; if (Le) e = "" + e; else { var r = g(e, /^[\r\n\t ]+/); n = r && r[0] } "application/xhtml+xml" === Qe && (e = '' + e + ""); var i = oe ? oe.createHTML(e) : e; if (Ze === $e) try { t = (new $).parseFromString(i, Qe) } catch (e) { } if (!t || !t.documentElement) { t = le.createDocument(Ze, "template", null); try { t.documentElement.innerHTML = Je ? "" : i } catch (e) { } } var a = t.body || t.documentElement; return e && n && a.insertBefore(o.createTextNode(n), a.childNodes[0] || null), Ze === $e ? ue.call(t, Oe ? "html" : "body")[0] : Oe ? t.documentElement : a }, pt = function (e) { return ce.call(e.ownerDocument || e, e, u.SHOW_ELEMENT | u.SHOW_COMMENT | u.SHOW_TEXT, null, !1) }, ht = function (e) { return !(e instanceof V || e instanceof X) && !("string" == typeof e.nodeName && "string" == typeof e.textContent && "function" == typeof e.removeChild && e.attributes instanceof x && "function" == typeof e.removeAttribute && "function" == typeof e.setAttribute && "string" == typeof e.namespaceURI && "function" == typeof e.insertBefore) }, gt = function (e) { return "object" === (void 0 === c ? "undefined" : G(c)) ? e instanceof c : e && "object" === (void 0 === e ? "undefined" : G(e)) && "number" == typeof e.nodeType && "string" == typeof e.nodeName }, yt = function (e, t, r) { de[e] && f(de[e], (function (e) { e.call(n, t, r, rt) })) }, vt = function (e) { var t = void 0; if (yt("beforeSanitizeElements", e, null), ht(e)) return mt(e), !0; if (g(e.nodeName, /[\u0080-\uFFFF]/)) return mt(e), !0; var r = nt(e.nodeName); if (yt("uponSanitizeElement", e, { tagName: r, allowedTags: Ae }), !gt(e.firstElementChild) && (!gt(e.content) || !gt(e.content.firstElementChild)) && T(/<[/\w]/g, e.innerHTML) && T(/<[/\w]/g, e.textContent)) return mt(e), !0; if ("select" === r && T(/