Feature update
- added option to mark any open article as default - added new article creation UI and flow - added feature to add section after creation of article
This commit is contained in:
parent
70b13b7f5a
commit
0bee787ccb
489
components.js
489
components.js
@ -74,11 +74,13 @@ smButton.innerHTML = `
|
|||||||
background-color: rgba(var(--text-color), 0.3);
|
background-color: rgba(var(--text-color), 0.3);
|
||||||
}
|
}
|
||||||
@media (hover: hover){
|
@media (hover: hover){
|
||||||
:host(:not([disabled])) .button:hover{
|
:host(:not([disabled])) .button:hover,
|
||||||
|
:host(:focus-within:not([disabled])) .button{
|
||||||
-webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);
|
-webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);
|
||||||
box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);
|
box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);
|
||||||
}
|
}
|
||||||
:host([variant='outlined']) .button:hover{
|
:host([variant='outlined']:not([disabled])) .button:hover,
|
||||||
|
:host(:focus-within[variant='outlined']:not([disabled])) .button:hover{
|
||||||
-webkit-box-shadow: 0 0 0 1px rgba(var(--text-color), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);
|
-webkit-box-shadow: 0 0 0 1px rgba(var(--text-color), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);
|
||||||
box-shadow: 0 0 0 1px rgba(var(--text-color), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);
|
box-shadow: 0 0 0 1px rgba(var(--text-color), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);
|
||||||
}
|
}
|
||||||
@ -120,6 +122,9 @@ customElements.define('sm-button',
|
|||||||
this.removeAttribute('disabled');
|
this.removeAttribute('disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
focusIn() {
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
|
||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
if (!this.hasAttribute('disabled') && (e.key === 'Enter' || e.code === 'Space')) {
|
if (!this.hasAttribute('disabled') && (e.key === 'Enter' || e.code === 'Space')) {
|
||||||
@ -156,12 +161,11 @@ smForm.innerHTML = `
|
|||||||
}
|
}
|
||||||
:host{
|
:host{
|
||||||
display: flex;
|
display: flex;
|
||||||
--gap: 1rem;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
form{
|
form{
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--gap);
|
gap: var(--gap, 1.5rem);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -986,6 +990,27 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Stack {
|
||||||
|
constructor() {
|
||||||
|
this.items = [];
|
||||||
|
}
|
||||||
|
push(element) {
|
||||||
|
this.items.push(element);
|
||||||
|
}
|
||||||
|
pop() {
|
||||||
|
if (this.items.length == 0)
|
||||||
|
return "Underflow";
|
||||||
|
return this.items.pop();
|
||||||
|
}
|
||||||
|
peek() {
|
||||||
|
return this.items[this.items.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const popupStack = new Stack();
|
||||||
|
|
||||||
const smPopup = document.createElement('template');
|
const smPopup = document.createElement('template');
|
||||||
smPopup.innerHTML = `
|
smPopup.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
@ -1019,10 +1044,6 @@ smPopup.innerHTML = `
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
background: var(--backdrop-background);
|
|
||||||
-webkit-transition: opacity 0.3s;
|
|
||||||
-o-transition: opacity 0.3s;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
@ -1030,6 +1051,18 @@ smPopup.innerHTML = `
|
|||||||
-webkit-transform: scale(0.9) translateY(-2rem) !important;
|
-webkit-transform: scale(0.9) translateY(-2rem) !important;
|
||||||
transform: scale(0.9) translateY(-2rem) !important;
|
transform: scale(0.9) translateY(-2rem) !important;
|
||||||
}
|
}
|
||||||
|
.background{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
background: var(--backdrop-background);
|
||||||
|
-webkit-transition: opacity 0.3s;
|
||||||
|
-o-transition: opacity 0.3s;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
.popup{
|
.popup{
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
@ -1049,17 +1082,10 @@ smPopup.innerHTML = `
|
|||||||
min-height: var(--min-height);
|
min-height: var(--min-height);
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
-webkit-transform: scale(1) translateY(100%);
|
|
||||||
transform: scale(1) translateY(100%);
|
|
||||||
-webkit-transition: -webkit-transform 0.3s;
|
|
||||||
transition: -webkit-transform 0.3s;
|
|
||||||
-o-transition: transform 0.3s;
|
|
||||||
transition: transform 0.3s, -webkit-transform 0.3s;
|
|
||||||
transition: transform 0.3s;
|
|
||||||
background: rgba(var(--background-color), 1);
|
background: rgba(var(--background-color), 1);
|
||||||
-webkit-box-shadow: 0 -1rem 2rem #00000020;
|
-webkit-box-shadow: 0 -1rem 2rem #00000020;
|
||||||
box-shadow: 0 -1rem 2rem #00000020;
|
box-shadow: 0 -1rem 2rem #00000020;
|
||||||
content-visibility: auto;
|
transition: transform 0.3s;
|
||||||
}
|
}
|
||||||
.container-header{
|
.container-header{
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
@ -1090,13 +1116,11 @@ smPopup.innerHTML = `
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.hide{
|
.hide{
|
||||||
opacity: 0;
|
display:none;
|
||||||
pointer-events: none;
|
|
||||||
visibility: none;
|
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 640px){
|
@media screen and (min-width: 640px){
|
||||||
:host{
|
:host{
|
||||||
--border-radius: 0.4rem;
|
--border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
.popup{
|
.popup{
|
||||||
-ms-flex-item-align: center;
|
-ms-flex-item-align: center;
|
||||||
@ -1104,8 +1128,6 @@ smPopup.innerHTML = `
|
|||||||
align-self: center;
|
align-self: center;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
height: var(--height);
|
height: var(--height);
|
||||||
-webkit-transform: scale(1) translateY(3rem);
|
|
||||||
transform: scale(1) translateY(3rem);
|
|
||||||
-webkit-box-shadow: 0 3rem 2rem -0.5rem #00000040;
|
-webkit-box-shadow: 0 3rem 2rem -0.5rem #00000040;
|
||||||
box-shadow: 0 3rem 2rem -0.5rem #00000040;
|
box-shadow: 0 3rem 2rem -0.5rem #00000040;
|
||||||
}
|
}
|
||||||
@ -1140,7 +1162,8 @@ smPopup.innerHTML = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div part="background" class="popup-container hide" role="dialog">
|
<div class="popup-container hide" role="dialog">
|
||||||
|
<div part="background" class="background"></div>
|
||||||
<div part="popup" class="popup">
|
<div part="popup" class="popup">
|
||||||
<div part="popup-header" class="popup-top">
|
<div part="popup-header" class="popup-top">
|
||||||
<div class="handle"></div>
|
<div class="handle"></div>
|
||||||
@ -1162,7 +1185,6 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
this.allowClosing = false;
|
this.allowClosing = false;
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.pinned = false;
|
this.pinned = false;
|
||||||
this.popupStack = undefined;
|
|
||||||
this.offset = 0;
|
this.offset = 0;
|
||||||
this.touchStartY = 0;
|
this.touchStartY = 0;
|
||||||
this.touchEndY = 0;
|
this.touchEndY = 0;
|
||||||
@ -1174,17 +1196,18 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
this.mutationObserver
|
this.mutationObserver
|
||||||
|
|
||||||
this.popupContainer = this.shadowRoot.querySelector('.popup-container');
|
this.popupContainer = this.shadowRoot.querySelector('.popup-container');
|
||||||
|
this.backdrop = this.shadowRoot.querySelector('.background');
|
||||||
this.popup = this.shadowRoot.querySelector('.popup');
|
this.popup = this.shadowRoot.querySelector('.popup');
|
||||||
this.popupBodySlot = this.shadowRoot.querySelector('.popup-body slot');
|
this.popupBodySlot = this.shadowRoot.querySelector('.popup-body slot');
|
||||||
this.popupHeader = this.shadowRoot.querySelector('.popup-top');
|
this.popupHeader = this.shadowRoot.querySelector('.popup-top');
|
||||||
|
|
||||||
this.resumeScrolling = this.resumeScrolling.bind(this);
|
this.resumeScrolling = this.resumeScrolling.bind(this);
|
||||||
|
this.setStateOpen = this.setStateOpen.bind(this);
|
||||||
this.show = this.show.bind(this);
|
this.show = this.show.bind(this);
|
||||||
this.hide = this.hide.bind(this);
|
this.hide = this.hide.bind(this);
|
||||||
this.handleTouchStart = this.handleTouchStart.bind(this);
|
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||||
this.handleTouchMove = this.handleTouchMove.bind(this);
|
this.handleTouchMove = this.handleTouchMove.bind(this);
|
||||||
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||||
this.movePopup = this.movePopup.bind(this);
|
|
||||||
this.detectFocus = this.detectFocus.bind(this);
|
this.detectFocus = this.detectFocus.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1196,86 +1219,140 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
return this.isOpen;
|
return this.isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animateTo(element, keyframes, options) {
|
||||||
|
const anime = element.animate(keyframes, { ...options, fill: 'both' })
|
||||||
|
anime.finished.then(() => {
|
||||||
|
anime.commitStyles()
|
||||||
|
anime.cancel()
|
||||||
|
})
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
resumeScrolling() {
|
resumeScrolling() {
|
||||||
const scrollY = document.body.style.top;
|
const scrollY = document.body.style.top;
|
||||||
window.scrollTo(0, parseInt(scrollY || '0') * -1);
|
window.scrollTo(0, parseInt(scrollY || '0') * -1);
|
||||||
setTimeout(() => {
|
document.body.style.overflow = 'auto';
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.top = 'initial';
|
||||||
document.body.style.top = 'initial';
|
}
|
||||||
}, 300);
|
|
||||||
|
setStateOpen() {
|
||||||
|
const animOptions = {
|
||||||
|
duration: 300,
|
||||||
|
easing: 'ease'
|
||||||
|
}
|
||||||
|
const initialAnimation = (window.innerWidth > 640) ? 'scale(1.1)' : `translateY(${this.offset ? `${this.offset}px` : '100%'})`
|
||||||
|
this.animateTo(this.popup, [
|
||||||
|
{
|
||||||
|
opacity: this.offset ? 1 : 0,
|
||||||
|
transform: initialAnimation
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'none'
|
||||||
|
},
|
||||||
|
], animOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
show(options = {}) {
|
show(options = {}) {
|
||||||
const { pinned = false, popupStack } = options;
|
const { pinned = false } = options;
|
||||||
if (popupStack)
|
if (!this.isOpen) {
|
||||||
this.popupStack = popupStack;
|
const animOptions = {
|
||||||
if (this.popupStack && !this.hasAttribute('open')) {
|
duration: 300,
|
||||||
this.popupStack.push({
|
easing: 'ease'
|
||||||
popup: this,
|
|
||||||
permission: pinned
|
|
||||||
});
|
|
||||||
if (this.popupStack.items.length > 1) {
|
|
||||||
this.popupStack.items[this.popupStack.items.length - 2].popup.classList.add('stacked');
|
|
||||||
}
|
}
|
||||||
|
if (popupStack) {
|
||||||
|
popupStack.push({
|
||||||
|
popup: this,
|
||||||
|
permission: pinned
|
||||||
|
});
|
||||||
|
if (popupStack.items.length > 1) {
|
||||||
|
this.animateTo(popupStack.items[popupStack.items.length - 2].popup.shadowRoot.querySelector('.popup'), [
|
||||||
|
{ transform: 'none' },
|
||||||
|
{ transform: 'translateY(-1.5rem) scale(0.9)' },
|
||||||
|
], animOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.popupContainer.classList.remove('hide');
|
||||||
|
if (!this.offset)
|
||||||
|
this.backdrop.animate([
|
||||||
|
{ opacity: 0 },
|
||||||
|
{ opacity: 1 },
|
||||||
|
], animOptions)
|
||||||
|
this.setStateOpen()
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("popupopened", {
|
new CustomEvent("popupopened", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
detail: {
|
detail: {
|
||||||
popup: this,
|
popup: this,
|
||||||
popupStack: this.popupStack
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.setAttribute('open', '');
|
|
||||||
this.pinned = pinned;
|
this.pinned = pinned;
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.body.style.top = `-${window.scrollY}px`;
|
||||||
|
const elementToFocus = this.autoFocus || this.focusable[0];
|
||||||
|
elementToFocus.tagName.includes('SM-') ? elementToFocus.focusIn() : elementToFocus.focus();
|
||||||
|
if (!this.hasAttribute('open'))
|
||||||
|
this.setAttribute('open', '');
|
||||||
}
|
}
|
||||||
this.popupContainer.classList.remove('hide');
|
|
||||||
this.popup.style.transform = 'none';
|
|
||||||
document.body.style.overflow = 'hidden';
|
|
||||||
document.body.style.top = `-${window.scrollY}px`;
|
|
||||||
const elementToFocus = this.autoFocus || this.focusable[0];
|
|
||||||
elementToFocus.tagName.includes('SM-') ? elementToFocus.focusIn() : elementToFocus.focus();
|
|
||||||
return this.popupStack;
|
|
||||||
}
|
}
|
||||||
hide() {
|
hide() {
|
||||||
if (window.innerWidth < 640)
|
const animOptions = {
|
||||||
this.popup.style.transform = 'translateY(100%)';
|
duration: 150,
|
||||||
else
|
easing: 'ease'
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
this.backdrop.animate([
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ opacity: 0 }
|
||||||
|
], animOptions)
|
||||||
|
this.animateTo(this.popup, [
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: (window.innerWidth > 640) ? 'none' : `translateY(${this.offset ? `${this.offset}px` : '0'})`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: (window.innerWidth > 640) ? 'scale(1.1)' : 'translateY(100%)'
|
||||||
|
},
|
||||||
|
], animOptions).finished
|
||||||
|
.finally(() => {
|
||||||
|
this.popupContainer.classList.add('hide');
|
||||||
|
this.popup.style = ''
|
||||||
|
this.removeAttribute('open');
|
||||||
|
if (typeof popupStack !== 'undefined') {
|
||||||
|
popupStack.pop();
|
||||||
|
if (popupStack.items.length) {
|
||||||
|
this.animateTo(popupStack.items[popupStack.items.length - 1].popup.shadowRoot.querySelector('.popup'), [
|
||||||
|
{ transform: 'translateY(-1.5rem) scale(0.9)' },
|
||||||
|
{ transform: 'none' },
|
||||||
|
], animOptions)
|
||||||
|
|
||||||
if (this.forms.length) {
|
} else {
|
||||||
setTimeout(() => {
|
this.resumeScrolling();
|
||||||
this.forms.forEach(form => form.reset());
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CustomEvent("popupclosed", {
|
|
||||||
bubbles: true,
|
|
||||||
detail: {
|
|
||||||
popup: this,
|
|
||||||
popupStack: this.popupStack
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
);
|
this.resumeScrolling();
|
||||||
this.isOpen = false;
|
}
|
||||||
}, 300);
|
|
||||||
|
if (this.forms.length) {
|
||||||
|
this.forms.forEach(form => form.reset());
|
||||||
|
}
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("popupclosed", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: {
|
||||||
|
popup: this,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.isOpen = false;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTouchStart(e) {
|
handleTouchStart(e) {
|
||||||
|
this.popupHeader.addEventListener('touchmove', this.handleTouchMove, { passive: true });
|
||||||
|
this.popupHeader.addEventListener('touchend', this.handleTouchEnd, { passive: true });
|
||||||
this.touchStartY = e.changedTouches[0].clientY;
|
this.touchStartY = e.changedTouches[0].clientY;
|
||||||
this.popup.style.transition = 'transform 0.1s';
|
this.popup.style.transition = 'transform 0.1s';
|
||||||
this.touchStartTime = e.timeStamp;
|
this.touchStartTime = e.timeStamp;
|
||||||
@ -1284,7 +1361,9 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
handleTouchMove(e) {
|
handleTouchMove(e) {
|
||||||
if (this.touchStartY < e.changedTouches[0].clientY) {
|
if (this.touchStartY < e.changedTouches[0].clientY) {
|
||||||
this.offset = e.changedTouches[0].clientY - this.touchStartY;
|
this.offset = e.changedTouches[0].clientY - this.touchStartY;
|
||||||
this.touchEndAnimation = window.requestAnimationFrame(() => this.movePopup());
|
this.touchEndAnimation = window.requestAnimationFrame(() => {
|
||||||
|
this.popup.style.transform = `translateY(${this.offset}px)`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1297,27 +1376,26 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
if (this.touchEndTime - this.touchStartTime > 200) {
|
if (this.touchEndTime - this.touchStartTime > 200) {
|
||||||
if (this.touchEndY - this.touchStartY > this.threshold) {
|
if (this.touchEndY - this.touchStartY > this.threshold) {
|
||||||
if (this.pinned) {
|
if (this.pinned) {
|
||||||
this.show();
|
this.setStateOpen();
|
||||||
return;
|
return;
|
||||||
} else
|
} else
|
||||||
this.hide();
|
this.hide();
|
||||||
} else {
|
} else {
|
||||||
this.show();
|
this.setStateOpen();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.touchEndY > this.touchStartY)
|
if (this.touchEndY > this.touchStartY)
|
||||||
if (this.pinned) {
|
if (this.pinned) {
|
||||||
this.show();
|
this.setStateOpen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
|
this.popupHeader.removeEventListener('touchmove', this.handleTouchMove, { passive: true });
|
||||||
|
this.popupHeader.removeEventListener('touchend', this.handleTouchEnd, { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
movePopup() {
|
|
||||||
this.popup.style.transform = `translateY(${this.offset}px)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
detectFocus(e) {
|
detectFocus(e) {
|
||||||
if (e.code === 'Tab') {
|
if (e.code === 'Tab') {
|
||||||
@ -1333,14 +1411,20 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFocusableList() {
|
||||||
|
this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input, sm-select, select, sm-checkbox, sm-textarea, textarea, [tabindex]:not([tabindex="-1"])')
|
||||||
|
this.autoFocus = this.querySelector('[autofocus]')
|
||||||
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.popupBodySlot.addEventListener('slotchange', () => {
|
this.popupBodySlot.addEventListener('slotchange', () => {
|
||||||
this.forms = this.querySelectorAll('sm-form');
|
this.forms = this.querySelectorAll('sm-form');
|
||||||
|
this.updateFocusableList()
|
||||||
});
|
});
|
||||||
this.popupContainer.addEventListener('mousedown', e => {
|
this.popupContainer.addEventListener('mousedown', e => {
|
||||||
if (e.target === this.popupContainer && !this.pinned) {
|
if (e.target === this.popupContainer && !this.pinned) {
|
||||||
if (this.pinned) {
|
if (this.pinned) {
|
||||||
this.show();
|
this.setStateOpen();
|
||||||
} else
|
} else
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
@ -1360,25 +1444,18 @@ customElements.define('sm-popup', class extends HTMLElement {
|
|||||||
resizeObserver.observe(this);
|
resizeObserver.observe(this);
|
||||||
|
|
||||||
this.mutationObserver = new MutationObserver(entries => {
|
this.mutationObserver = new MutationObserver(entries => {
|
||||||
entries.forEach(mutation => {
|
this.updateFocusableList()
|
||||||
this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input, sm-select, select, sm-checkbox, sm-textarea, textarea, [tabindex]:not([tabindex="-1"])')
|
|
||||||
this.autoFocus = this.querySelector('[autofocus]')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true })
|
this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true })
|
||||||
|
|
||||||
this.addEventListener('keydown', this.detectFocus);
|
this.addEventListener('keydown', this.detectFocus);
|
||||||
this.popupHeader.addEventListener('touchstart', this.handleTouchStart, { passive: true });
|
this.popupHeader.addEventListener('touchstart', this.handleTouchStart, { passive: true });
|
||||||
this.popupHeader.addEventListener('touchmove', this.handleTouchMove, { passive: true });
|
|
||||||
this.popupHeader.addEventListener('touchend', this.handleTouchEnd, { passive: true });
|
|
||||||
}
|
}
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.removeEventListener('keydown', this.detectFocus);
|
this.removeEventListener('keydown', this.detectFocus);
|
||||||
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();
|
resizeObserver.unobserve();
|
||||||
this.mutationObserver.disconnect()
|
this.mutationObserver.disconnect()
|
||||||
|
this.popupHeader.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
|
||||||
}
|
}
|
||||||
attributeChangedCallback(name) {
|
attributeChangedCallback(name) {
|
||||||
if (name === 'open') {
|
if (name === 'open') {
|
||||||
@ -2281,7 +2358,7 @@ smSelect.innerHTML = `
|
|||||||
fill: rgba(var(--text-color), 0.7);
|
fill: rgba(var(--text-color), 0.7);
|
||||||
}
|
}
|
||||||
.selected-option-text{
|
.selected-option-text{
|
||||||
font-size: 0.9rem;
|
font-size: inherit;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-o-text-overflow: ellipsis;
|
-o-text-overflow: ellipsis;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@ -2315,6 +2392,7 @@ smSelect.innerHTML = `
|
|||||||
}
|
}
|
||||||
.options{
|
.options{
|
||||||
top: 100%;
|
top: 100%;
|
||||||
|
padding: var(--options-padding, 0.3rem);
|
||||||
margin-top: 0.2rem;
|
margin-top: 0.2rem;
|
||||||
overflow: hidden auto;
|
overflow: hidden auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -2330,7 +2408,7 @@ smSelect.innerHTML = `
|
|||||||
max-height: var(--max-height);
|
max-height: var(--max-height);
|
||||||
background: rgba(var(--background-color), 1);
|
background: rgba(var(--background-color), 1);
|
||||||
border: solid 1px rgba(var(--text-color), 0.2);
|
border: solid 1px rgba(var(--text-color), 0.2);
|
||||||
border-radius: 0.3rem;
|
border-radius: var(--border-radius, 0.5rem);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
||||||
box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
||||||
@ -2600,11 +2678,12 @@ smOption.innerHTML = `
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
grid-template-columns: max-content minmax(0, 1fr);
|
grid-template-columns: max-content minmax(0, 1fr);
|
||||||
padding: 0.8rem 1.2rem;
|
padding: var(--padding, 0.6rem 1rem);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
outline: none;
|
outline: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
border-radius: var(--border-radius, 0.3rem);
|
||||||
}
|
}
|
||||||
:host(:focus){
|
:host(:focus){
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -2746,6 +2825,7 @@ customElements.define('sm-checkbox', class extends HTMLElement {
|
|||||||
mode: 'open'
|
mode: 'open'
|
||||||
}).append(smCheckbox.content.cloneNode(true))
|
}).append(smCheckbox.content.cloneNode(true))
|
||||||
|
|
||||||
|
this.defaultState
|
||||||
this.checkbox = this.shadowRoot.querySelector('.checkbox');
|
this.checkbox = this.shadowRoot.querySelector('.checkbox');
|
||||||
|
|
||||||
this.reset = this.reset.bind(this)
|
this.reset = this.reset.bind(this)
|
||||||
@ -2796,7 +2876,7 @@ customElements.define('sm-checkbox', class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.removeAttribute('checked')
|
this.value = this.defaultState
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch() {
|
dispatch() {
|
||||||
@ -2820,6 +2900,7 @@ customElements.define('sm-checkbox', class extends HTMLElement {
|
|||||||
this.setAttribute('tabindex', '0')
|
this.setAttribute('tabindex', '0')
|
||||||
}
|
}
|
||||||
this.setAttribute('role', 'checkbox')
|
this.setAttribute('role', 'checkbox')
|
||||||
|
this.defaultState = this.hasAttribute('checked')
|
||||||
if (!this.hasAttribute('checked')) {
|
if (!this.hasAttribute('checked')) {
|
||||||
this.setAttribute('aria-checked', 'false')
|
this.setAttribute('aria-checked', 'false')
|
||||||
}
|
}
|
||||||
@ -3417,6 +3498,10 @@ customElements.define('sm-switch', class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
dispatch() {
|
dispatch() {
|
||||||
this.dispatchEvent(new CustomEvent('change', {
|
this.dispatchEvent(new CustomEvent('change', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
@ -4004,4 +4089,204 @@ customElements.define('menu-option', class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const smTextarea = document.createElement('template')
|
||||||
|
smTextarea.innerHTML = `
|
||||||
|
<style>
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
::-moz-focus-inner{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.hide{
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
:host{
|
||||||
|
display: grid;
|
||||||
|
--accent-color: #4d2588;
|
||||||
|
--text-color: 17, 17, 17;
|
||||||
|
--background-color: 255, 255, 255;
|
||||||
|
--danger-color: red;
|
||||||
|
--border-radius: 0.3rem;
|
||||||
|
--background: rgba(var(--text-color), 0.06);
|
||||||
|
--padding: initial;
|
||||||
|
--max-height: 8rem;
|
||||||
|
}
|
||||||
|
:host([variant="outlined"]) .textarea {
|
||||||
|
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 0.4) inset;
|
||||||
|
background: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
.textarea{
|
||||||
|
display: grid;
|
||||||
|
position: relative;
|
||||||
|
cursor: text;
|
||||||
|
min-width: 0;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden auto;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
align-items: stretch;
|
||||||
|
max-height: var(--max-height);
|
||||||
|
background: var(--background);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: var(--padding);
|
||||||
|
}
|
||||||
|
.textarea::after,
|
||||||
|
textarea{
|
||||||
|
padding: 0.7rem 1rem;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 1em;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
resize: none;
|
||||||
|
grid-area: 2/1;
|
||||||
|
justify-self: stretch;
|
||||||
|
background: none;
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
line-height: 1.5;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.textarea::after{
|
||||||
|
content: attr(data-value) ' ';
|
||||||
|
visibility: hidden;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
.readonly{
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.textarea:focus-within:not(.readonly){
|
||||||
|
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
|
||||||
|
}
|
||||||
|
.placeholder{
|
||||||
|
position: absolute;
|
||||||
|
margin: 0.7rem 1rem;
|
||||||
|
opacity: .7;
|
||||||
|
font-weight: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: 1.5;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
:host([disabled]) .textarea{
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<label class="textarea" part="textarea">
|
||||||
|
<span class="placeholder"></span>
|
||||||
|
<textarea rows="1"></textarea>
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
48
css/main.css
48
css/main.css
@ -132,7 +132,8 @@ a:any-link:focus-visible {
|
|||||||
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sm-input {
|
sm-input,
|
||||||
|
sm-textarea {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
--border-radius: 0.3rem;
|
--border-radius: 0.3rem;
|
||||||
}
|
}
|
||||||
@ -346,12 +347,8 @@ ul {
|
|||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: grid;
|
display: grid;
|
||||||
-webkit-box-pack: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.observe-empty-state:empty {
|
.observe-empty-state:empty {
|
||||||
@ -581,6 +578,11 @@ menu-option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.article-link {
|
.article-link {
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
color: rgba(var(--text-color), 0.8);
|
color: rgba(var(--text-color), 0.8);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -590,15 +592,17 @@ menu-option {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.default-article {
|
.default-article::before {
|
||||||
margin-left: auto;
|
-ms-flex-item-align: start;
|
||||||
|
align-self: flex-start;
|
||||||
|
content: "Actively written";
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
background-color: #00e67650;
|
background-color: var(--accent-color);
|
||||||
padding: 0.2rem 0.4rem;
|
padding: 0.2rem 0.4rem;
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.2rem;
|
||||||
font-weight: 700;
|
font-weight: 500;
|
||||||
letter-spacing: 0.05em;
|
color: var(--foreground-color);
|
||||||
color: rgba(var(--text-color), 0.8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#edit_sections_popup {
|
#edit_sections_popup {
|
||||||
@ -614,21 +618,30 @@ menu-option {
|
|||||||
|
|
||||||
.section-card {
|
.section-card {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.section-card:not(.section-card--new) {
|
.section-card:not(.section-card--new) {
|
||||||
padding: 0.8rem 0;
|
padding: 0.8rem 0;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.section-card--new input {
|
.section-card--new input {
|
||||||
border: none;
|
border: none;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
background: inherit;
|
background: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.8rem 0;
|
padding: 0.8rem 0.2rem;
|
||||||
}
|
}
|
||||||
.section-card--new input:focus {
|
.section-card--new input:focus {
|
||||||
outline: var(--accent-color) solid;
|
outline: var(--accent-color) solid;
|
||||||
}
|
}
|
||||||
|
.section-card .remove {
|
||||||
|
padding: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
#insert_section_button {
|
#insert_section_button {
|
||||||
-ms-flex-item-align: start;
|
-ms-flex-item-align: start;
|
||||||
@ -776,7 +789,7 @@ menu-option {
|
|||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
}
|
}
|
||||||
.active .icon {
|
.active .icon {
|
||||||
fill: white;
|
fill: var(--foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.quote-template {
|
.quote-template {
|
||||||
@ -864,8 +877,9 @@ menu-option {
|
|||||||
background-color: #00e67650;
|
background-color: #00e67650;
|
||||||
}
|
}
|
||||||
.entry__changes .removed {
|
.entry__changes .removed {
|
||||||
-webkit-text-decoration-color: red;
|
color: var(--danger-color);
|
||||||
text-decoration-color: red;
|
-webkit-text-decoration-color: var(--danger-color);
|
||||||
|
text-decoration-color: var(--danger-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 40rem) and (any-hover: none) {
|
@media screen and (max-width: 40rem) and (any-hover: none) {
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -113,7 +113,8 @@ a:any-link:focus-visible {
|
|||||||
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sm-input {
|
sm-input,
|
||||||
|
sm-textarea {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
--border-radius: 0.3rem;
|
--border-radius: 0.3rem;
|
||||||
}
|
}
|
||||||
@ -309,10 +310,8 @@ ul {
|
|||||||
}
|
}
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.observe-empty-state:empty {
|
.observe-empty-state:empty {
|
||||||
@ -488,7 +487,6 @@ menu-option {
|
|||||||
#main_page {
|
#main_page {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#current_article_title {
|
#current_article_title {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
@ -512,6 +510,8 @@ menu-option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.article-link {
|
.article-link {
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
color: rgba(var(--text-color), 0.8);
|
color: rgba(var(--text-color), 0.8);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -521,14 +521,17 @@ menu-option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.default-article {
|
.default-article {
|
||||||
margin-left: auto;
|
&::before {
|
||||||
font-size: 0.7rem;
|
align-self: flex-start;
|
||||||
background-color: #00e67650;
|
content: "Actively written";
|
||||||
padding: 0.2rem 0.4rem;
|
margin-bottom: 0.3rem;
|
||||||
border-radius: 0.3rem;
|
font-size: 0.7rem;
|
||||||
font-weight: 700;
|
background-color: var(--accent-color);
|
||||||
letter-spacing: 0.05em;
|
padding: 0.2rem 0.4rem;
|
||||||
color: rgba(var(--text-color), 0.8);
|
border-radius: 0.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--foreground-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#edit_sections_popup {
|
#edit_sections_popup {
|
||||||
@ -542,8 +545,10 @@ menu-option {
|
|||||||
}
|
}
|
||||||
.section-card {
|
.section-card {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
font-size: 0.9rem;
|
||||||
&:not(.section-card--new) {
|
&:not(.section-card--new) {
|
||||||
padding: 0.8rem 0;
|
padding: 0.8rem 0;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
&--new {
|
&--new {
|
||||||
input {
|
input {
|
||||||
@ -551,13 +556,17 @@ menu-option {
|
|||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
background: inherit;
|
background: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.8rem 0;
|
padding: 0.8rem 0.2rem;
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: var(--accent-color) solid;
|
outline: var(--accent-color) solid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.remove {
|
||||||
|
padding: 0.3rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#insert_section_button {
|
#insert_section_button {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
@ -676,7 +685,7 @@ menu-option {
|
|||||||
.active {
|
.active {
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
.icon {
|
.icon {
|
||||||
fill: white;
|
fill: var(--foreground-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +767,8 @@ menu-option {
|
|||||||
background-color: #00e67650;
|
background-color: #00e67650;
|
||||||
}
|
}
|
||||||
.removed {
|
.removed {
|
||||||
text-decoration-color: red;
|
color: var(--danger-color);
|
||||||
|
text-decoration-color: var(--danger-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
293
index.html
293
index.html
@ -101,6 +101,20 @@
|
|||||||
</svg>
|
</svg>
|
||||||
Edit sections
|
Edit sections
|
||||||
</menu-option>
|
</menu-option>
|
||||||
|
<menu-option onclick="setDefaultArticle()">
|
||||||
|
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
|
fill="#000000">
|
||||||
|
<g>
|
||||||
|
<path d="M0,0h24v24H0V0z" fill="none" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M14,2H6C4.9,2,4.01,2.9,4.01,4L4,20c0,1.1,0.89,2,1.99,2H18c1.1,0,2-0.9,2-2V8L14,2z M18,20H6V4h7v5h5V20z M8.82,13.05 L7.4,14.46L10.94,18l5.66-5.66l-1.41-1.41l-4.24,4.24L8.82,13.05z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Make default article
|
||||||
|
</menu-option>
|
||||||
</sm-menu>
|
</sm-menu>
|
||||||
</div>
|
</div>
|
||||||
<theme-toggle></theme-toggle>
|
<theme-toggle></theme-toggle>
|
||||||
@ -205,8 +219,8 @@
|
|||||||
<h3>Create article</h3>
|
<h3>Create article</h3>
|
||||||
</header>
|
</header>
|
||||||
<sm-form>
|
<sm-form>
|
||||||
<sm-input placeholder="Article title" required autofocus></sm-input>
|
<sm-input id="get_article_title" placeholder="Article title" required autofocus></sm-input>
|
||||||
<sm-checkbox checked>
|
<sm-checkbox id="set_default_checkbox" checked>
|
||||||
<div class="grid button__icon--right gap-0-5">
|
<div class="grid button__icon--right gap-0-5">
|
||||||
Set as default
|
Set as default
|
||||||
<p style="font-size: 0.8rem;">
|
<p style="font-size: 0.8rem;">
|
||||||
@ -214,15 +228,29 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</sm-checkbox>
|
</sm-checkbox>
|
||||||
<!-- <sm-switch>
|
<div class="grid gap-1">
|
||||||
<div slot="left">
|
<div class="grid gap-0-5">
|
||||||
Make private
|
<h4>Define sections (optional)</h4>
|
||||||
|
<p>Create and name sections by writing title of each section separated by a comma (,)</p>
|
||||||
</div>
|
</div>
|
||||||
</sm-switch> -->
|
<sm-textarea id="get_section_titles" rows="4" placeholder="section title 1, section title 2, ...">
|
||||||
<sm-button variant="primary">Create</sm-button>
|
</sm-textarea>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="grid gap-1">
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<sm-switch>
|
||||||
|
<h4 slot="left">
|
||||||
|
Make private
|
||||||
|
</h4>
|
||||||
|
</sm-switch>
|
||||||
|
<p>Define the FLO IDs separated by a comma (,), which are allowed to contribute.</p>
|
||||||
|
</div>
|
||||||
|
<sm-textarea id="get_section_titles" rows="4"></sm-textarea>
|
||||||
|
</div> -->
|
||||||
|
<sm-button variant="primary" onclick="cc.createNewArticle()">Create</sm-button>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
<sm-popup id="edit_sections_popup" open>
|
<sm-popup id="edit_sections_popup">
|
||||||
<header slot="header" class="popup__header">
|
<header slot="header" class="popup__header">
|
||||||
<button class="popup__header__close" onclick="hidePopup()">
|
<button class="popup__header__close" onclick="hidePopup()">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
@ -239,26 +267,29 @@
|
|||||||
<p class="empty-state">
|
<p class="empty-state">
|
||||||
There are no sections so far, you can add section with button below.
|
There are no sections so far, you can add section with button below.
|
||||||
</p>
|
</p>
|
||||||
<button id="insert_section_button" onclick="insertEmptySection()" class="button">
|
<div class="flex space-between align-center">
|
||||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
<sm-button id="insert_section_button" onclick="insertEmptySection()">
|
||||||
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
|
||||||
<g>
|
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<rect fill="none" height="24" width="24" />
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g />
|
|
||||||
<g>
|
<g>
|
||||||
<path
|
<rect fill="none" height="24" width="24" />
|
||||||
d="M17,19.22H5V7h7V5H5C3.9,5,3,5.9,3,7v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-7h-2V19.22z" />
|
|
||||||
<path d="M19,2h-2v3h-3c0.01,0.01,0,2,0,2h3v2.99c0.01,0.01,2,0,2,0V7h3V5h-3V2z" />
|
|
||||||
<rect height="2" width="8" x="7" y="9" />
|
|
||||||
<polygon points="7,12 7,14 15,14 15,12 12,12" />
|
|
||||||
<rect height="2" width="8" x="7" y="15" />
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
<g>
|
||||||
</svg>
|
<g />
|
||||||
Add new section
|
<g>
|
||||||
</button>
|
<path
|
||||||
|
d="M17,19.22H5V7h7V5H5C3.9,5,3,5.9,3,7v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-7h-2V19.22z" />
|
||||||
|
<path d="M19,2h-2v3h-3c0.01,0.01,0,2,0,2h3v2.99c0.01,0.01,2,0,2,0V7h3V5h-3V2z" />
|
||||||
|
<rect height="2" width="8" x="7" y="9" />
|
||||||
|
<polygon points="7,12 7,14 15,14 15,12 12,12" />
|
||||||
|
<rect height="2" width="8" x="7" y="15" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Insert section
|
||||||
|
</sm-button>
|
||||||
|
<sm-button variant="primary" onclick="saveSectionEdit()">Save</sm-button>
|
||||||
|
</div>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
<template id="section_template">
|
<template id="section_template">
|
||||||
<text-field class="heading"></text-field>
|
<text-field class="heading"></text-field>
|
||||||
@ -311,13 +342,20 @@
|
|||||||
<p><br></p>
|
<p><br></p>
|
||||||
</template>
|
</template>
|
||||||
<template id="history_entry_template">
|
<template id="history_entry_template">
|
||||||
<li class="history-entry grid gap-0-5">
|
<li class="history-entry grid gap-1">
|
||||||
<div class="flex align-center space-between">
|
<div class="flex align-center space-between">
|
||||||
<time class="entry__time"></time>
|
<time class="entry__time"></time>
|
||||||
<span class="entry__score"></span>
|
<span class="entry__score"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="label">Author</div>
|
<div class="label flex align-center">
|
||||||
|
<svg class="icon" style="margin-right: 0.2rem;" width="24" height="24" viewBox="0 0 24 24"
|
||||||
|
fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M14.6243 7.99154C13.9395 8.14279 13.4165 8.69672 13.3047 9.38904C13.2248 9.88365 13.3664 10.3773 13.6735 10.7498L9.29125 15.0941C8.93718 15.4451 8.48852 15.6853 8.00011 15.7854L6.12418 16.1699L9.19811 13.1381C9.53438 12.8064 9.53812 12.265 9.20646 11.9287C8.8748 11.5924 8.33333 11.5887 7.99706 11.9203L4.97835 14.8977L5.47976 12.451C5.50451 12.3303 5.55656 12.2168 5.63191 12.1192L6.49083 11.0073C9.58386 7.00317 14.32 4.72705 19.2553 4.71054L16.3569 7.60884L14.6243 7.99154ZM2.79008 17.0559L3.8042 12.1076C3.88132 11.7313 4.0435 11.3776 4.27833 11.0736L5.13724 9.96172C8.89964 5.09105 14.861 2.53305 20.8954 3.07051C21.5971 3.133 22.2997 3.23735 23 3.38478L17.2133 9.1713L14.9932 9.66167L15.4238 9.91837C15.9039 10.2046 15.9849 10.8668 15.588 11.2603L10.4954 16.3088C9.90529 16.8938 9.15752 17.2941 8.34351 17.461L3.88965 18.3738L2.45572 19.788C2.11945 20.1197 1.57798 20.116 1.24632 19.7797C0.91466 19.4434 0.918397 18.9019 1.25467 18.5703L2.79008 17.0559Z" />
|
||||||
|
</svg>
|
||||||
|
Author
|
||||||
|
</div>
|
||||||
<span class="entry__author breakable"></span>
|
<span class="entry__author breakable"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="entry__changes"></div>
|
<div class="entry__changes"></div>
|
||||||
@ -412,29 +450,12 @@
|
|||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stack {
|
|
||||||
constructor() {
|
|
||||||
this.items = [];
|
|
||||||
}
|
|
||||||
push(element) {
|
|
||||||
this.items.push(element);
|
|
||||||
}
|
|
||||||
pop() {
|
|
||||||
if (this.items.length == 0)
|
|
||||||
return "Underflow";
|
|
||||||
return this.items.pop();
|
|
||||||
}
|
|
||||||
peek() {
|
|
||||||
return this.items[this.items.length - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let popupStack = new Stack()
|
|
||||||
let zIndex = 10
|
let zIndex = 10
|
||||||
// function required for popups or modals to appear
|
// function required for popups or modals to appear
|
||||||
function showPopup(popupId, pinned) {
|
function showPopup(popupId, pinned) {
|
||||||
zIndex++
|
zIndex++
|
||||||
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
||||||
popupStack = getRef(popupId).show({ pinned, popupStack })
|
getRef(popupId).show({ pinned })
|
||||||
return getRef(popupId);
|
return getRef(popupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,6 +466,29 @@
|
|||||||
popupStack.peek().popup.hide()
|
popupStack.peek().popup.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('popupopened', e => {
|
||||||
|
switch (e.target.id) {
|
||||||
|
case 'edit_sections_popup':
|
||||||
|
renderSectionList()
|
||||||
|
break;
|
||||||
|
case 'article_list_popup':
|
||||||
|
renderArticleList()
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.addEventListener('popupclosed', e => {
|
||||||
|
zIndex--
|
||||||
|
switch (e.target.id) {
|
||||||
|
case 'edit_sections_popup':
|
||||||
|
getRef('section_list_container').innerHTML = ''
|
||||||
|
break;
|
||||||
|
case 'article_list_popup':
|
||||||
|
getRef('article_list').innerHTML = ``
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// displays a popup for asking permission. Use this instead of JS confirm
|
// displays a popup for asking permission. Use this instead of JS confirm
|
||||||
const getConfirmation = (title, options = {}) => {
|
const getConfirmation = (title, options = {}) => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
@ -734,35 +778,62 @@
|
|||||||
</script>
|
</script>
|
||||||
<script id="cc">
|
<script id="cc">
|
||||||
const cc = {
|
const cc = {
|
||||||
createNewArticle(title) {
|
createNewArticle() {
|
||||||
const uid = floCrypto.randString(16, true)
|
if (isSubAdmin) {
|
||||||
floGlobals.appObjects.cc['defaultArticle'] = uid
|
const title = getRef('get_article_title').value.trim()
|
||||||
floGlobals.appObjects.cc['articleList'][uid] = {
|
const setDefault = getRef('set_default_checkbox').checked
|
||||||
title,
|
const sectionTitles = getRef('get_section_titles').value.trim()
|
||||||
timestamp: Date.now()
|
let sections = []
|
||||||
}
|
if (sectionTitles !== '') {
|
||||||
floCloudAPI.updateObjectData('cc')
|
sections = sectionTitles.split(',').map(title => {
|
||||||
.then((res) => {
|
return {
|
||||||
console.log('created article entry', res)
|
id: floCrypto.randString(16, true),
|
||||||
})
|
title: title.trim(),
|
||||||
.catch(err => console.error(err))
|
}
|
||||||
floGlobals.appObjects[uid] = {
|
})
|
||||||
public: true,
|
|
||||||
editors: [],
|
|
||||||
sections: [{
|
|
||||||
id: floCrypto.randString(16, true),
|
|
||||||
title: 'Introduction',
|
|
||||||
}, {
|
|
||||||
id: floCrypto.randString(16, true),
|
|
||||||
title: 'core',
|
|
||||||
}
|
}
|
||||||
]
|
const uid = floCrypto.randString(16, true)
|
||||||
|
if (setDefault)
|
||||||
|
floGlobals.appObjects.cc['defaultArticle'] = uid
|
||||||
|
floGlobals.appObjects.cc['articleList'][uid] = {
|
||||||
|
title,
|
||||||
|
timestamp: Date.now()
|
||||||
|
}
|
||||||
|
floGlobals.appObjects[uid] = {
|
||||||
|
public: true,
|
||||||
|
editors: [],
|
||||||
|
sections
|
||||||
|
}
|
||||||
|
Promise.all([
|
||||||
|
floCloudAPI.updateObjectData('cc'),
|
||||||
|
floCloudAPI.resetObjectData(uid)
|
||||||
|
])
|
||||||
|
.then((res) => {
|
||||||
|
hidePopup()
|
||||||
|
notify('created article', 'success')
|
||||||
|
window.location.hash = `#/home?articleID=${uid}`
|
||||||
|
})
|
||||||
|
.catch(err => console.error(err))
|
||||||
|
} else {
|
||||||
|
notify('This action requires sub-admin privileges', 'error')
|
||||||
}
|
}
|
||||||
floCloudAPI.resetObjectData(uid)
|
}
|
||||||
.then((res) => {
|
}
|
||||||
console.log('created article', res)
|
|
||||||
})
|
function setDefaultArticle() {
|
||||||
.catch(err => console.error(err))
|
if (isSubAdmin) {
|
||||||
|
getConfirmation('Set as default article?').then(res => {
|
||||||
|
if (res) {
|
||||||
|
floGlobals.appObjects.cc['defaultArticle'] = currentArticle.id
|
||||||
|
floCloudAPI.updateObjectData('cc')
|
||||||
|
.then((res) => {
|
||||||
|
notify('Set current article as default', 'success')
|
||||||
|
})
|
||||||
|
.catch(err => console.error(err))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notify('This action requires sub-admin privileges', 'error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +908,7 @@
|
|||||||
currentArticle.uniqueEntries[entry.origin] = { iterations: [{ ...entry, timestamp }] }
|
currentArticle.uniqueEntries[entry.origin] = { iterations: [{ ...entry, timestamp }] }
|
||||||
parentSection.firstElementChild.after(render.contentCard(entry.origin))
|
parentSection.firstElementChild.after(render.contentCard(entry.origin))
|
||||||
} else {
|
} else {
|
||||||
currentArticle.uniqueEntries[entry.origin].iterations.push({ ...entry, timestamp })
|
currentArticle.uniqueEntries[entry.origin].iterations.push({ ...entry, timestamp, editor: myFloID })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -930,7 +1001,6 @@
|
|||||||
const { title } = floGlobals.appObjects.cc.articleList[id]
|
const { title } = floGlobals.appObjects.cc.articleList[id]
|
||||||
const { writer, sections } = currentArticle
|
const { writer, sections } = currentArticle
|
||||||
const frag = document.createDocumentFragment()
|
const frag = document.createDocumentFragment()
|
||||||
const isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
|
||||||
let index = 0
|
let index = 0
|
||||||
for (const sectionID in sections) {
|
for (const sectionID in sections) {
|
||||||
frag.append(render.section(sectionID, sections[sectionID], index))
|
frag.append(render.section(sectionID, sections[sectionID], index))
|
||||||
@ -938,8 +1008,6 @@
|
|||||||
}
|
}
|
||||||
if (!isSubAdmin) {
|
if (!isSubAdmin) {
|
||||||
getRef('current_article_title').setAttribute('disabled', '')
|
getRef('current_article_title').setAttribute('disabled', '')
|
||||||
} else {
|
|
||||||
renderSectionList()
|
|
||||||
}
|
}
|
||||||
getRef('current_article_title').value = title
|
getRef('current_article_title').value = title
|
||||||
getRef('article_wrapper').innerHTML = ''
|
getRef('article_wrapper').innerHTML = ''
|
||||||
@ -953,22 +1021,30 @@
|
|||||||
className: 'article-link flex interact'
|
className: 'article-link flex interact'
|
||||||
})
|
})
|
||||||
if (isDefaultArticle) {
|
if (isDefaultArticle) {
|
||||||
link.append(createElement('span', {
|
link.classList.add('default-article')
|
||||||
className: 'default-article',
|
|
||||||
textContent: 'Actively written'
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
return link
|
return link
|
||||||
},
|
},
|
||||||
contentCard(id, version = 0) {
|
contentCard(id, version = 0) {
|
||||||
const clone = getRef('content_card_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('content_card_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.dataset.uid = id
|
clone.dataset.uid = id
|
||||||
if (!floGlobals.subAdmins.includes(myFloID)) {
|
if (!isSubAdmin) {
|
||||||
clone.querySelector('.content__area').setAttribute('contentEditable', true)
|
clone.querySelector('.content__area').setAttribute('contentEditable', true)
|
||||||
}
|
}
|
||||||
const { data, contributors } = getIterationDetails(id)
|
const { data, contributors } = getIterationDetails(id)
|
||||||
|
console.log(contributors)
|
||||||
clone.querySelector('.content__area').innerHTML = DOMPurify.sanitize(data)
|
clone.querySelector('.content__area').innerHTML = DOMPurify.sanitize(data)
|
||||||
clone.querySelector('.content__editor').textContent = `by ${contributors}`;
|
if (contributors.size === 1) {
|
||||||
|
const [contributor] = contributors
|
||||||
|
clone.querySelector('.content__editor').textContent = `by ${contributor}`;
|
||||||
|
} else {
|
||||||
|
clone.querySelector('.content__editor').innerHTML = `
|
||||||
|
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.6243 7.99154C13.9395 8.14279 13.4165 8.69672 13.3047 9.38904C13.2248 9.88365 13.3664 10.3773 13.6735 10.7498L9.29125 15.0941C8.93718 15.4451 8.48852 15.6853 8.00011 15.7854L6.12418 16.1699L9.19811 13.1381C9.53438 12.8064 9.53812 12.265 9.20646 11.9287C8.8748 11.5924 8.33333 11.5887 7.99706 11.9203L4.97835 14.8977L5.47976 12.451C5.50451 12.3303 5.55656 12.2168 5.63191 12.1192L6.49083 11.0073C9.58386 7.00317 14.32 4.72705 19.2553 4.71054L16.3569 7.60884L14.6243 7.99154ZM2.79008 17.0559L3.8042 12.1076C3.88132 11.7313 4.0435 11.3776 4.27833 11.0736L5.13724 9.96172C8.89964 5.09105 14.861 2.53305 20.8954 3.07051C21.5971 3.133 22.2997 3.23735 23 3.38478L17.2133 9.1713L14.9932 9.66167L15.4238 9.91837C15.9039 10.2046 15.9849 10.8668 15.588 11.2603L10.4954 16.3088C9.90529 16.8938 9.15752 17.2941 8.34351 17.461L3.88965 18.3738L2.45572 19.788C2.11945 20.1197 1.57798 20.116 1.24632 19.7797C0.91466 19.4434 0.918397 18.9019 1.25467 18.5703L2.79008 17.0559Z"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
// clone.querySelector('.content__score').textContent = score;
|
// clone.querySelector('.content__score').textContent = score;
|
||||||
return clone
|
return clone
|
||||||
},
|
},
|
||||||
@ -1008,7 +1084,7 @@
|
|||||||
const frag = document.createDocumentFragment()
|
const frag = document.createDocumentFragment()
|
||||||
section.children[0].dataset.index = index
|
section.children[0].dataset.index = index
|
||||||
section.children[1].dataset.sectionId = sectionID
|
section.children[1].dataset.sectionId = sectionID
|
||||||
if (floGlobals.subAdmins.includes(myFloID)) {
|
if (isSubAdmin) {
|
||||||
section.querySelector('.content-card--empty').remove()
|
section.querySelector('.content-card--empty').remove()
|
||||||
} else {
|
} else {
|
||||||
section.querySelector('.heading').setAttribute('disabled', '')
|
section.querySelector('.heading').setAttribute('disabled', '')
|
||||||
@ -1066,6 +1142,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function renderSectionList() {
|
function renderSectionList() {
|
||||||
|
if (!isSubAdmin) return
|
||||||
const frag = document.createDocumentFragment()
|
const frag = document.createDocumentFragment()
|
||||||
floGlobals.appObjects[currentArticle.id].sections.forEach(section => {
|
floGlobals.appObjects[currentArticle.id].sections.forEach(section => {
|
||||||
frag.append(render.sectionCard(section))
|
frag.append(render.sectionCard(section))
|
||||||
@ -1088,7 +1165,49 @@
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
getRef('section_list_container').append(emptySection)
|
getRef('section_list_container').append(emptySection)
|
||||||
|
emptySection.querySelector('input').focus()
|
||||||
}
|
}
|
||||||
|
getRef('section_list_container').addEventListener('click', e => {
|
||||||
|
if (e.target.closest('.remove')) {
|
||||||
|
e.target.closest('.section-card').remove()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function saveSectionEdit() {
|
||||||
|
const newSections = []
|
||||||
|
getRef('section_list_container').querySelectorAll('.section-card--new').forEach(section => {
|
||||||
|
const title = section.querySelector('input').value.trim()
|
||||||
|
if (title !== '')
|
||||||
|
newSections.push({
|
||||||
|
id: floCrypto.randString(16, true),
|
||||||
|
title
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (newSections.length) {
|
||||||
|
newSections.forEach(elem => {
|
||||||
|
floGlobals.appObjects[currentArticle.id].sections.push(elem)
|
||||||
|
})
|
||||||
|
floCloudAPI.updateObjectData(currentArticle.id)
|
||||||
|
.then((res) => {
|
||||||
|
const frag = document.createDocumentFragment()
|
||||||
|
const currentSectionCount = getRef('section_list_container').querySelectorAll('.section-card:not(.section-card--new)').length
|
||||||
|
let index = currentSectionCount
|
||||||
|
newSections.forEach(elem => {
|
||||||
|
const { title, id } = elem
|
||||||
|
currentArticle.sections[id] = { title, uniqueEntries: [] }
|
||||||
|
frag.append(render.section(id, currentArticle.sections[id], index))
|
||||||
|
index += 1
|
||||||
|
})
|
||||||
|
getRef('article_wrapper').append(frag)
|
||||||
|
notify('Sections updated', 'success')
|
||||||
|
hidePopup()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
notify(err, 'error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getArticleList() {
|
function getArticleList() {
|
||||||
const articleList = floGlobals.appObjects.cc.articleList
|
const articleList = floGlobals.appObjects.cc.articleList
|
||||||
@ -1114,7 +1233,7 @@
|
|||||||
const searchKey = e.target.value.trim()
|
const searchKey = e.target.value.trim()
|
||||||
const options = {
|
const options = {
|
||||||
keys: ['title'],
|
keys: ['title'],
|
||||||
threshold: 0
|
threshold: 0.3
|
||||||
}
|
}
|
||||||
const fuse = new Fuse(getArticleList(), options)
|
const fuse = new Fuse(getArticleList(), options)
|
||||||
renderArticleList(searchKey === '' ? undefined : fuse.search(searchKey).map(v => v.item))
|
renderArticleList(searchKey === '' ? undefined : fuse.search(searchKey).map(v => v.item))
|
||||||
@ -1234,6 +1353,7 @@
|
|||||||
},
|
},
|
||||||
200)
|
200)
|
||||||
|
|
||||||
|
|
||||||
const replaceBetween = (origin, startIndex, endIndex, insertion) =>
|
const replaceBetween = (origin, startIndex, endIndex, insertion) =>
|
||||||
`${origin.substring(0, startIndex)}${insertion}${origin.substring(endIndex)}`;
|
`${origin.substring(0, startIndex)}${insertion}${origin.substring(endIndex)}`;
|
||||||
const make = {
|
const make = {
|
||||||
@ -1357,6 +1477,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script id="onLoadStartUp">
|
<script id="onLoadStartUp">
|
||||||
|
let isSubAdmin = false
|
||||||
function onLoadStartUp() {
|
function onLoadStartUp() {
|
||||||
|
|
||||||
//floDapps.addStartUpFunction('Sample', Promised Function)
|
//floDapps.addStartUpFunction('Sample', Promised Function)
|
||||||
@ -1364,11 +1485,11 @@
|
|||||||
//floDapps.setCustomPrivKeyInput( () => { FUNCTION BODY *must resolve private key* } )
|
//floDapps.setCustomPrivKeyInput( () => { FUNCTION BODY *must resolve private key* } )
|
||||||
|
|
||||||
floDapps.launchStartUp().then(async result => {
|
floDapps.launchStartUp().then(async result => {
|
||||||
|
isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
floCloudAPI.requestObjectData('cc'),
|
floCloudAPI.requestObjectData('cc'),
|
||||||
])
|
])
|
||||||
showPage(window.location.hash)
|
showPage(window.location.hash)
|
||||||
renderArticleList()
|
|
||||||
|
|
||||||
console.log(result)
|
console.log(result)
|
||||||
// alert(`Welcome FLO_ID: ${ myFloID }`)
|
// alert(`Welcome FLO_ID: ${ myFloID }`)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user