diff --git a/RIBC.html b/RIBC.html deleted file mode 100644 index e267660..0000000 --- a/RIBC.html +++ /dev/null @@ -1,9234 +0,0 @@ - - - - - RIBC - - - - - - -
- RIBC - (use console) -
- - - - - - - - - - - - diff --git a/components-old.js b/components-old.js new file mode 100644 index 0000000..62b535b --- /dev/null +++ b/components-old.js @@ -0,0 +1,3640 @@ +/*jshint esversion: 6 */ +//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 { + + 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, + detail: { + value: this.isChecked + } + })) + } + + 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.chevron.classList.remove('rotate') + this.optionList.animate(this.slideUp, this.animationOptions) + .onfinish = () => { + this.optionList.classList.add('hide') + 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)`, + 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' + } + 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); + } + } +}) + +// strip select +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 + this._value + this.scrollDistance + } + 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() { + 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 (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) + } +}) + +const stripOption = document.createElement('template') +stripOption.innerHTML = ` + + +` + +//Strip option +customElements.define('strip-option', class extends HTMLElement{ + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(stripOption.content.cloneNode(true)) + this._value + this.radioButton = this.shadowRoot.querySelector('input') + } + 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._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) + } +}) + + +//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 + this.isOpen = false + } + + get open() { + return this.isOpen + } + + 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.isOpen = true + } + 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 + } + }) + ) + this.isOpen = false + }, 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)) + + this.isAutoPlaying = false + this.autoPlayInterval = 5000 + this.autoPlayTimeout + this.initialTimeout + this.activeSlideNum = 0 + this.carouselItems + this.indicators + this.showIndicator = false + this.carousel = this.shadowRoot.querySelector('.carousel') + this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') + this.carouselSlot = this.shadowRoot.querySelector('slot') + this.nextArrow = this.shadowRoot.querySelector('.carousel__button--right') + this.previousArrow = this.shadowRoot.querySelector('.carousel__button--left') + this.indicatorsContainer = this.shadowRoot.querySelector('.indicators') + } + + static get observedAttributes() { + return ['indicator', 'autoplay', 'interval'] + } + + scrollLeft = () => { + this.carousel.scrollBy({ + left: -this.scrollDistance, + behavior: 'smooth' + }) + } + + scrollRight = () => { + this.carousel.scrollBy({ + left: this.scrollDistance, + behavior: 'smooth' + }) + } + + handleIndicatorClick = (e) => { + if (e.target.closest('.dot')) { + const slideNum = parseInt(e.target.closest('.dot').dataset.rank) + if (this.activeSlideNum !== slideNum) { + this.showSlide(slideNum) + } + } + } + + showSlide = (slideNum) => { + this.carousel.scrollTo({ + left: (this.carouselItems[slideNum].getBoundingClientRect().left - this.carousel.getBoundingClientRect().left + this.carousel.scrollLeft), + behavior: 'smooth' + }) + } + + nextSlide = () => { + if (!this.carouselItems) return + let showSlideNo = (this.activeSlideNum + 1) < this.carouselItems.length ? this.activeSlideNum + 1 : 0 + this.showSlide(showSlideNo) + } + + autoPlay = () => { + this.nextSlide() + if (this.isAutoPlaying) { + this.autoPlayTimeout = setTimeout(() => { + this.autoPlay() + }, this.autoPlayInterval); + } + } + + startAutoPlay = () => { + this.setAttribute('autoplay', '') + } + + stopAutoPlay = () => { + this.removeAttribute('autoplay') + } + + connectedCallback() { + 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) { + const activeRank = parseInt(entry.target.dataset.rank) + if (entry.isIntersecting) { + this.indicators[activeRank].classList.add('active') + this.activeSlideNum = activeRank + } + else + this.indicators[activeRank].classList.remove('active') + } + if (!entry.target.previousElementSibling) + if (entry.isIntersecting) { + this.previousArrow.classList.remove('expand') + firstVisible = true + } + else { + this.previousArrow.classList.add('expand') + firstVisible = false + } + if (!entry.target.nextElementSibling) + if (entry.isIntersecting) { + this.nextArrow.classList.remove('expand') + lastVisible = true + } + else { + this.nextArrow.classList.add('expand') + lastVisible = false + } + if (firstVisible && lastVisible) + this.indicatorsContainer.classList.add('hide') + else + this.indicatorsContainer.classList.remove('hide') + }) + }, { + root: this.carouselContainer, + threshold: 0.9 + }) + + const carouselObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 + } + }) + + carouselObserver.observe(this.carouselContainer) + + this.carouselSlot.addEventListener('slotchange', e => { + this.carouselItems = this.carouselSlot.assignedElements() + this.carouselItems.forEach(item => allElementsObserver.observe(item)) + if (this.showIndicator) { + this.indicatorsContainer.innerHTML = `` + this.carouselItems.forEach((item, index) => { + let dot = document.createElement('div') + dot.classList.add('dot') + dot.dataset.rank = index + frag.append(dot) + item.dataset.rank = index + }) + this.indicatorsContainer.append(frag) + this.indicators = this.indicatorsContainer.children + } + }) + + this.addEventListener('keyup', e => { + if (e.code === 'ArrowLeft') + this.scrollRight() + else if (e.code === 'ArrowRight') + this.scrollRight() + }) + + this.nextArrow.addEventListener('click', this.scrollRight) + this.previousArrow.addEventListener('click', this.scrollLeft) + this.indicatorsContainer.addEventListener('click', this.handleIndicatorClick) + } + + async attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + if (name === 'indicator') { + if (this.hasAttribute('indicator')) + this.showIndicator = true + else + this.showIndicator = false + } + if (name === 'autoplay') { + if (this.hasAttribute('autoplay')) { + this.initialTimeout = setTimeout(() => { + this.isAutoPlaying = true + this.autoPlay() + }, this.autoPlayInterval); + } + else { + this.isAutoPlaying = false + clearTimeout(this.autoPlayTimeout) + clearTimeout(this.initialTimeout) + } + + } + if (name === 'interval') { + if (this.hasAttribute('interval') && this.getAttribute('interval').trim() !== '') { + this.autoPlayInterval = Math.abs(parseInt(this.getAttribute('interval').trim())) + } + else { + this.autoPlayInterval = 5000 + } + } + } + } + + disconnectedCallback() { + this.nextArrow.removeEventListener('click', this.scrollRight) + this.previousArrow.removeEventListener('click', this.scrollLeft) + this.indicatorsContainer.removeEventListener('click', this.handleIndicatorClick) + } +}) + +//notifications + +const smNotifications = document.createElement('template') +smNotifications.innerHTML = ` + +
+` + +customElements.define('sm-notifications', class extends HTMLElement { + constructor() { + super() + this.shadow = this.attachShadow({ + mode: 'open' + }).append(smNotifications.content.cloneNode(true)) + } + + handleTouchStart = (e) => { + this.notification = e.target.closest('.notification') + this.touchStartX = e.changedTouches[0].clientX + this.notification.style.transition = 'initial' + this.touchStartTime = e.timeStamp + } + + handleTouchMove = (e) => { + e.preventDefault() + if (this.touchStartX < e.changedTouches[0].clientX) { + this.offset = e.changedTouches[0].clientX - this.touchStartX; + this.touchEndAnimataion = requestAnimationFrame(this.movePopup) + } else { + this.offset = -(this.touchStartX - e.changedTouches[0].clientX); + this.touchEndAnimataion = requestAnimationFrame(this.movePopup) + } + } + + handleTouchEnd = (e) => { + this.notification.style.transition = 'transform 0.3s, opacity 0.3s' + this.touchEndTime = e.timeStamp + cancelAnimationFrame(this.touchEndAnimataion) + this.touchEndX = e.changedTouches[0].clientX + if (this.touchEndTime - this.touchStartTime > 200) { + if (this.touchEndX - this.touchStartX > this.threshold) { + this.removeNotification(this.notification) + } else if (this.touchStartX - this.touchEndX > this.threshold) { + this.removeNotification(this.notification, true) + } else { + this.resetPosition() + } + } else { + if (this.touchEndX > this.touchStartX) { + this.removeNotification(this.notification) + } else { + this.removeNotification(this.notification, true) + } + } + } + + movePopup = () => { + this.notification.style.transform = `translateX(${this.offset}px)` + } + + resetPosition = () => { + this.notification.style.transform = `translateX(0)` + } + + push = (messageBody, type, pinned) => { + let notification = document.createElement('div'), + composition = `` + notification.classList.add('notification') + if (pinned) + notification.classList.add('pinned') + if (type === 'error') { + composition += ` + + + + + ` + } else if (type === 'success') { + composition += ` + + + ` + } + composition += ` +

${messageBody}

+ + Close + + + ` + notification.innerHTML = composition + this.notificationPanel.prepend(notification) + if (window.innerWidth > 640) { + notification.animate([{ + transform: `translateX(1rem)`, + opacity: '0' + }, + { + transform: 'translateX(0)', + opacity: '1' + } + ], this.animationOptions).onfinish = () => { + notification.setAttribute('style', `transform: none;`); + } + } else { + notification.setAttribute('style', `transform: translateY(0); opacity: 1`) + } + notification.addEventListener('touchstart', this.handleTouchStart) + notification.addEventListener('touchmove', this.handleTouchMove) + notification.addEventListener('touchend', this.handleTouchEnd) + } + + removeNotification = (notification, toLeft) => { + if (!this.offset) + this.offset = 0; + + if (toLeft) + notification.animate([{ + transform: `translateX(${this.offset}px)`, + opacity: '1' + }, + { + transform: `translateX(-100%)`, + opacity: '0' + } + ], this.animationOptions).onfinish = () => { + notification.remove() + } + else { + notification.animate([{ + transform: `translateX(${this.offset}px)`, + opacity: '1' + }, + { + transform: `translateX(100%)`, + opacity: '0' + } + ], this.animationOptions).onfinish = () => { + notification.remove() + } + } + } + + clearAll = () => { + Array.from(this.notificationPanel.children).forEach(child => { + this.removeNotification(child) + }) + } + + connectedCallback() { + this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') + this.animationOptions = { + duration: 300, + fill: "forwards", + easing: "ease" + } + this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) + this.notification + this.offset + this.touchStartX = 0 + this.touchEndX = 0 + this.touchStartTime = 0 + this.touchEndTime = 0 + this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 + this.touchEndAnimataion; + + this.notificationPanel.addEventListener('click', e => { + if (e.target.closest('.close'))( + this.removeNotification(e.target.closest('.notification')) + ) + }) + + const observer = new MutationObserver(mutationList => { + mutationList.forEach(mutation => { + if (mutation.type === 'childList') { + if (mutation.addedNodes.length) { + if (!mutation.addedNodes[0].classList.contains('pinned')) + setTimeout(() => { + this.removeNotification(mutation.addedNodes[0]) + }, 5000); + if (window.innerWidth > 640) + this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; + else + this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; + } else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { + this.notificationPanel.style.padding = 0; + } + } + }) + }) + observer.observe(this.notificationPanel, { + attributes: true, + childList: true, + subtree: true + }) + } +}) + + + +// sm-menu +const smMenu = document.createElement('template') +smMenu.innerHTML = ` + +
+ +
+ +
+
`; +customElements.define('sm-menu', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smMenu.content.cloneNode(true)) + } + static get observedAttributes() { + return ['value'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + expand = () => { + if (!this.open) { + this.optionList.classList.remove('hide') + this.optionList.classList.add('no-transformations') + this.open = true + this.icon.classList.add('focused') + this.availableOptions.forEach(option => { + option.setAttribute('tabindex', '0') + }) + } + } + collapse() { + if (this.open) { + this.open = false + this.icon.classList.remove('focused') + this.optionList.classList.add('hide') + this.optionList.classList.remove('no-transformations') + this.availableOptions.forEach(option => { + option.removeAttribute('tabindex') + }) + } + } + connectedCallback() { + this.availableOptions + this.containerDimensions + this.optionList = this.shadowRoot.querySelector('.options') + let slot = this.shadowRoot.querySelector('.options slot'), + menu = this.shadowRoot.querySelector('.menu') + this.icon = this.shadowRoot.querySelector('.icon') + this.open = false; + menu.addEventListener('click', e => { + if (!this.open) { + this.expand() + } else { + this.collapse() + } + }) + menu.addEventListener('keydown', e => { + if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { + e.preventDefault() + this.availableOptions[0].focus() + } + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + if (!this.open) { + this.expand() + } else { + this.collapse() + } + } + }) + this.optionList.addEventListener('keydown', e => { + if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } + } + if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { + e.preventDefault() + if (document.activeElement.nextElementSibling) + document.activeElement.nextElementSibling.focus() + } + }) + this.optionList.addEventListener('click', e => { + this.collapse() + }) + slot.addEventListener('slotchange', e => { + this.availableOptions = slot.assignedElements() + this.containerDimensions = this.optionList.getBoundingClientRect() + }); + window.addEventListener('mousedown', e => { + if (!this.contains(e.target) && e.button !== 2) { + this.collapse() + } + }) + } +}) + +// option +const smMenuOption = document.createElement('template') +smMenuOption.innerHTML = ` + +
+ +
`; +customElements.define('sm-menu-option', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smMenuOption.content.cloneNode(true)) + } + + connectedCallback() { + this.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.click() + } + }) + } +}) + +// tab-header + +const smTabHeader = document.createElement('template') +smTabHeader.innerHTML = ` + +
+
+ +
+
+
+`; + +customElements.define('sm-tab-header', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smTabHeader.content.cloneNode(true)) + + this.indicator = this.shadowRoot.querySelector('.indicator'); + this.tabSlot = this.shadowRoot.querySelector('slot'); + this.tabHeader = this.shadowRoot.querySelector('.tab-header'); + } + + sendDetails(element) { + this.dispatchEvent( + new CustomEvent("switchtab", { + bubbles: true, + detail: { + target: this.target, + rank: parseInt(element.getAttribute('rank')) + } + }) + ) + } + + moveIndiactor(tabDimensions) { + //if(this.isTab) + this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) + //else + //this.indicator.setAttribute('style', `width: calc(${tabDimensions.width}px - 1.6rem); transform: translateX(calc(${ tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px + 0.8rem)`) + } + + connectedCallback() { + if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return; + this.prevTab + this.allTabs + this.activeTab + this.isTab = false + this.target = this.getAttribute('target') + + if (this.hasAttribute('variant') && this.getAttribute('variant') === 'tab') { + this.isTab = true + } + + this.tabSlot.addEventListener('slotchange', () => { + this.tabSlot.assignedElements().forEach((tab, index) => { + tab.setAttribute('rank', index) + }) + }) + this.allTabs = this.tabSlot.assignedElements(); + + this.tabSlot.addEventListener('click', e => { + if (e.target === this.prevTab || !e.target.closest('sm-tab')) + return + if (this.prevTab) + this.prevTab.classList.remove('active') + e.target.classList.add('active') + + e.target.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + inline: 'center' + }) + this.moveIndiactor(e.target.getBoundingClientRect()) + this.sendDetails(e.target) + this.prevTab = e.target; + this.activeTab = e.target; + }) + let resizeObserver = new ResizeObserver(entries => { + entries.forEach((entry) => { + if (this.prevTab) { + let tabDimensions = this.activeTab.getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + } + }) + }) + resizeObserver.observe(this) + let observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + this.indicator.style.transition = 'none' + if (this.activeTab) { + let tabDimensions = this.activeTab.getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + } else { + this.allTabs[0].classList.add('active') + let tabDimensions = this.allTabs[0].getBoundingClientRect(); + this.moveIndiactor(tabDimensions) + this.sendDetails(this.allTabs[0]) + this.prevTab = this.tabSlot.assignedElements()[0]; + this.activeTab = this.prevTab; + } + } + }) + }, { + threshold: 1.0 + }) + observer.observe(this) + } +}) + +// tab-panels + +const smTabPanels = document.createElement('template') +smTabPanels.innerHTML = ` + +
+ Nothing to see here. +
+`; + +customElements.define('sm-tab-panels', class extends HTMLElement { + constructor() { + super() + this.attachShadow({ + mode: 'open' + }).append(smTabPanels.content.cloneNode(true)) + this.panelSlot = this.shadowRoot.querySelector('slot'); + } + connectedCallback() { + + //animations + let flyInLeft = [{ + opacity: 0, + transform: 'translateX(-1rem)' + }, + { + opacity: 1, + transform: 'none' + } + ], + flyInRight = [{ + opacity: 0, + transform: 'translateX(1rem)' + }, + { + opacity: 1, + transform: 'none' + } + ], + flyOutLeft = [{ + opacity: 1, + transform: 'none' + }, + { + opacity: 0, + transform: 'translateX(-1rem)' + } + ], + flyOutRight = [{ + opacity: 1, + transform: 'none' + }, + { + opacity: 0, + transform: 'translateX(1rem)' + } + ], + animationOptions = { + duration: 300, + fill: 'forwards', + easing: 'ease' + } + this.prevPanel + this.allPanels + this.previousRank + + this.panelSlot.addEventListener('slotchange', () => { + this.panelSlot.assignedElements().forEach((panel) => { + panel.classList.add('hide-completely') + }) + }) + this.allPanels = this.panelSlot.assignedElements() + this._targetBodyFlyRight = (targetBody) => { + targetBody.classList.remove('hide-completely') + targetBody.animate(flyInRight, animationOptions) + } + this._targetBodyFlyLeft = (targetBody) => { + targetBody.classList.remove('hide-completely') + targetBody.animate(flyInLeft, animationOptions) + } + document.addEventListener('switchtab', e => { + if (e.detail.target !== this.id) + return + + if (this.prevPanel) { + let targetBody = this.allPanels[e.detail.rank], + currentBody = this.prevPanel; + if (this.previousRank < e.detail.rank) { + if (currentBody && !targetBody) + currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + } + else if (targetBody && !currentBody) { + this._targetBodyFlyRight(targetBody) + } else if (currentBody && targetBody) { + currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + this._targetBodyFlyRight(targetBody) + } + } + } else { + if (currentBody && !targetBody) + currentBody.animate(flyOutRight, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + } + else if (targetBody && !currentBody) { + this._targetBodyFlyLeft(targetBody) + } else if (currentBody && targetBody) { + currentBody.animate(flyOutRight, animationOptions).onfinish = () => { + currentBody.classList.add('hide-completely') + this._targetBodyFlyLeft(targetBody) + } + } + } + } else { + this.allPanels[e.detail.rank].classList.remove('hide-completely') + } + this.previousRank = e.detail.rank + this.prevPanel = this.allPanels[e.detail.rank]; + }) + } +}) diff --git a/components.js b/components.js new file mode 100644 index 0000000..ef67c2e --- /dev/null +++ b/components.js @@ -0,0 +1,3767 @@ +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') + } + } + + 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, oldVal, newVal) { + if (name === 'disabled') { + this.removeAttribute('tabindex') + this.setAttribute('aria-disabled', 'true') + } + else { + this.setAttribute('tabindex', '0') + this.setAttribute('aria-disabled', 'false') + } + } + }) +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.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') + } + + reset() { + this.removeAttribute('checked') + } + + 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') + 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 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 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.handleInput = this.handleInput.bind(this) + this.handleKeydown = this.handleKeydown.bind(this) + this.reset = this.reset.bind(this) + } + debounce(callback, wait) { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; + } + handleInput(e) { + 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) { + this.submitButton.click() + } + else { + this.requiredElements.find(elem => !elem.isValid).vibrate() + } + } + } + reset() { + this.formElements.forEach(elem => elem.reset()) + } + connectedCallback() { + const slot = this.shadowRoot.querySelector('slot') + slot.addEventListener('slotchange', e => { + 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 = e.target.assignedElements().find(elem => elem.getAttribute('variant') === 'primary' || elem.getAttribute('type') === 'submit'); + this.resetButton = e.target.assignedElements().find(elem => elem.getAttribute('type') === 'reset'); + if (this.resetButton) { + this.resetButton.addEventListener('click', this.reset) + } + }) + this.addEventListener('input', this.debounce(this.handleInput, 100)) + this.addEventListener('keydown', this.debounce(this.handleKeydown, 100)) + } + disconnectedCallback() { + this.removeEventListener('input', this.debounce(this.handleInput, 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.validationFunction + 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'] + } + + 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 + } + + set disabled(value) { + if (value) + this.inputParent.classList.add('disabled') + else + this.inputParent.classList.remove('disabled') + } + 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.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.feedbackText.textContent = '* required' + this.setAttribute('aria-required', 'true') + } + else { + this.feedbackText.textContent = '' + this.setAttribute('aria-required', 'false') + } + } + 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 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 mey 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.addEventListener('keyup', e => { + if (e.code === 'Enter' || e.code === 'Space') { + e.preventDefault() + this.click() + } + }) + } +}) +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.popupStack + this.offset + this.touchStartY = 0 + this.touchEndY = 0 + this.touchStartTime = 0 + this.touchEndTime = 0 + this.touchEndAnimataion + + this.popupContainer = this.shadowRoot.querySelector('.popup-container') + 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.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.movePopup = this.movePopup.bind(this) + } + + static get observedAttributes() { + return ['open']; + } + + get open() { + return this.isOpen + } + + 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(options = {}) { + const {pinned = false, popupStack = undefined} = options + 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.isOpen = true + } + 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.forms.length) { + setTimeout(() => { + this.forms.forEach(form => form.reset()) + }, 300); + } + setTimeout(() => { + this.dispatchEvent( + new CustomEvent("popupclosed", { + bubbles: true, + detail: { + popup: this, + popupStack: this.popupStack + } + }) + ) + this.isOpen = false + }, 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()) + } + } + + 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.popupBodySlot.addEventListener('slotchange', () => { + this.forms = this.querySelectorAll('sm-form') + }) + this.popupContainer.addEventListener('mousedown', e => { + if (e.target === this.popupContainer && !this.pinned) { + if (this.pinned) { + this.show() + } 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.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 }) + resizeObserver.unobserve() + } + attributeChangedCallback(name, oldVal, newVal) { + if (name === 'open') { + if (this.hasAttribute('open')) { + this.show() + } + } + } +}) + +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') + } + } + + 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 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 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 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 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() + } + } + }) + 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, + }) + } +}) + +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 + this._value + this.scrollDistance + + 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 + 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 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.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.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 ['value', 'disabled'] + } + get value() { + return this.getAttribute('value') + } + set value(val) { + this.setAttribute('value', val) + } + + 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 = firstElement.textContent + this.previousOption = firstElement; + if (fire) { + this.fireEvent() + } + } + } + + 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.selectedOptionText.textContent = document.activeElement.textContent; + this.fireEvent() + if (this.previousOption) { + this.previousOption.classList.remove('check-selected') + } + document.activeElement.classList.add('check-selected') + this.previousOption = document.activeElement + } + } + 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') + } + } + } +}) + +// 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') + } +}) diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..0b56e6d --- /dev/null +++ b/css/main.css @@ -0,0 +1,1562 @@ +* { + padding: 0; + margin: 0; + box-sizing: border-box; + font-family: "Roboto", sans-serif; +} + +:root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, +body { + height: 100%; + scroll-behavior: smooth; +} + +body { + color: rgba(var(--text-color), 1); + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: #5D54A4; + --text-color: 17, 17, 17; + --background-color: 240, 240, 255; + --foreground-color: rgb(248, 248, 255); + --danger-color: red; + scrollbar-width: thin; +} + +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: #9D65C9; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --foreground-color: rgb(20, 20, 20); + --danger-color: rgb(255, 106, 106); +} +body[data-theme=dark] ::-webkit-calendar-picker-indicator { + filter: invert(1); +} + +p { + max-width: 70ch; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); +} +p:not(:last-of-type) { + margin-bottom: 1.5rem; +} + +img { + object-fit: cover; +} + +a:where([class]) { + color: inherit; + text-decoration: none; +} +a:where([class]):focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +a { + color: var(--accent-color); +} + +button, +.button { + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + cursor: pointer; +} + +button:disabled { + opacity: 0.5; +} + +a.button { + padding: 0.6rem 1.2rem; + border-radius: 0.3rem; + background-color: rgba(var(--text-color), 0.06); +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; +} +sm-button[variant=primary] .icon { + fill: rgba(var(--background-color), 1); +} +sm-button[disabled] .icon { + fill: rgba(var(--text-color), 0.6); +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.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; +} + +.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/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.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%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { + font-weight: 400; +} + +.weight-500 { + font-weight: 500; +} + +.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); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +#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; +} + +.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; +} + +#main_page { + height: 100%; + grid-template-rows: auto 1fr auto; + grid-template-areas: "main-header" "sub-pages" "main-nav"; +} + +#main_header { + grid-area: main-header; + display: flex; + gap: 1rem; + align-items: center; + position: sticky; + padding: 0.5rem 1rem; + background: var(--foreground-color); + z-index: 1; +} + +#main_nav { + grid-area: main-nav; + position: relative; + display: flex; + align-items: center; + background-color: var(--foreground-color); +} + +.nav-list__item { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + padding: 0.5rem 0; + -webkit-tap-highlight-color: transparent; + font-size: 0.8rem; + font-weight: 500; + color: rgba(var(--text-color), 0.8); +} +.nav-list__item--active { + color: var(--accent-color); +} +.nav-list__item--active .icon { + fill: var(--accent-color); +} +.nav-list__item--active .icon--outlined { + display: none; +} +.nav-list__item--active .icon--filled { + display: inline-block; +} +.nav-list__item:not(.nav-list__item--active) .icon--outlined { + display: inline-block; +} +.nav-list__item:not(.nav-list__item--active) .icon--filled { + display: none; +} +.nav-list__item .icon { + margin-bottom: 0.3rem; +} + +#sub_page_container { + grid-area: sub-pages; + height: 100%; + overflow-y: auto; +} + +.container-card { + position: relative; + background: var(--foreground-color); + border-radius: 0.5rem; +} + +.medium-top-bottom-margin { + margin: 0.5rem 0; +} + +#sign_in_page { + display: grid; + position: fixed; + z-index: 5; + top: 0; + bottom: 0; + left: 0; + right: 0; + place-content: center; + background-color: var(--foreground-color); + gap: 1rem; +} + +#sign_in_form { + width: 22rem; +} + +.task { + display: grid; + grid-template-columns: auto 1fr; + margin: 0 1rem; +} +.task .task__branch_container { + padding-bottom: 2rem; +} + +.task:last-of-type .left .line { + transform: scaleY(0); +} + +.task .left { + display: flex; + position: relative; + justify-content: center; + padding-top: 0.5rem; +} + +.task .left .circle { + display: inline-flex; + position: relative; + align-self: flex-start; + height: 1rem; + width: 1rem; + border-radius: 50%; + background: var(--foreground-color); + border: solid 2px rgba(var(--text-color), 0.4); + z-index: 1; +} + +.task .left .line { + position: absolute; + left: 50%; + height: 100%; + width: 2px; + transform: translateX(-50%) scaleY(1); + background-color: rgba(var(--text-color), 0.4); +} + +.task .right { + margin-left: 1rem; + display: flex; + flex-direction: column; + width: 100%; +} + +.task .right .apply-cont { + width: 100%; + display: flex; + flex-direction: row; +} + +.task .right .apply-cont h4 { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.task h4 { + margin-top: 0.4rem; + margin-bottom: 1rem; +} + +.timeline-task__description { + white-space: pre-line; +} + +.task .assigned-interns .assigned-intern { + padding: 0.4rem; +} + +.completed-task .left .circle { + border: solid 2px #00C853 !important; + background: #00C853 !important; +} + +.completed-task .left .line { + background-color: #00C853 !important; +} + +.page { + gap: 1rem; + display: grid; + position: relative; + padding: 1rem; + animation: fadein 0.3s; + grid-template-columns: minmax(0, 1fr); +} + +@keyframes fadein { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +.task-title { + font-weight: 500; +} + +.padding { + padding: 1rem; +} + +#dashboard_page { + padding-bottom: 5rem; + grid-template-columns: auto; +} + +.logo { + display: flex; + align-items: center; + font-size: 1.2rem; + width: 100%; +} + +.logo .cls-2, +.logo .cls-3 { + fill: rgba(var(--text-color), 1); + font-size: 146.9px; + font-family: ArialMT, Arial; +} + +.logo svg { + height: 2.5rem; +} + +.logo h4 { + margin: 0; +} + +.project-card { + padding: 1rem; + font-weight: 500; + line-height: 1.5; + text-transform: capitalize; + color: rgba(var(--text-color), 0.8); +} + +.intern-card { + user-select: none; + padding: 0.8rem 1rem; + gap: 0.8rem; + grid-template-columns: auto 1fr auto; +} + +.intern-card__initials { + display: flex; + height: 2.6rem; + width: 2.6rem; + justify-content: center; + align-items: center; + border-radius: 40%; + color: white; + font-weight: 500; + font-size: 1rem; + text-transform: uppercase; + background-color: var(--accent-color); +} + +.intern-card__score-wrapper { + font-weight: 500; + font-size: 1.2rem; +} + +.intern-card .icon { + fill: #FF5722 !important; + height: 1rem !important; + width: 1rem !important; + margin-left: 0.2rem; +} + +.request-card { + display: grid; + position: relative; + padding: 1rem; +} +.request-card sm-button { + --padding: 0.5rem 0.8rem; +} + +.request-card__description { + width: 100%; + font-size: 1rem; + margin-bottom: 1rem; +} + +.reject-app { + margin-left: auto; + margin-right: 0.5rem; +} + +#updates_page sm-select { + --max-height: 50vh; +} + +#updates { + transition: opacity 0.3s ease; +} + +#updates_page__project_selector strip-option { + font-size: 0.9rem; +} + +.intern-update { + display: grid; + gap: 0.5rem; + padding: 1rem; + border-radius: 0.5rem; + background-color: var(--foreground-color); +} + +.update__topic { + font-weight: 500; + font-size: 1rem; + margin-top: 0.5rem; + text-transform: capitalize; + max-width: 65ch; +} + +.update__sender { + color: var(--accent-color); + font-size: 0.9rem; + font-weight: 500; +} + +.update__time { + font-size: 0.85rem; + color: rgba(var(--text-color), 0.8); +} + +.update__message { + white-space: pre-line; +} + +.container-header { + display: flex; + align-items: center; + width: 100%; + padding: 1rem; +} + +.container-header h4 { + flex: 1; + font-weight: 500; +} + +#intern_info_popup .grid > * { + justify-self: center; +} +#intern_info_popup #update_intern_score { + width: 100%; + margin-top: 1rem; +} + +#intern_info__initials { + margin-bottom: 1rem; + position: relative; + height: 3rem; + width: 3rem; + font-size: 1.3rem; +} +#intern_info__initials::before { + content: ""; + position: absolute; + background-color: inherit; + border-radius: inherit; + height: calc(100% + 1.5rem); + width: calc(100% + 1.5rem); + opacity: 0.3; + z-index: -1; +} + +#intern_info__name { + font-size: 1.5rem; + margin-bottom: 0.5rem; +} + +.gold-fill { + fill: #FF5722; +} + +#intern_info__score { + font-size: 1.5rem; +} + +#project_info { + flex-direction: column; +} + +.branch-button { + margin-bottom: 0.5rem; + display: flex; + border-radius: 0; + padding: 0.5rem; + border-radius: 0.2rem; + text-transform: capitalize; + justify-self: start; + align-items: center; + user-select: none; + font-size: 0.85rem; + font-weight: 500; +} +.branch-button .icon { + height: 1.2rem; + width: 1.2rem; +} + +.active-branch { + opacity: 1; + color: white; + background: var(--accent-color); +} + +#task_list { + padding: 1rem 0 1.5rem 0; +} + +.task-list-item { + display: grid; + grid-template-columns: auto 1fr auto; + grid-template-areas: "status title options" "status interns interns" "status description description" "status . ."; + align-content: flex-start; + padding: 1rem; + gap: 0.5rem; + border-radius: 0.5rem; + background: rgba(var(--text-color), 0.02); +} +.task-list-item sm-checkbox { + grid-area: status; + align-self: flex-start; + padding: 0.2rem 0.5rem 0.5rem 0; +} +.task-list-item h4 { + font-weight: 500; + margin: 0; +} +.task-list-item .task-title { + grid-area: title; + line-height: 1.6; +} +.task-list-item .assigned-interns { + grid-area: interns; +} + +.task__branch_container:not(:empty) { + display: grid; + gap: 0.5rem; + padding: 0.5rem 0; +} +.task__branch_container .branch-button { + position: relative; + background-color: transparent; + padding: 0; + padding-left: 2rem; + margin: 0.5rem 0; +} +.task__branch_container .branch-button::before { + position: absolute; + content: ""; + top: -50%; + left: 0; + display: inline-flex; + width: 1rem; + height: 100%; + align-self: flex-start; + margin-right: 0.8rem; + border-left: solid; + border-bottom: solid; + border-width: 0.15rem; + border-color: rgba(var(--text-color), 0.6); + border-radius: 0 0 0 0.2rem; +} +.task__branch_container .branch-button + .branch-button::before { + top: calc(-50% - 1.5rem ); + height: calc(100% + 1.5rem); +} + +.task-option { + grid-area: options; + transition: opacity 0.3s ease; + padding: 0.5rem; +} +.task-option .icon { + height: 1.2rem; + width: 1.2rem; +} + +.task-description { + grid-area: description; + margin: 0; + overflow-wrap: break-word; + word-wrap: break-word; + white-space: pre-line; +} + +.assigned-interns { + display: flex; + flex-wrap: wrap; + margin-bottom: 1rem; +} + +.assigned-interns .assigned-intern { + user-select: none; + display: flex; + font-size: 0.8rem; + margin: 0.2rem 0.5rem 0.2rem 0; + padding: 0.2rem 0 0.2rem 0.4rem; + border-radius: 0.2rem; + border: 1px solid rgba(var(--text-color), 0.24); + align-items: center; + white-space: nowrap; + text-transform: capitalize; +} +.assigned-interns .assigned-intern button { + padding: 0.2rem; +} +.assigned-interns .assigned-intern button .icon { + height: 1rem; + width: 1rem; +} + +#task_context { + position: absolute; + top: 0; + right: 0; + margin: -1rem 1rem 0 1rem; + list-style: none; + padding: 0.5rem 0; + width: max-content; + border-radius: 0.3rem; + transition: 0.3s opacity ease; + background-color: var(--foreground-color); + box-shadow: 0 0.5rem 1rem -0.3rem rgba(0, 0, 0, 0.3); +} +#task_context li { + padding: 0.8rem 1.5rem; + display: flex; + align-items: center; + font-size: 0.9rem; +} +#task_context li .icon { + height: 1.2rem; + width: 1.2rem; + margin-right: 0.5rem; +} + +.temp-task .cancel-task-button { + margin-right: 0.5rem; +} + +#editing_panel__description { + margin-bottom: 2rem; +} + +#branch_container { + display: flex; + flex-flow: row wrap; + margin: 0.5rem 0 1rem 0; +} + +#intern_list_popup { + flex-direction: column; +} + +#intern_search_field { + margin-bottom: 1rem; +} + +#intern_list_container { + height: 100%; + overflow-y: auto; +} + +#best_interns_container, +#project_list_container { + margin-bottom: 1rem; +} + +#best_interns_container .container-header .icon, +#project_list_container .container-header .icon { + margin-right: 0.5rem; +} + +#edit_data_fig { + fill: rgba(var(--text-color), 0.6); + width: 60vw; + margin: 2rem 0; +} + +#loading_page { + display: grid; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 5; + text-align: center; + place-content: center; + justify-items: center; + background-color: var(--foreground-color); +} + +.loading-message { + font-size: 1.3rem; + margin: 1.5rem 0 0.5rem 0; +} + +#loading_page__footer { + position: absolute; + bottom: 0; + width: 100%; + padding: 1.5rem; +} +#loading_page__footer .icon { + height: 4rem; + width: 4rem; +} + +#project_watching_section { + position: relative; + overflow: hidden; +} + +#project_explorer { + padding: 0; +} + +#project_explorer__right { + gap: 1rem; + align-items: flex-start; + align-content: flex-start; + padding: 1rem; +} + +#explorer_branch_container { + margin-top: 1.5rem; +} + +#watch_project_button { + margin-left: 1rem; + text-transform: capitalize; +} + +#admin_page { + position: relative; + display: grid; + gap: 0; + padding: 0; + height: 100%; +} + +#project_editing_panel { + position: relative; + padding: 1rem 0; + height: 100%; + overflow-y: auto; +} + +#editing_panel__title { + margin-bottom: 1rem; +} + +.fab-actions { + display: grid; + gap: 1rem; + position: absolute; + bottom: 0; + right: 0; + margin: 1rem; + justify-items: end; + text-align: end; + z-index: 5; +} +.fab-actions[open] .fab-actions__item { + transform: translateY(0); + opacity: 1; +} +.fab-actions[open] .fab .icon:nth-of-type(1) { + transform: scale(0) rotate(180deg); +} +.fab-actions[open] .fab .icon:nth-of-type(2) { + transform: scale(1) rotate(0); +} +.fab-actions[open] ~ #fab_backdrop { + opacity: 1; + clip-path: circle(100%); +} + +.fab-actions__item { + display: flex; + align-items: center; + justify-self: end; + padding: 0.6rem 1rem; + border-radius: 2rem; + transform: translateY(1.5rem); + background-color: var(--foreground-color); + opacity: 0; + transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s; + box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.2); + user-select: none; +} +.fab-actions__item:hover, .fab-actions__item:active { + transform: scale(0.9); +} +.fab-actions__item:nth-of-type(1) { + transition-delay: 0.2s; +} +.fab-actions__item:nth-of-type(2) { + transition-delay: 0.1s; +} +.fab-actions__item .icon { + fill: var(--accent-color); + margin-left: 0.5rem; +} +.fab-actions__item-name { + font-size: 0.9rem; +} + +.fab { + position: relative; + display: flex; + justify-content: center; + align-items: center; + padding: 1rem; + height: 3.2rem; + width: 3.2rem; + border-radius: 50%; + background-color: var(--accent-color); + box-shadow: 0 0.5rem 0.8rem rgba(0, 0, 0, 0.3); + transition: transform 0.3s; + -webkit-tap-highlight-color: transparent; +} +.fab:active { + transform: scale(0.9); +} +.fab .icon { + position: absolute; + height: 100%; + fill: white; + transition: transform 0.3s; +} +.fab .icon:nth-of-type(1) { + transform: scale(1) rotate(0); +} +.fab .icon:nth-of-type(2) { + transform: scale(0) rotate(-180deg); +} + +#fab_backdrop { + position: fixed; + z-index: 3; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0; + clip-path: circle(0% at 100% 100%); + transition: clip-path 0.5s, opacity 0.5s; + background-color: rgba(0, 0, 0, 0.5); +} + +#update_of_project { + color: rgba(var(--text-color), 0.8); +} + +#update_of_task { + font-size: 1.3rem; + margin: 0.4rem 0 1.8rem 0; +} + +ul { + padding: 0; + list-style: none; +} + +#assigned_task_list { + display: grid; + gap: 1rem; + margin-top: 1rem; + align-content: flex-start; + grid-template-columns: minmax(0, 1fr); +} + +.task-card { + display: grid; + padding: 1rem; + border-radius: 0.5rem; + grid-template-columns: minmax(0, 1fr); + background-color: var(--foreground-color); +} + +.task__header { + display: grid; + gap: 0 0.5rem; + align-items: flex-start; + grid-template-columns: 1fr auto; + grid-template-areas: ". send-button" ". send-button"; +} + +.task__project-title { + font-size: 0.9rem; + font-weight: 500; + border-radius: 0.3rem; + padding: 0.3rem 0.5rem; + justify-self: flex-start; + margin-bottom: 0.5rem !important; + color: rgba(var(--text-color), 0.8); + background-color: rgba(var(--text-color), 0.06); +} + +.task__title { + font-size: 1.3rem; + margin-bottom: 1rem !important; +} + +.task__description { + word-wrap: break-word; + overflow-wrap: break-word; + white-space: pre-line; + color: rgba(var(--text-color), 0.8); +} + +.send-update-button { + grid-area: send-button; + --padding: 0.6rem 0.8rem; + color: var(--accent-color); +} +.send-update-button .icon { + height: 1.2rem; + width: 1.2rem; + fill: var(--accent-color); +} + +#admin_page__left { + height: 100%; + overflow-y: hidden; +} +#admin_page__left sm-tab-header { + --gap: 0; + --justify-content: stretch; + background-color: var(--foreground-color); + border-bottom: 1px solid rgba(var(--text-color), 0.2); +} +#admin_page__left sm-tab { + justify-content: center; +} +#admin_page__left sm-tab-panels, +#admin_page__left sm-tab-panels > * { + height: 100%; + flex-direction: column; +} +#admin_page__left sm-tab-panels { + overflow-y: hidden; +} +#admin_page__left sm-tab-panels > * { + display: flex; +} +#admin_page__left .list-container { + height: 100%; + overflow-y: auto; + padding-bottom: 2rem; +} +#admin_page__left .empty-state { + padding: 1rem; + text-align: center; +} + +#update_filters_wrapper { + gap: 1.5rem; +} + +input[type=date] { + display: flex; + width: 100%; + padding: 0.5rem; + border: rgba(var(--text-color), 0.2) solid thin; + border-radius: 0.3rem; + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: rgba(var(--text-color), 0.06); +} +input[type=date]:focus { + outline: none; + box-shadow: 0 0 0 0.1rem var(--accent-color); +} + +.search__icon { + height: 1.2rem; + width: 1.2rem; +} + +#user_role { + justify-self: start; + font-size: 0.7rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.4rem 0.8rem; + border-radius: 0.3rem; + border: solid var(--accent-color) thin; +} + +#project_watching_section { + display: grid; + gap: 1rem; +} + +#project_watchlist { + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); +} + +.watchlist_project_card { + color: inherit; + display: grid; + border-radius: 0.5rem; + grid-template-rows: auto 1fr; + gap: 1rem; + padding: 1rem; + background-color: rgba(var(--text-color), 0.04); +} +.watchlist_project_card .project__title { + font-size: 1.1rem; + line-height: 1.5; +} + +.progress-bar { + display: flex; + height: 0.5rem; + background-color: rgba(var(--text-color), 0.2); + border-radius: 1rem; + overflow: hidden; + align-self: flex-end; +} +.progress-bar .progress-value { + background-color: var(--accent-color); + transition: width 0.3s; +} + +#username { + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} + +#logout { + margin-top: 1.5rem; +} + +@media only screen and (max-width: 640px) { + .hide-on-mobile, +.hide-page-on-mobile { + display: none; + } + + #project_editing_panel { + padding: 1rem; + } + + .list-container { + padding-bottom: 5rem; + } +} +@media only screen and (min-width: 640px) { + .hide-on-desktop { + display: none !important; + } + + sm-popup { + --width: 26rem; + } + + .popup__header { + padding: 1.5rem 1.5rem 0 0.75rem; + } + + #main_nav { + padding: 0.5rem; + background-color: rgba(var(--background-color), 1); + flex-direction: column; + } + #main_nav theme-toggle { + margin: 1rem; + margin-top: auto; + } + + .nav-list__item { + flex-direction: row; + align-items: center; + border-radius: 0.5rem; + padding: 0.8rem; + margin-bottom: 0.25rem; + font-size: 1rem; + } + .nav-list__item--active { + background-color: rgba(var(--text-color), 0.06); + } + .nav-list__item .icon { + margin-bottom: 0; + } + .nav-list__item_title { + display: none; + } + + .project-card--active { + background-color: rgba(var(--text-color), 0.1); + } + + .page { + background-color: var(--foreground-color); + } + + #sign_in { + width: 24rem; + height: auto; + border-radius: 0.4rem; + } + + #dashboard_page { + grid-template-columns: 3fr 18rem; + } + + #dashboard_page #project_watching_section { + align-self: flex-start; + } + + #all_interns_page__header { + grid-template-columns: 1fr auto; + } + + #admin_page { + padding: 1rem 0; + gap: 1rem; + grid-template-columns: 18rem minmax(0, 1fr); + grid-template-rows: 1fr; + } + + #admin_page__left { + background-color: var(--foreground-color); + } + + #project_editing_panel { + padding-right: 1rem; + } + + #admin_page__left, +#project_editing_panel { + border-radius: 0.5rem; + } + + #edit_data_fig { + width: 16rem; + justify-self: center; + } + + #project_explorer { + display: grid; + height: 100%; + grid-template-columns: 16rem 3fr; + grid-template-areas: "left right"; + } + + #project_explorer__left { + grid-area: left; + height: 100%; + overflow-y: auto; + padding-bottom: 1.5rem; + border-right: 1px solid rgba(var(--text-color), 0.06); + background-color: rgba(var(--background-color), 1); + } + + #project_explorer__left h4 { + margin-top: 0; + margin-bottom: 0.5rem; + color: var(--accent-color); + font-size: 0.9rem; + } + + #project_explorer__right { + grid-area: right; + height: 100%; + overflow-y: auto; + } + + #main_page { + grid-template-columns: 4rem minmax(0, 1fr); + grid-template-areas: "main-header main-header" "main-nav sub-pages"; + } + + #post_update_popup { + --width: 28rem; + } + + #updates_page { + height: 100%; + gap: 1rem; + grid-template-areas: "updates update-filters"; + grid-template-columns: minmax(0, 1fr) 20rem; + } + + #update_filters_wrapper { + padding: 1rem; + border-radius: 0.5rem; + align-content: flex-start; + grid-area: update-filters; + background-color: var(--foreground-color); + } + + #updates_wrapper { + height: 100%; + overflow-y: auto; + grid-area: updates; + } + + #all_interns_list { + gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); + } + #all_interns_list .intern-card { + gap: 1.5rem 0.5rem; + padding: 1.5rem; + grid-template-columns: 1fr; + border-radius: 0.5rem; + background-color: var(--foreground-color); + } + #all_interns_list .intern-card__initials { + position: relative; + grid-column: 1/3; + z-index: 1; + } + #all_interns_list .intern-card__initials::after { + content: ""; + position: absolute; + background-color: inherit; + border-radius: inherit; + height: calc(100% + 1rem); + width: calc(100% + 1rem); + opacity: 0.3; + z-index: -1; + } + + #intern_list_popup { + --height: 80vh; + } + + #settings_page { + height: 100%; + align-items: flex-start; + padding: 2rem; + } + + .watchlist_project_card { + padding: 1.5rem; + } +} +@media only screen and (min-width: 1280px) { + #main_page { + grid-template-columns: 12rem minmax(0, 1fr); + grid-template-areas: "main-header main-header" "main-nav sub-pages"; + } + + #main_nav { + align-items: flex-start; + } + + .nav-list__item .icon { + margin-right: 0.5rem; + } + .nav-list__item_title { + display: inline-block; + } +} +@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:hover { + background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), var(--foreground-color); + } + + .send-update-button, +.task-option, +.apply-button { + opacity: 0; + transition: opacity 0.3s; + } + + .task-list-item:hover .task-option, +.task-option:focus-within, +.task:hover .apply-button, +.task-card:hover .send-update-button { + opacity: 1; + } +} \ No newline at end of file diff --git a/css/main.min.css b/css/main.min.css new file mode 100644 index 0000000..3a016e6 --- /dev/null +++ b/css/main.min.css @@ -0,0 +1 @@ +.hide,.ripple{pointer-events:none}.fab,.interact,.nav-list__item{-webkit-tap-highlight-color:transparent}#updates,.task-option{transition:opacity .3s ease}*{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#5D54A4;--text-color:17,17,17;--background-color:240,240,255;--foreground-color:rgb(248, 248, 255);--danger-color:red;scrollbar-width:thin}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#9D65C9;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--foreground-color:rgb(20, 20, 20);--danger-color:rgb(255, 106, 106)}body[data-theme=dark] ::-webkit-calendar-picker-indicator{filter:invert(1)}p{max-width:70ch;line-height:1.7;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1.5rem}img{object-fit:cover}a:where([class]){color:inherit;text-decoration:none}a:where([class]):focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}a{color:var(--accent-color)}.button,button{position:relative;display:inline-flex;border:none;background-color:transparent;overflow:hidden;color:inherit;cursor:pointer}.color-0-8,.nav-list__item{color:rgba(var(--text-color),.8)}button:disabled{opacity:.5}a.button{padding:.6rem 1.2rem;border-radius:.3rem;background-color:rgba(var(--text-color),.06)}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}sm-button[variant=primary] .icon{fill:rgba(var(--background-color),1)}#edit_data_fig,sm-button[disabled] .icon{fill:rgba(var(--text-color),.6)}.hide{opacity:0}.hide-completely{display:none!important}#main_header,#main_nav,.flex,.nav-list__item{display:flex}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable,.task-description,.task__description{word-wrap:break-word;overflow-wrap:break-word}.breakable{-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/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}.capitalize,.project-card{text-transform:capitalize}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.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}#loading_page,.text-center{text-align:center}.align-start{align-items:flex-start}.align-center,.popup__header{align-items:center}.justify-start{justify-content:start}.justify-center,.task .left{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%}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16)}.interact{position:relative;overflow:hidden;cursor:pointer}.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),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}.popup__header{display:grid;gap:.5rem;width:100%;padding:0 1.5rem 0 .5rem;grid-template-columns:auto 1fr auto}.popup__header__close{padding:.5rem;cursor:pointer}#main_page{height:100%;grid-template-rows:auto 1fr auto;grid-template-areas:"main-header" "sub-pages" "main-nav"}#main_header{grid-area:main-header;gap:1rem;align-items:center;position:sticky;padding:.5rem 1rem;background:var(--foreground-color);z-index:1}#main_nav{grid-area:main-nav;position:relative;align-items:center;background-color:var(--foreground-color)}.nav-list__item{flex-direction:column;align-items:center;width:100%;padding:.5rem 0;font-size:.8rem;font-weight:500}.nav-list__item--active{color:var(--accent-color)}.nav-list__item--active .icon{fill:var(--accent-color)}.nav-list__item--active .icon--outlined{display:none}.nav-list__item--active .icon--filled{display:inline-block}.nav-list__item:not(.nav-list__item--active) .icon--outlined{display:inline-block}.nav-list__item:not(.nav-list__item--active) .icon--filled{display:none}.nav-list__item .icon{margin-bottom:.3rem}#sub_page_container{grid-area:sub-pages;height:100%;overflow-y:auto}.container-card{position:relative;background:var(--foreground-color);border-radius:.5rem}#loading_page,#sign_in_page{position:fixed;place-content:center;z-index:5;top:0;bottom:0;left:0;right:0}.medium-top-bottom-margin{margin:.5rem 0}#sign_in_page{display:grid;background-color:var(--foreground-color);gap:1rem}#sign_in_form{width:22rem}.task{display:grid;grid-template-columns:auto 1fr;margin:0 1rem}#assigned_task_list,.page,.task-card{grid-template-columns:minmax(0,1fr)}.task .task__branch_container{padding-bottom:2rem}.task:last-of-type .left .line{transform:scaleY(0)}.task .left{display:flex;position:relative;padding-top:.5rem}.task .left .circle{display:inline-flex;position:relative;align-self:flex-start;height:1rem;width:1rem;border-radius:50%;background:var(--foreground-color);border:2px solid;z-index:1}.task .left .line{position:absolute;left:50%;height:100%;width:2px;transform:translateX(-50%) scaleY(1);background-color:rgba(var(--text-color),.4)}.task .right{margin-left:1rem;display:flex;flex-direction:column;width:100%}.task .right .apply-cont{width:100%;display:flex;flex-direction:row}.task .right .apply-cont h4{-webkit-box-flex:1;-ms-flex:1;flex:1}.task h4{margin-top:.4rem;margin-bottom:1rem}.timeline-task__description{white-space:pre-line}.task .assigned-interns .assigned-intern{padding:.4rem}.padding,.page{padding:1rem}.completed-task .left .circle{border:2px solid #00C853!important;background:#00C853!important}.completed-task .left .line{background-color:#00C853!important}.page{gap:1rem;display:grid;position:relative;animation:fadein .3s}@keyframes fadein{0%{opacity:0}100%{opacity:1}}.task-title{font-weight:500}#dashboard_page{padding-bottom:5rem;grid-template-columns:auto}.intern-card,.task-list-item{grid-template-columns:auto 1fr auto}.logo{display:flex;align-items:center;font-size:1.2rem;width:100%}.logo .cls-2,.logo .cls-3{fill:rgba(var(--text-color),1);font-size:146.9px;font-family:ArialMT,Arial}.logo svg{height:2.5rem}.logo h4{margin:0}.project-card{padding:1rem;font-weight:500;line-height:1.5;color:rgba(var(--text-color),.8)}.intern-card{user-select:none;padding:.8rem 1rem;gap:.8rem}.intern-card__initials{display:flex;height:2.6rem;width:2.6rem;justify-content:center;align-items:center;border-radius:40%;color:#fff;font-weight:500;font-size:1rem;text-transform:uppercase;background-color:var(--accent-color)}.intern-card__score-wrapper{font-weight:500;font-size:1.2rem}.intern-card .icon{fill:#FF5722!important;height:1rem!important;width:1rem!important;margin-left:.2rem}.request-card{display:grid;position:relative;padding:1rem}.request-card sm-button{--padding:0.5rem 0.8rem}.request-card__description{width:100%;font-size:1rem;margin-bottom:1rem}.reject-app{margin-left:auto;margin-right:.5rem}#updates_page sm-select{--max-height:50vh}#updates_page__project_selector strip-option{font-size:.9rem}.intern-update{display:grid;gap:.5rem;padding:1rem;border-radius:.5rem;background-color:var(--foreground-color)}.update__topic{font-weight:500;font-size:1rem;margin-top:.5rem;text-transform:capitalize;max-width:65ch}.update__sender{color:var(--accent-color);font-size:.9rem;font-weight:500}#update_of_project,.task__description,.task__project-title,.update__time{color:rgba(var(--text-color),.8)}.update__time{font-size:.85rem}.update__message{white-space:pre-line}.container-header{display:flex;align-items:center;width:100%;padding:1rem}.container-header h4{flex:1;font-weight:500}#intern_info_popup .grid>*{justify-self:center}#intern_info_popup #update_intern_score{width:100%;margin-top:1rem}#intern_info__initials{margin-bottom:1rem;position:relative;height:3rem;width:3rem;font-size:1.3rem}#intern_info__initials::before{content:"";position:absolute;background-color:inherit;border-radius:inherit;height:calc(100% + 1.5rem);width:calc(100% + 1.5rem);opacity:.3;z-index:-1}#intern_info__name{font-size:1.5rem;margin-bottom:.5rem}.gold-fill{fill:#FF5722}#intern_info__score{font-size:1.5rem}#project_info{flex-direction:column}#user_role,.branch-button{justify-self:start;font-weight:500}.branch-button{margin-bottom:.5rem;display:flex;padding:.5rem;border-radius:.2rem;text-transform:capitalize;align-items:center;user-select:none;font-size:.85rem}.branch-button .icon{height:1.2rem;width:1.2rem}.active-branch{opacity:1;color:#fff;background:var(--accent-color)}#task_list{padding:1rem 0 1.5rem}.task-list-item{display:grid;grid-template-areas:"status title options" "status interns interns" "status description description" "status . .";align-content:flex-start;padding:1rem;gap:.5rem;border-radius:.5rem;background:rgba(var(--text-color),.02)}.task-list-item sm-checkbox{grid-area:status;align-self:flex-start;padding:.2rem .5rem .5rem 0}.task-list-item h4{font-weight:500;margin:0}.task-list-item .task-title{grid-area:title;line-height:1.6}.task-list-item .assigned-interns{grid-area:interns}.task__branch_container:not(:empty){display:grid;gap:.5rem;padding:.5rem 0}.task__branch_container .branch-button{position:relative;background-color:transparent;padding:0;padding-left:2rem;margin:.5rem 0}#loading_page,#task_context,.fab-actions__item{background-color:var(--foreground-color)}.task__branch_container .branch-button::before{position:absolute;content:"";top:-50%;left:0;display:inline-flex;width:1rem;height:100%;align-self:flex-start;margin-right:.8rem;border-left:solid;border-bottom:solid;border-width:.15rem;border-color:rgba(var(--text-color),.6);border-radius:0 0 0 .2rem}.task__branch_container .branch-button+.branch-button::before{top:calc(-50% - 1.5rem);height:calc(100% + 1.5rem)}.task-option{grid-area:options;padding:.5rem}.task-option .icon{height:1.2rem;width:1.2rem}.task-description{grid-area:description;margin:0;white-space:pre-line}.assigned-interns{display:flex;flex-wrap:wrap;margin-bottom:1rem}.assigned-interns .assigned-intern{user-select:none;display:flex;font-size:.8rem;margin:.2rem .5rem .2rem 0;padding:.2rem 0 .2rem .4rem;border-radius:.2rem;border:1px solid;align-items:center;white-space:nowrap;text-transform:capitalize}.assigned-interns .assigned-intern button{padding:.2rem}.assigned-interns .assigned-intern button .icon{height:1rem;width:1rem}#task_context{position:absolute;top:0;right:0;margin:-1rem 1rem 0;list-style:none;padding:.5rem 0;width:max-content;border-radius:.3rem;transition:.3s opacity ease;box-shadow:0 .5rem 1rem -.3rem rgba(0,0,0,.3)}#task_context li{padding:.8rem 1.5rem;display:flex;align-items:center;font-size:.9rem}#task_context li .icon{height:1.2rem;width:1.2rem;margin-right:.5rem}.temp-task .cancel-task-button{margin-right:.5rem}#editing_panel__description{margin-bottom:2rem}#branch_container{display:flex;flex-flow:row wrap;margin:.5rem 0 1rem}#intern_list_popup{flex-direction:column}#best_interns_container,#intern_search_field,#project_list_container{margin-bottom:1rem}#intern_list_container{height:100%;overflow-y:auto}#best_interns_container .container-header .icon,#project_list_container .container-header .icon{margin-right:.5rem}#edit_data_fig{width:60vw;margin:2rem 0}#loading_page{display:grid;justify-items:center}.loading-message{font-size:1.3rem;margin:1.5rem 0 .5rem}#loading_page__footer{position:absolute;bottom:0;width:100%;padding:1.5rem}#loading_page__footer .icon{height:4rem;width:4rem}#project_watching_section{position:relative;overflow:hidden}#project_explorer{padding:0}#project_explorer__right{gap:1rem;align-items:flex-start;align-content:flex-start;padding:1rem}#explorer_branch_container{margin-top:1.5rem}#watch_project_button{margin-left:1rem;text-transform:capitalize}#admin_page{position:relative;display:grid;gap:0;padding:0;height:100%}#project_editing_panel{position:relative;padding:1rem 0;height:100%;overflow-y:auto}#editing_panel__title{margin-bottom:1rem}.fab-actions{display:grid;gap:1rem;position:absolute;bottom:0;right:0;margin:1rem;justify-items:end;text-align:end;z-index:5}#logout,#username{margin-top:1.5rem}.fab-actions[open] .fab-actions__item{transform:translateY(0);opacity:1}.fab-actions[open] .fab .icon:nth-of-type(1){transform:scale(0) rotate(180deg)}.fab-actions[open] .fab .icon:nth-of-type(2){transform:scale(1) rotate(0)}.fab-actions[open]~#fab_backdrop{opacity:1;clip-path:circle(100%)}.fab-actions__item{display:flex;align-items:center;justify-self:end;padding:.6rem 1rem;border-radius:2rem;transform:translateY(1.5rem);opacity:0;transition:transform .3s cubic-bezier(.175,.885,.32,1.275),opacity .3s;box-shadow:0 .2rem .5rem rgba(0,0,0,.2);user-select:none}.fab-actions__item:active,.fab-actions__item:hover,.fab:active{transform:scale(.9)}.fab-actions__item:nth-of-type(1){transition-delay:.2s}.fab-actions__item:nth-of-type(2){transition-delay:.1s}.fab,.fab .icon{transition:transform .3s}.fab-actions__item .icon{fill:var(--accent-color);margin-left:.5rem}.fab-actions__item-name{font-size:.9rem}.fab{position:relative;display:flex;justify-content:center;align-items:center;padding:1rem;height:3.2rem;width:3.2rem;border-radius:50%;background-color:var(--accent-color);box-shadow:0 .5rem .8rem rgba(0,0,0,.3)}.fab .icon{position:absolute;height:100%;fill:#fff}.fab .icon:nth-of-type(1){transform:scale(1) rotate(0)}.fab .icon:nth-of-type(2){transform:scale(0) rotate(-180deg)}#fab_backdrop{position:fixed;z-index:3;top:0;bottom:0;left:0;right:0;opacity:0;clip-path:circle(0 at 100% 100%);transition:clip-path .5s,opacity .5s;background-color:rgba(0,0,0,.5)}#update_of_task{font-size:1.3rem;margin:.4rem 0 1.8rem}ul{padding:0;list-style:none}#assigned_task_list{display:grid;gap:1rem;margin-top:1rem;align-content:flex-start}.task-card{display:grid;padding:1rem;border-radius:.5rem;background-color:var(--foreground-color)}.task__project-title,input[type=date]{background-color:rgba(var(--text-color),.06)}.task__header{display:grid;gap:0 .5rem;align-items:flex-start;grid-template-columns:1fr auto;grid-template-areas:". send-button" ". send-button"}.task__project-title{font-size:.9rem;font-weight:500;border-radius:.3rem;padding:.3rem .5rem;justify-self:flex-start;margin-bottom:.5rem!important}.task__title{font-size:1.3rem;margin-bottom:1rem!important}.task__description{white-space:pre-line}.send-update-button{grid-area:send-button;--padding:0.6rem 0.8rem;color:var(--accent-color)}.send-update-button .icon{height:1.2rem;width:1.2rem;fill:var(--accent-color)}#admin_page__left{height:100%;overflow-y:hidden}#admin_page__left sm-tab-header{--gap:0;--justify-content:stretch;background-color:var(--foreground-color);border-bottom:1px solid rgba(var(--text-color),.2)}#admin_page__left sm-tab{justify-content:center}#admin_page__left sm-tab-panels,#admin_page__left sm-tab-panels>*{height:100%;flex-direction:column}#admin_page__left sm-tab-panels{overflow-y:hidden}#admin_page__left sm-tab-panels>*{display:flex}#admin_page__left .list-container{height:100%;overflow-y:auto;padding-bottom:2rem}#admin_page__left .empty-state{padding:1rem;text-align:center}#update_filters_wrapper{gap:1.5rem}input[type=date]{display:flex;width:100%;padding:.5rem;border:rgba(var(--text-color),.2) solid thin;border-radius:.3rem;font-family:inherit;font-size:inherit;color:inherit}#project_watching_section,#project_watchlist,.watchlist_project_card{display:grid;gap:1rem}input[type=date]:focus{outline:0;box-shadow:0 0 0 .1rem var(--accent-color)}.search__icon{height:1.2rem;width:1.2rem}#user_role{font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;padding:.4rem .8rem;border-radius:.3rem;border:var(--accent-color) solid thin}#project_watchlist{grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}.watchlist_project_card{color:inherit;border-radius:.5rem;grid-template-rows:auto 1fr;padding:1rem;background-color:rgba(var(--text-color),.04)}.watchlist_project_card .project__title{font-size:1.1rem;line-height:1.5}.progress-bar{display:flex;height:.5rem;background-color:rgba(var(--text-color),.2);border-radius:1rem;overflow:hidden;align-self:flex-end}.progress-bar .progress-value{background-color:var(--accent-color);transition:width .3s}#username{margin-bottom:.5rem}@media only screen and (max-width:640px){.hide-on-mobile,.hide-page-on-mobile{display:none}#project_editing_panel{padding:1rem}.list-container{padding-bottom:5rem}}@media only screen and (min-width:640px){#admin_page__left,#project_editing_panel,.nav-list__item{border-radius:.5rem}.hide-on-desktop{display:none!important}sm-popup{--width:26rem}.popup__header{padding:1.5rem 1.5rem 0 .75rem}#main_nav{padding:.5rem;background-color:rgba(var(--background-color),1);flex-direction:column}#main_nav theme-toggle{margin:1rem;margin-top:auto}.nav-list__item{flex-direction:row;align-items:center;padding:.8rem;margin-bottom:.25rem;font-size:1rem}.nav-list__item--active{background-color:rgba(var(--text-color),.06)}.nav-list__item .icon{margin-bottom:0}.nav-list__item_title{display:none}.project-card--active{background-color:rgba(var(--text-color),.1)}#admin_page__left,.page{background-color:var(--foreground-color)}#sign_in{width:24rem;height:auto;border-radius:.4rem}#dashboard_page{grid-template-columns:3fr 18rem}#dashboard_page #project_watching_section{align-self:flex-start}#all_interns_page__header{grid-template-columns:1fr auto}#admin_page{padding:1rem 0;gap:1rem;grid-template-columns:18rem minmax(0,1fr);grid-template-rows:1fr}#project_editing_panel{padding-right:1rem}#edit_data_fig{width:16rem;justify-self:center}#project_explorer{display:grid;height:100%;grid-template-columns:16rem 3fr;grid-template-areas:"left right"}#project_explorer__left{grid-area:left;height:100%;overflow-y:auto;padding-bottom:1.5rem;border-right:1px solid rgba(var(--text-color),.06);background-color:rgba(var(--background-color),1)}#all_interns_list .intern-card,#update_filters_wrapper{border-radius:.5rem;background-color:var(--foreground-color)}#project_explorer__left h4{margin-top:0;margin-bottom:.5rem;color:var(--accent-color);font-size:.9rem}#project_explorer__right{grid-area:right;height:100%;overflow-y:auto}#main_page{grid-template-columns:4rem minmax(0,1fr);grid-template-areas:"main-header main-header" "main-nav sub-pages"}#post_update_popup{--width:28rem}#updates_page{height:100%;gap:1rem;grid-template-areas:"updates update-filters";grid-template-columns:minmax(0,1fr) 20rem}#update_filters_wrapper{padding:1rem;align-content:flex-start;grid-area:update-filters}#updates_wrapper{height:100%;overflow-y:auto;grid-area:updates}#all_interns_list{gap:1rem;grid-template-columns:repeat(auto-fill,minmax(14rem,1fr))}#all_interns_list .intern-card{gap:1.5rem .5rem;padding:1.5rem;grid-template-columns:1fr}#all_interns_list .intern-card__initials{position:relative;grid-column:1/3;z-index:1}#all_interns_list .intern-card__initials::after{content:"";position:absolute;background-color:inherit;border-radius:inherit;height:calc(100% + 1rem);width:calc(100% + 1rem);opacity:.3;z-index:-1}#intern_list_popup{--height:80vh}#settings_page{height:100%;align-items:flex-start;padding:2rem}.watchlist_project_card{padding:1.5rem}}@media only screen and (min-width:1280px){#main_page{grid-template-columns:12rem minmax(0,1fr);grid-template-areas:"main-header main-header" "main-nav sub-pages"}#main_nav{align-items:flex-start}.nav-list__item .icon{margin-right:.5rem}.nav-list__item_title{display:inline-block}}@media (any-hover:hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.interact:hover{background:linear-gradient(rgba(var(--text-color),.06),rgba(var(--text-color),.06)),var(--foreground-color)}.apply-button,.send-update-button,.task-option{opacity:0;transition:opacity .3s}.task-card:hover .send-update-button,.task-list-item:hover .task-option,.task-option:focus-within,.task:hover .apply-button{opacity:1}} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss new file mode 100644 index 0000000..ddd2ea4 --- /dev/null +++ b/css/main.scss @@ -0,0 +1,1582 @@ +* { + padding: 0; + margin: 0; + box-sizing: border-box; + font-family: 'Roboto', sans-serif; +} + +:root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, +body { + height: 100%; + scroll-behavior: smooth; +} + +body { + + &, + * { + --accent-color: #5D54A4; + --text-color: 17, 17, 17; + --background-color: 240, 240, 255; + --foreground-color: rgb(248, 248, 255); + --danger-color: red; + scrollbar-width: thin; + } + + color: rgba(var(--text-color), 1); + background: rgba(var(--background-color), 1); +} + +body[data-theme='dark'] { + + &, + * { + --accent-color: #9D65C9; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --foreground-color: rgb(20, 20, 20); + --danger-color: rgb(255, 106, 106); + } + ::-webkit-calendar-picker-indicator { + filter: invert(1); + } +} + +p { + max-width: 70ch; + line-height: 1.7; + color: rgba(var(--text-color), 0.8); + + &:not(:last-of-type) { + margin-bottom: 1.5rem; + } +} + +img { + object-fit: cover; +} + +a:where([class]) { + color: inherit; + text-decoration: none; + + &:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} +a{ + color: var(--accent-color); +} + +button, +.button { + position: relative; + display: inline-flex; + border: none; + background-color: transparent; + overflow: hidden; + color: inherit; + cursor: pointer; +} +button:disabled{ + opacity: 0.5; +} + +a.button{ + padding: 0.6rem 1.2rem; + border-radius: 0.3rem; + background-color: rgba(var(--text-color), 0.06); +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; + + &[variant="primary"] { + .icon { + fill: rgba(var(--background-color), 1); + } + } + + &[disabled] { + .icon { + fill: rgba(var(--text-color), 0.6); + } + } +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.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; +} + +.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/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { + text-transform: capitalize; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.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%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { + font-weight: 400; +} + +.weight-500 { + font-weight: 500; +} + +.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); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; + + &--left { + margin-right: 0.5rem; + } + + &--right { + margin-left: 0.5rem; + } +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; + + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + + sm-button { + margin: 0; + } + + .flex { + padding: 0; + margin-top: 1rem; + + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; + } + } +} + +.popup__header { + display: grid; + gap: 0.5rem; + width: 100%; + padding: 0 1.5rem 0 0.5rem; + align-items: center; + grid-template-columns: auto 1fr auto; +} + +.popup__header__close { + padding: 0.5rem; + cursor: pointer; +} + +#main_page { + height: 100%; + grid-template-rows: auto 1fr auto; + grid-template-areas: 'main-header''sub-pages''main-nav'; +} + +#main_header { + grid-area: main-header; + display: flex; + gap: 1rem; + align-items: center; + position: sticky; + padding: 0.5rem 1rem; + background: var(--foreground-color); + z-index: 1; +} + +#main_nav { + grid-area: main-nav; + position: relative; + display: flex; + align-items: center; + background-color: var(--foreground-color); +} + +.nav-list__item { + display: flex; + flex-direction: column; + align-items: center; + + width: 100%; + padding: 0.5rem 0; + -webkit-tap-highlight-color: transparent; + + font-size: 0.8rem; + font-weight: 500; + color: rgba(var(--text-color), 0.8); + + &--active { + color: var(--accent-color); + + .icon { + fill: var(--accent-color); + } + .icon--outlined{ + display: none; + } + .icon--filled{ + display: inline-block; + } + } + &:not(.nav-list__item--active) { + .icon--outlined{ + display: inline-block; + } + .icon--filled{ + display: none; + } + } + + .icon { + margin-bottom: 0.3rem; + } +} + +#sub_page_container { + grid-area: sub-pages; + height: 100%; + overflow-y: auto; +} + +.container-card { + position: relative; + background: var(--foreground-color); + border-radius: 0.5rem; +} + +.medium-top-bottom-margin { + margin: 0.5rem 0; +} + +#sign_in_page { + display: grid; + position: fixed; + z-index: 5; + top: 0; + bottom: 0; + left: 0; + right: 0; + place-content: center; + background-color: var(--foreground-color); + gap: 1rem; +} + +#sign_in_form { + width: 22rem; +} + + +.task { + display: grid; + grid-template-columns: auto 1fr; + margin: 0 1rem; + .task__branch_container{ + padding-bottom: 2rem; + } +} + +.task:last-of-type .left .line { + transform: scaleY(0); +} + +.task .left { + display: flex; + position: relative; + justify-content: center; + padding-top: 0.5rem; +} + +.task .left .circle { + display: inline-flex; + position: relative; + align-self: flex-start; + height: 1rem; + width: 1rem; + border-radius: 50%; + background: var(--foreground-color); + border: solid 2px rgba(var(--text-color), 0.4); + z-index: 1; +} + +.task .left .line { + position: absolute; + left: 50%; + height: 100%; + width: 2px; + transform: translateX(-50%) scaleY(1); + background-color: rgba(var(--text-color), 0.4); +} + +.task .right { + margin-left: 1rem; + display: flex; + flex-direction: column; + width: 100%; +} + +.task .right .apply-cont { + width: 100%; + display: flex; + flex-direction: row; +} + +.task .right .apply-cont h4 { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.task h4 { + margin-top: 0.4rem; + margin-bottom: 1rem; +} + +.timeline-task__description{ + white-space: pre-line; +} + + +.task .assigned-interns .assigned-intern { + padding: 0.4rem; +} + +.completed-task .left .circle { + border: solid 2px #00C853 !important; + background: #00C853 !important; +} + +.completed-task .left .line { + background-color: #00C853 !important; +} + +.page { + gap: 1rem; + display: grid; + position: relative; + padding: 1rem; + animation: fadein 0.3s; + grid-template-columns: minmax(0, 1fr); +} +@keyframes fadein { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +.task-title { + font-weight: 500; +} + +.padding { + padding: 1rem; +} + +#dashboard_page { + padding-bottom: 5rem; + grid-template-columns: auto; +} +.logo { + display: flex; + align-items: center; + font-size: 1.2rem; + width: 100%; +} + +.logo .cls-2, +.logo .cls-3 { + fill: rgba(var(--text-color), 1); + font-size: 146.9px; + font-family: ArialMT, Arial; +} + +.logo svg { + height: 2.5rem; +} + +.logo h4 { + margin: 0; +} + +.project-card { + padding: 1rem; + font-weight: 500; + line-height: 1.5; + text-transform: capitalize; + color: rgba(var(--text-color), 0.8); +} + +.intern-card { + user-select: none; + padding: 0.8rem 1rem; + gap: 0.8rem; + grid-template-columns: auto 1fr auto; +} + +.intern-card__initials{ + display: flex; + height: 2.6rem; + width: 2.6rem; + justify-content: center; + align-items: center; + border-radius: 40%; + color: white; + font-weight: 500; + font-size: 1rem; + text-transform: uppercase; + background-color: var(--accent-color); +} + +.intern-card__score-wrapper { + font-weight: 500; + font-size: 1.2rem; +} + +.intern-card .icon { + fill: #FF5722 !important; + height: 1rem !important; + width: 1rem !important; + margin-left: 0.2rem; +} + +.request-card { + display: grid; + position: relative; + padding: 1rem; + sm-button{ + --padding: 0.5rem 0.8rem; + } +} + +.request-card__description{ + width: 100%; + font-size: 1rem; + margin-bottom: 1rem; +} +.reject-app{ + margin-left: auto; + margin-right: 0.5rem; +} + +#updates_page{ + sm-select{ + --max-height: 50vh; + } +} +#updates { + transition: opacity 0.3s ease; +} +#updates_page__project_selector{ + strip-option{ + font-size: 0.9rem; + } +} +#all_updates_list{ +} +.intern-update { + display: grid; + gap: 0.5rem; + padding: 1rem; + border-radius: 0.5rem; + background-color: var(--foreground-color); +} + +.update__topic { + font-weight: 500; + font-size: 1rem; + margin-top: 0.5rem; + text-transform: capitalize; + max-width: 65ch; +} + +.update__sender { + color: var(--accent-color); + font-size: 0.9rem; + font-weight: 500; +} + +.update__time { + font-size: 0.85rem; + color: rgba(var(--text-color), 0.8); +} + +.update__message { + white-space: pre-line; +} + +.container-header { + display: flex; + align-items: center; + width: 100%; + padding: 1rem; +} + +.container-header h4 { + flex: 1; + font-weight: 500; +} + +#intern_info_popup { + .grid{ + & > *{ + justify-self: center; + } + } + #update_intern_score{ + width: 100%; + margin-top: 1rem; + } +} +#intern_info__initials{ + margin-bottom: 1rem; + position: relative; + height: 3rem; + width: 3rem; + font-size: 1.3rem; + &::before{ + content: ''; + position: absolute; + background-color: inherit; + border-radius: inherit; + height: calc(100% + 1.5rem); + width: calc(100% + 1.5rem); + opacity: 0.3; + z-index: -1; + } +} +#intern_info__name{ + font-size: 1.5rem; + margin-bottom: 0.5rem; +} +.gold-fill { + fill: #FF5722; +} +#intern_info__score{ + font-size: 1.5rem; +} + +#project_info { + flex-direction: column; +} + +.branch-button { + margin-bottom: 0.5rem; + display: flex; + border-radius: 0; + padding: 0.5rem; + border-radius: 0.2rem; + text-transform: capitalize; + justify-self: start; + align-items: center; + user-select: none; + font-size: 0.85rem; + font-weight: 500; + .icon{ + height: 1.2rem; + width: 1.2rem; + } +} + +.active-branch { + opacity: 1; + color: white; + background: var(--accent-color); +} + +#task_list{ + padding: 1rem 0 1.5rem 0; +} +.task-list-item { + display: grid; + grid-template-columns: auto 1fr auto; + grid-template-areas: 'status title options' + 'status interns interns' + 'status description description' + 'status . .'; + align-content: flex-start; + padding: 1rem; + gap: 0.5rem; + border-radius: 0.5rem; + background: rgba(var(--text-color), 0.02); + sm-checkbox { + grid-area: status; + align-self: flex-start; + padding: 0.2rem 0.5rem 0.5rem 0; + } + h4 { + font-weight: 500; + margin: 0; + } + + .task-title { + grid-area: title; + line-height: 1.6; + } + .assigned-interns { + grid-area: interns; + } +} +.task__branch_container{ + &:not(:empty){ + display: grid; + gap: 0.5rem; + padding: 0.5rem 0; + } + .branch-button{ + position: relative; + background-color: transparent; + padding: 0; + padding-left: 2rem; + margin: 0.5rem 0; + &::before{ + position: absolute; + content: ''; + top: -50%; + left: 0; + display: inline-flex; + width: 1rem; + height: 100%; + align-self: flex-start; + margin-right: 0.8rem; + border-left: solid; + border-bottom: solid; + border-width: 0.15rem; + border-color: rgba(var(--text-color), 0.6); + border-radius: 0 0 0 0.2rem; + } + } + .branch-button + .branch-button{ + &::before{ + top: calc(-50% - 1.5rem ); + height: calc(100% + 1.5rem); + } + } +} + +.task-option { + grid-area: options; + transition: opacity 0.3s ease; + padding: 0.5rem; + .icon{ + height: 1.2rem; + width: 1.2rem; + } +} + +.task-description{ + grid-area: description; + margin: 0; + overflow-wrap: break-word; + word-wrap: break-word; + white-space: pre-line; +} + +.assigned-interns { + display: flex; + flex-wrap: wrap; + margin-bottom: 1rem; +} + +.assigned-interns .assigned-intern { + user-select: none; + display: flex; + font-size: 0.8rem; + margin: 0.2rem 0.5rem 0.2rem 0; + padding: 0.2rem 0 0.2rem 0.4rem; + border-radius: 0.2rem; + border: 1px solid rgba(var(--text-color), 0.24); + align-items: center; + white-space: nowrap; + text-transform: capitalize; + button { + padding: 0.2rem; + .icon { + height: 1rem; + width: 1rem; + } + } +} + +#task_context { + position: absolute; + top: 0; + right: 0; + margin: -1rem 1rem 0 1rem; + list-style: none; + padding: 0.5rem 0; + width: max-content; + border-radius: 0.3rem; + transition: 0.3s opacity ease; + background-color: var(--foreground-color); + box-shadow: 0 0.5rem 1rem -0.3rem rgba(0, 0, 0, 0.3); + + li { + padding: 0.8rem 1.5rem; + display: flex; + align-items: center; + font-size: 0.9rem; + .icon { + height: 1.2rem; + width: 1.2rem; + margin-right: 0.5rem; + } + } +} + +.temp-task { + .cancel-task-button{ + margin-right: 0.5rem; + } +} +#editing_panel__description{ + margin-bottom: 2rem; +} +#branch_container { + display: flex; + flex-flow: row wrap; + margin: 0.5rem 0 1rem 0; +} + +#intern_list_popup { + flex-direction: column; +} +#intern_search_field{ + margin-bottom: 1rem; +} +#intern_list_container { + height: 100%; + overflow-y: auto; +} + +#best_interns_container, +#project_list_container { + margin-bottom: 1rem; +} + +#best_interns_container .container-header .icon, +#project_list_container .container-header .icon { + margin-right: 0.5rem; +} + +#edit_data_fig { + fill: rgba(var(--text-color), 0.6); + width: 60vw; + margin: 2rem 0; +} +#loading_page { + display: grid; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 5; + text-align: center; + place-content: center; + justify-items: center; + background-color: var(--foreground-color); +} + +.loading-message { + font-size: 1.3rem; + margin: 1.5rem 0 0.5rem 0; +} + +#loading_page__footer { + position: absolute; + bottom: 0; + width: 100%; + padding: 1.5rem; + + .icon { + height: 4rem; + width: 4rem; + } +} + +#project_watching_section { + position: relative; + overflow: hidden; +} +#project_explorer { + padding: 0; +} +#project_explorer__right { + gap: 1rem; + align-items: flex-start; + align-content: flex-start; + padding: 1rem; +} +#explorer_branch_container{ + margin-top: 1.5rem; +} +#watch_project_button{ + margin-left: 1rem; + text-transform: capitalize; +} + + +#admin_page { + position: relative; + display: grid; + gap: 0; + padding: 0; + height: 100%; +} + +#project_editing_panel { + position: relative; + padding: 1rem 0; + height: 100%; + overflow-y: auto; +} +#editing_panel__title{ + margin-bottom: 1rem; +} + +.fab-actions{ + display: grid; + gap: 1rem; + position: absolute; + bottom: 0; + right: 0; + margin: 1rem; + justify-items: end; + text-align: end; + z-index: 5; + &[open]{ + .fab-actions__item{ + transform: translateY(0); + opacity: 1; + } + .fab{ + .icon{ + &:nth-of-type(1){ + transform: scale(0) rotate(180deg); + } + &:nth-of-type(2){ + transform: scale(1) rotate(0); + } + } + } + & ~ #fab_backdrop{ + opacity: 1; + clip-path: circle(100%); + } + } +} +.fab-actions__item{ + display: flex; + align-items: center; + justify-self: end; + padding: 0.6rem 1rem; + border-radius: 2rem; + transform: translateY(1.5rem); + background-color: var(--foreground-color); + opacity: 0; + transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s; + box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.2); + user-select: none; + &:hover, + &:active{ + transform: scale(0.9); + } + &:nth-of-type(1){ + transition-delay: 0.2s; + } + &:nth-of-type(2){ + transition-delay: 0.1s; + } + .icon{ + fill: var(--accent-color); + margin-left: 0.5rem; + } + &-name{ + font-size: 0.9rem; + } +} +.fab{ + position: relative; + display: flex; + justify-content: center; + align-items: center; + padding: 1rem; + height: 3.2rem; + width: 3.2rem; + border-radius: 50%; + background-color: var(--accent-color); + box-shadow: 0 0.5rem 0.8rem rgba(0, 0, 0, 0.3); + transition: transform 0.3s; + -webkit-tap-highlight-color: transparent; + &:active{ + transform: scale(0.9); + } + .icon{ + position: absolute; + height: 100%; + fill: white; + transition: transform 0.3s; + &:nth-of-type(1){ + transform: scale(1) rotate(0); + } + &:nth-of-type(2){ + transform: scale(0) rotate(-180deg); + } + } +} +#fab_backdrop{ + position: fixed; + z-index: 3; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0; + clip-path: circle(0% at 100% 100%); + transition: clip-path 0.5s, opacity 0.5s; + background-color: rgba(0, 0, 0, 0.5); +} + +#update_of_project { + color: rgba(var(--text-color), 0.8); +} + +#update_of_task { + font-size: 1.3rem; + margin: 0.4rem 0 1.8rem 0; +} + +ul { + padding: 0; + list-style: none; +} +#intern_view{ +} + +#assigned_task_list { + display: grid; + gap: 1rem; + margin-top: 1rem; + align-content: flex-start; + grid-template-columns: minmax(0, 1fr); +} + +.task-card { + display: grid; + padding: 1rem; + border-radius: 0.5rem; + grid-template-columns: minmax(0, 1fr); + background-color: var(--foreground-color); +} + +.task__header { + display: grid; + gap: 0 0.5rem; + align-items: flex-start; + grid-template-columns: 1fr auto; + grid-template-areas: '. send-button''. send-button'; +} + +.task__project-title { + font-size: 0.9rem; + font-weight: 500; + border-radius: 0.3rem; + padding: 0.3rem 0.5rem; + justify-self: flex-start; + margin-bottom: 0.5rem !important; + color: rgba(var(--text-color), 0.8); + background-color: rgba(var(--text-color), 0.06); +} + +.task__title { + font-size: 1.3rem; + margin-bottom: 1rem !important; +} + +.task__description { + word-wrap: break-word; + overflow-wrap: break-word; + white-space: pre-line; + color: rgba(var(--text-color), 0.8); +} + +.send-update-button { + grid-area: send-button; + --padding: 0.6rem 0.8rem; + color: var(--accent-color); + + .icon { + height: 1.2rem; + width: 1.2rem; + fill: var(--accent-color); + } +} + +#admin_page__left{ + height: 100%; + overflow-y: hidden; + sm-tab-header{ + --gap: 0; + --justify-content: stretch; + background-color: var(--foreground-color); + border-bottom: 1px solid rgba(var(--text-color), 0.2); + } + sm-tab{ + justify-content: center; + } + sm-tab-panels, + sm-tab-panels > *{ + height: 100%; + flex-direction: column; + } + sm-tab-panels{ + overflow-y: hidden; + } + sm-tab-panels > *{ + display: flex; + } + .list-container{ + height: 100%; + overflow-y: auto; + padding-bottom: 2rem; + } + .empty-state{ + padding: 1rem; + text-align: center; + } +} +#update_filters_wrapper{ + gap: 1.5rem; +} +input[type="date"]{ + display: flex; + width: 100%; + padding: 0.5rem; + border: rgba(var(--text-color), 0.2) solid thin; + border-radius: 0.3rem; + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: rgba(var(--text-color), 0.06); + &:focus{ + outline: none; + box-shadow: 0 0 0 0.1rem var(--accent-color); + } +} +.search__icon{ + height: 1.2rem; + width: 1.2rem; +} +#user_role{ + justify-self: start; + font-size: 0.7rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.4rem 0.8rem; + border-radius: 0.3rem; + border: solid var(--accent-color) thin; +} +#project_watching_section{ + display: grid; + gap: 1rem; +} +#project_watchlist{ + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(15rem ,1fr)); + +} +.watchlist_project_card{ + color: inherit; + display: grid; + border-radius: 0.5rem; + grid-template-rows: auto 1fr; + gap: 1rem; + padding: 1rem; + background-color: rgba(var(--text-color), 0.04); + .project__title{ + font-size: 1.1rem; + line-height: 1.5; + } +} +.progress-bar{ + display: flex; + height: 0.5rem; + background-color: rgba(var(--text-color), 0.2); + border-radius: 1rem; + overflow: hidden; + align-self: flex-end; + .progress-value{ + background-color: var(--accent-color); + transition: width 0.3s; + } +} +#username{ + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} +#logout{ + margin-top: 1.5rem; +} +@media only screen and (max-width: 640px) { + .hide-on-mobile, + .hide-page-on-mobile { + display: none; + } + #project_editing_panel{ + padding: 1rem; + } + .list-container{ + padding-bottom: 5rem; + } +} +@media only screen and (min-width: 640px) { + .hide-on-desktop { + display: none !important; + } + + sm-popup { + --width: 26rem; + } + + .popup__header { + padding: 1.5rem 1.5rem 0 0.75rem; + } + + #main_nav { + padding: 0.5rem; + background-color: rgba(var(--background-color), 1); + flex-direction: column; + theme-toggle{ + margin: 1rem; + margin-top: auto; + } + } + + .nav-list__item { + flex-direction: row; + align-items: center; + + border-radius: 0.5rem; + padding: 0.8rem; + margin-bottom: 0.25rem; + + font-size: 1rem; + + &--active { + background-color: rgba(var(--text-color), 0.06); + } + + .icon { + margin-bottom: 0; + } + &_title{ + display: none; + } + } + .project-card { + &--active{ + background-color: rgba(var(--text-color), 0.1); + } + } + .page{ + background-color: var(--foreground-color); + } + + #sign_in { + width: 24rem; + height: auto; + border-radius: 0.4rem; + } + + #dashboard_page { + grid-template-columns: 3fr 18rem; + } + + #dashboard_page #project_watching_section { + align-self: flex-start; + } + #all_interns_page__header{ + grid-template-columns: 1fr auto; + } + + #admin_page { + padding: 1rem 0; + gap: 1rem; + grid-template-columns: 18rem minmax(0, 1fr); + grid-template-rows: 1fr; + } + #admin_page__left{ + background-color: var(--foreground-color); + } + #project_editing_panel{ + padding-right: 1rem; + } + #admin_page__left, + #project_editing_panel{ + border-radius: 0.5rem; + } + + #edit_data_fig { + width: 16rem; + justify-self: center; + } + + #project_explorer { + display: grid; + height: 100%; + grid-template-columns: 16rem 3fr; + grid-template-areas: 'left right'; + } + #project_explorer__left { + grid-area: left; + height: 100%; + overflow-y: auto; + padding-bottom: 1.5rem; + border-right: 1px solid rgba(var(--text-color), 0.06); + background-color: rgba(var(--background-color), 1); + } + + #project_explorer__left h4 { + margin-top: 0; + margin-bottom: 0.5rem; + color: var(--accent-color); + font-size: 0.9rem; + } + + #project_explorer__right { + grid-area: right; + height: 100%; + overflow-y: auto; + } + #main_page { + grid-template-columns: 4rem minmax(0, 1fr); + grid-template-areas: 'main-header main-header''main-nav sub-pages'; + } + + #post_update_popup{ + --width: 28rem; + } + #updates_page{ + height: 100%; + gap: 1rem; + grid-template-areas: 'updates update-filters'; + grid-template-columns: minmax(0, 1fr) 20rem; + } + #update_filters_wrapper{ + padding: 1rem; + border-radius: 0.5rem; + align-content: flex-start; + grid-area: update-filters; + background-color: var(--foreground-color); + } + #updates_wrapper{ + height: 100%; + overflow-y: auto; + grid-area: updates; + } + #all_interns_list{ + gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(14rem ,1fr)); + .intern-card{ + gap: 1.5rem 0.5rem; + padding: 1.5rem; + grid-template-columns: 1fr; + border-radius: 0.5rem; + background-color: var(--foreground-color); + &__initials{ + position: relative; + grid-column: 1/3; + z-index: 1; + } + &__initials::after{ + content: ''; + position: absolute; + background-color: inherit; + border-radius: inherit; + height: calc(100% + 1rem); + width: calc(100% + 1rem); + opacity: 0.3; + z-index: -1; + } + } + } + #intern_list_popup { + --height: 80vh; + } + #settings_page { + height: 100%; + align-items: flex-start; + padding: 2rem; + } + .watchlist_project_card{ + padding: 1.5rem; + } +} + +@media only screen and (min-width: 1280px) { + #main_page { + // gap: 0 1.5rem; + grid-template-columns: 12rem minmax(0, 1fr); + grid-template-areas: 'main-header main-header''main-nav sub-pages'; + } + #main_nav{ + align-items: flex-start; + } + .nav-list__item { + + .icon { + margin-right: 0.5rem; + } + &_title{ + display: inline-block; + } + } +} + +@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:hover { + background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), var(--foreground-color); + } + + .send-update-button, + .task-option, + .apply-button { + opacity: 0; + transition: opacity 0.3s; + } + + + .task-list-item:hover .task-option, + .task-option:focus-within, + .task:hover .apply-button, + .task-card:hover .send-update-button { + opacity: 1; + } +} + +@media (any-hover: none) { +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..59a1e99 --- /dev/null +++ b/index.html @@ -0,0 +1,11655 @@ + + + + + + RIBC + + + + + + + + + + + + + + + + +

+

+
+ Cancel + OK +
+
+
+ +

Loading RIBC

+

+ A FLO Blockchain App by RanchiMall +

+ +
+
+

Sign In

+

Welcome to RIBC.

+ + + Sign in + +

+ Don't have a private key? get it here +
or +

+ + Sign in as guest + +
+
+
+ + +
+ +
+
+
+

Projects watchlist

+
+

No project added to watchlist.

+
+
+

My tasks

+
    +
    +
    +
    +
    + + + + +

    Leaderboard

    + All +
    +
    +
    +
    +
    + + + + +

    Projects

    + All +
    +
    +
    +
    +
    +
    +
    +

    +
    + + + + + + + Sign out + +
    +
    +
    +
    + + Projects + Interns + Requests + + +
    +
    +

    No project added

    +
    +
    +
      +

      No interns added

      +
      +
      +
        +

        No pending requests

        +
        +
        +
        +
        +

        +

        +

        Tasks

        + +
          +

          No tasks added yet, tasks will appear here after adding them.

          + + + + + + Add task + +
            +
          • + + + + + Edit title +
          • +
          • + + + + + Edit description +
          • +
          • + + + + + Assign an intern +
          • +
          • + + + + + Create new Branch +
          • +
          • + + + + + Delete +
          • +
          +
          +
          +
            +
          • + + Add project + + + + + +
          • +
          • + + Add intern + + + + + +
          • +
          • + + Commit changes + + + + + +
          • +
          + +
          +
          +
          +
          + Filter +
          +

          Filter

          +
          +
          By Projects
          + +
          +
          +
          By Intern
          + +
          + + Clear +
          +
          +
            +

            No related updates

            +
            +
            +
            +
            +

            Interns

            + + + + + + +
            +
              +

              No intern found

              +
              +
              +
              +

              My projects

              +
              +

              Other projects

              +
              +
              +
              +
              +

              + + Watch + +
              +

              + +

              +
              +

              No tasks are added to this projects

              +
              +
              +
              +
              + + + +
              +
              +

              Intern name

              + +
              +
              + + + + +

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

              No intern found

              +
              + + + + + + + + + + + + Add + + + + + + + + + + + + + + + Add + + + + + + + + + + + + + + Create + + + + + +
              +

              + + + + + + + + Post update + + +
              + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/old.html b/old.html new file mode 100644 index 0000000..31abc3e --- /dev/null +++ b/old.html @@ -0,0 +1,13719 @@ + + + + + RIBC + + + + + + + + + +
              + Message + +
              + + + + +
              +
              +
              + + + + +

              Projects you are watching

              + + +
              +
              + + +
              +
              +

              My task

              +
              +

              +

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

              Leaderboard

              + All +
              +
              + +
              +
              +
              +
              + + + + + +

              Projects

              + All +
              +
              +
              +
              + +
              +
              +

              Settings

              +
              +

              Account

              +

              + +
              +
              +

              Dark mode

              +
              + + Automatic
              + Dark mode active : 6pm - 6am +
              + +
              +
              + Manual
              + Dark mode +
              + +
              +
              +
              +

              About

              +
              Version 8.2.5
              + +
              Powered by
              + + + + + + + + + + + + + +
              +
              +
              +
              +
              + + Go back to previous page + + +

              +
              +
              +
              +
              +
              + + Go back to previous page + + +

              Projects

              +
              +
              +

              My projects

              +
              +

              Other projects

              +
              +
              + +
              +
              +
              +
              +
              +

              Projects

              + + show project adding panel + + +
              +
              + +
              +
              +
              +
              +

              Interns

              + + show new intern adding panel + + +
              +
              + +
              +
              +
              +
              +
              + + admin panel illustration + + + +

              Click on a project to manage it.

              +
              +
              +
              +
              +

              Project Name

              +
              +

              + +

              +
              +
              +

              Tasks

              +
              + +
              + + +
              +
              +
              + Copied +
              + + + + + + + + + + + + + + + + + + + + + + +