UX improvements
This commit is contained in:
parent
b61adfc188
commit
47dc6de154
224
components.js
224
components.js
@ -2387,6 +2387,7 @@ smSelect.innerHTML = `
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.selection:focus{
|
||||
-webkit-box-shadow: 0 0 0 0.1rem var(--accent-color);
|
||||
@ -2417,7 +2418,7 @@ smSelect.innerHTML = `
|
||||
background: rgba(var(--background-color), 1);
|
||||
border: solid 1px rgba(var(--text-color), 0.2);
|
||||
border-radius: var(--border-radius, 0.5rem);
|
||||
z-index: 2;
|
||||
z-index: 1;
|
||||
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
||||
box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
|
||||
}
|
||||
@ -4290,4 +4291,223 @@ customElements.define('sm-textarea',
|
||||
this.checkInput()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const tagsInput = document.createElement('template')
|
||||
tagsInput.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
--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);
|
||||
}
|
||||
.hide{
|
||||
display: none !important;
|
||||
}
|
||||
.tags-wrapper{
|
||||
position: relative;
|
||||
display: flex;
|
||||
cursor: text;
|
||||
flex-wrap: wrap;
|
||||
justify-items: flex-start;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.5rem 0 0.5rem;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--background);
|
||||
}
|
||||
.tags-wrapper:focus-within{
|
||||
box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important;
|
||||
}
|
||||
|
||||
.tag {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
border-radius: 0.3rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
margin: 0 0.5rem 0.5rem 0;
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
}
|
||||
|
||||
.icon {
|
||||
height: 1.2rem;
|
||||
width: 1.2rem;
|
||||
margin-left: 0.3rem;
|
||||
fill: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
|
||||
input,
|
||||
input:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
input {
|
||||
display: inline-flex;
|
||||
width: auto;
|
||||
color: inherit;
|
||||
max-width: inherit;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
padding: 0.4rem 0.5rem;
|
||||
margin: 0 0.5rem 0.5rem 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
.placeholder{
|
||||
position: absolute;
|
||||
padding: 0 0.5rem;
|
||||
top: 50%;
|
||||
font-weight: 500;
|
||||
transform: translateY(-50%);
|
||||
color: rgba(var(--text-color), 0.6);
|
||||
}
|
||||
</style>
|
||||
<div class="tags-wrapper">
|
||||
<input type="text" size="3"/>
|
||||
<p class="placeholder"></p>
|
||||
</div>
|
||||
`
|
||||
|
||||
customElements.define('tags-input', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({
|
||||
mode: 'open'
|
||||
}).append(tagsInput.content.cloneNode(true))
|
||||
|
||||
this.input = this.shadowRoot.querySelector('input')
|
||||
this.tagsWrapper = this.shadowRoot.querySelector('.tags-wrapper')
|
||||
this.placeholder = this.shadowRoot.querySelector('.placeholder')
|
||||
this.reflectedAttributes = ['placeholder', 'limit']
|
||||
this.limit = undefined
|
||||
this.tags = new Set()
|
||||
|
||||
this.reset = this.reset.bind(this)
|
||||
this.handleInput = this.handleInput.bind(this)
|
||||
this.handleKeydown = this.handleKeydown.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.removeTag = this.removeTag.bind(this)
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['placeholder', 'limit']
|
||||
}
|
||||
get value() {
|
||||
return [...this.tags].join()
|
||||
}
|
||||
get isValid() {
|
||||
return this.tags.size
|
||||
}
|
||||
focusIn() {
|
||||
this.input.focus()
|
||||
}
|
||||
reset() {
|
||||
this.input.value = ''
|
||||
this.tags.clear()
|
||||
while (this.input.previousElementSibling) {
|
||||
this.input.previousElementSibling.remove()
|
||||
}
|
||||
}
|
||||
handleInput(e) {
|
||||
const inputValueLength = e.target.value.trim().length
|
||||
e.target.setAttribute('size', inputValueLength ? inputValueLength : '3')
|
||||
if (inputValueLength) {
|
||||
this.placeholder.classList.add('hide')
|
||||
}
|
||||
else if (!inputValueLength && !this.tags.size) {
|
||||
this.placeholder.classList.remove('hide')
|
||||
}
|
||||
}
|
||||
handleKeydown(e) {
|
||||
if (e.key === ',' || e.key === '/') {
|
||||
e.preventDefault()
|
||||
}
|
||||
if (e.target.value.trim() !== '') {
|
||||
if (e.key === 'Enter' || e.key === ',' || e.key === '/' || e.code === 'Space') {
|
||||
const tagValue = e.target.value.trim()
|
||||
if (this.tags.has(tagValue)) {
|
||||
this.tagsWrapper.querySelector(`[data-value="${tagValue}"]`).animate([
|
||||
{
|
||||
backgroundColor: 'initial'
|
||||
},
|
||||
{
|
||||
backgroundColor: 'var(--accent-color)'
|
||||
},
|
||||
{
|
||||
backgroundColor: 'initial'
|
||||
},
|
||||
], {
|
||||
duration: 300,
|
||||
easing: 'ease'
|
||||
})
|
||||
}
|
||||
else {
|
||||
const tag = document.createElement('span')
|
||||
tag.dataset.value = tagValue
|
||||
tag.className = 'tag'
|
||||
tag.innerHTML = `
|
||||
<span class="tag-text">${tagValue}</span>
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
|
||||
`
|
||||
this.input.before(tag)
|
||||
this.tags.add(tagValue)
|
||||
}
|
||||
e.target.value = ''
|
||||
e.target.setAttribute('size', '3')
|
||||
if (this.limit && this.limit < this.tags.size + 1) {
|
||||
this.input.readOnly = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (e.key === 'Backspace' && this.input.previousElementSibling) {
|
||||
this.removeTag(this.input.previousElementSibling)
|
||||
}
|
||||
if (this.limit && this.limit > this.tags.size) {
|
||||
this.input.readOnly = false
|
||||
}
|
||||
}
|
||||
}
|
||||
handleClick(e) {
|
||||
if (e.target.closest('.tag')) {
|
||||
this.removeTag(e.target.closest('.tag'))
|
||||
}
|
||||
else {
|
||||
this.input.focus()
|
||||
}
|
||||
}
|
||||
removeTag(tag) {
|
||||
this.tags.delete(tag.dataset.value)
|
||||
tag.remove()
|
||||
if (!this.tags.size) {
|
||||
this.placeholder.classList.remove('hide')
|
||||
}
|
||||
}
|
||||
connectedCallback() {
|
||||
this.input.addEventListener('input', this.handleInput)
|
||||
this.input.addEventListener('keydown', this.handleKeydown)
|
||||
this.tagsWrapper.addEventListener('click', this.handleClick)
|
||||
}
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (name === 'placeholder') {
|
||||
this.placeholder.textContent = newValue
|
||||
}
|
||||
if (name === 'limit') {
|
||||
this.limit = parseInt(newValue)
|
||||
}
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.input.removeEventListener('input', this.handleInput)
|
||||
this.input.removeEventListener('keydown', this.handleKeydown)
|
||||
this.tagsWrapper.removeEventListener('click', this.handleClick)
|
||||
}
|
||||
})
|
||||
91
css/main.css
91
css/main.css
@ -136,7 +136,8 @@ a:any-link:focus-visible {
|
||||
}
|
||||
|
||||
sm-input,
|
||||
sm-textarea {
|
||||
sm-textarea,
|
||||
tags-input {
|
||||
font-size: 0.9rem;
|
||||
--border-radius: 0.3rem;
|
||||
}
|
||||
@ -529,6 +530,8 @@ menu-option {
|
||||
}
|
||||
|
||||
#filter_panel {
|
||||
position: sticky;
|
||||
top: 6.5rem;
|
||||
z-index: 1;
|
||||
padding: 0.5rem 1.5rem;
|
||||
grid-column: 1/-1;
|
||||
@ -661,9 +664,6 @@ menu-option {
|
||||
|
||||
.heading {
|
||||
font-weight: 700;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.heading::before {
|
||||
content: "";
|
||||
@ -673,17 +673,12 @@ menu-option {
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
.heading button {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.article-section {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
overflow-x: auto;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
-ms-scroll-snap-type: x mandatory;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
.article-section:not(:last-of-type) {
|
||||
margin-bottom: 1.5rem;
|
||||
@ -693,10 +688,6 @@ menu-option {
|
||||
}
|
||||
|
||||
.content-card {
|
||||
scroll-snap-align: start;
|
||||
width: min(46ch, 100%);
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--foreground-color);
|
||||
-webkit-box-shadow: 0 0 0 1px rgba(var(--text-color), 0.16) inset;
|
||||
@ -818,32 +809,17 @@ menu-option {
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
background-color: var(--foreground-color);
|
||||
border: solid thin rgba(var(--text-color), 0.2);
|
||||
border-radius: 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
-webkit-box-shadow: 0.3rem 0.5rem 0 0.1rem rgba(var(--text-color), 0.8);
|
||||
box-shadow: 0.1rem 0.2rem 0 0.1rem rgba(var(--text-color), 0.8);
|
||||
overflow: hidden;
|
||||
justify-self: center;
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
.quote-template::before {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 100%;
|
||||
width: 0.3rem;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
.quote-template blockquote {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.quote-template figcaption {
|
||||
margin-top: 0.5rem;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
font-size: 0.8rem;
|
||||
padding-left: 1.3rem figcaption;
|
||||
padding-left-margin-top: 0.5rem;
|
||||
padding-left-color: rgba(var(--text-color), 0.8);
|
||||
padding-left-font-size: 0.8rem;
|
||||
padding-left-margin-left: auto;
|
||||
}
|
||||
|
||||
#version_history_panel {
|
||||
@ -977,14 +953,18 @@ menu-option {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
#publish_article_popup {
|
||||
--min-height: 50vh;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 40rem) {
|
||||
#article_name_wrapper,
|
||||
#selected_content_options {
|
||||
grid-row: 2/3;
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
#article_name_wrapper sm-menu,
|
||||
#selected_content_options sm-menu {
|
||||
#article_name_wrapper #filter_button,
|
||||
#selected_content_options #filter_button {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@ -994,6 +974,24 @@ menu-option {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.article-section {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-scroll-snap-type: x mandatory;
|
||||
scroll-snap-type: x mandatory;
|
||||
overflow-x: auto;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
scroll-snap-align: start;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
width: min(45ch, calc(100% - 2rem));
|
||||
}
|
||||
|
||||
.hide-on-mobile {
|
||||
display: none;
|
||||
}
|
||||
@ -1041,6 +1039,10 @@ menu-option {
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
}
|
||||
|
||||
#filter_panel {
|
||||
top: 4.2rem;
|
||||
}
|
||||
|
||||
#main_page.active-sidebar {
|
||||
-ms-scroll-chaining: none;
|
||||
overscroll-behavior: contain;
|
||||
@ -1063,6 +1065,11 @@ menu-option {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.article-section {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(40ch, 1fr));
|
||||
}
|
||||
|
||||
#article_list_popup .popup__header {
|
||||
grid-template-columns: auto 1fr auto;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -116,7 +116,8 @@ a:any-link:focus-visible {
|
||||
}
|
||||
|
||||
sm-input,
|
||||
sm-textarea {
|
||||
sm-textarea,
|
||||
tags-input {
|
||||
font-size: 0.9rem;
|
||||
--border-radius: 0.3rem;
|
||||
}
|
||||
@ -460,6 +461,8 @@ menu-option {
|
||||
}
|
||||
|
||||
#filter_panel {
|
||||
position: sticky;
|
||||
top: 6.5rem;
|
||||
z-index: 1;
|
||||
padding: 0.5rem 1.5rem;
|
||||
grid-column: 1/-1;
|
||||
@ -576,7 +579,6 @@ menu-option {
|
||||
|
||||
.heading {
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
&::before {
|
||||
content: "";
|
||||
width: 0.3rem;
|
||||
@ -585,14 +587,13 @@ menu-option {
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
button{
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.article-section {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
overflow-x: auto;
|
||||
flex-shrink: 0;
|
||||
scroll-snap-type: x mandatory;
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
@ -601,9 +602,6 @@ menu-option {
|
||||
}
|
||||
}
|
||||
.content-card {
|
||||
scroll-snap-align: start;
|
||||
width: min(46ch, 100%);
|
||||
flex-shrink: 0;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--foreground-color);
|
||||
box-shadow: 0 0 0 1px rgba(var(--text-color), 0.16) inset;
|
||||
@ -700,32 +698,22 @@ menu-option {
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
background-color: var(--foreground-color);
|
||||
border: solid thin rgba(var(--text-color), 0.2);
|
||||
border-radius: 0.5rem;
|
||||
border-radius: .2rem;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
-webkit-box-shadow: .3rem .5rem 0 .1rem rgba(var(--text-color), 0.8);
|
||||
box-shadow: .1rem .2rem 0 .1rem rgba(var(--text-color), 0.8);
|
||||
overflow: hidden;
|
||||
justify-self: center;
|
||||
padding-left: 1.3rem;
|
||||
&::before {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 100%;
|
||||
width: 0.3rem;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
blockquote {
|
||||
display: flex;
|
||||
}
|
||||
.quote {
|
||||
}
|
||||
padding-left: 1.3rem
|
||||
figcaption {
|
||||
margin-top: 0.5rem;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
font-size: 0.8rem;
|
||||
margin-top: .5rem;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
font-size: .8rem;
|
||||
margin-left: auto
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#version_history_panel {
|
||||
border-radius: 0.5rem;
|
||||
width: min(24rem, 100%);
|
||||
@ -849,18 +837,33 @@ menu-option {
|
||||
}
|
||||
}
|
||||
|
||||
#publish_article_popup{
|
||||
--min-height: 50vh;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 40rem) {
|
||||
#article_name_wrapper,
|
||||
#selected_content_options {
|
||||
grid-row: 2/3;
|
||||
grid-column: 1/-1;
|
||||
sm-menu {
|
||||
#filter_button {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
#article_name_wrapper{
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.article-section{
|
||||
display: flex;
|
||||
scroll-snap-type: x mandatory;
|
||||
overflow-x: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.content-card{
|
||||
scroll-snap-align: start;
|
||||
flex-shrink: 0;
|
||||
width: min(45ch, calc(100% - 2rem));
|
||||
}
|
||||
.hide-on-mobile {
|
||||
display: none;
|
||||
}
|
||||
@ -901,6 +904,9 @@ menu-option {
|
||||
padding: 1rem 1.5rem;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
}
|
||||
#filter_panel {
|
||||
top: 4.2rem;
|
||||
}
|
||||
#main_page {
|
||||
&.active-sidebar {
|
||||
overscroll-behavior: contain;
|
||||
@ -921,6 +927,10 @@ menu-option {
|
||||
#article_wrapper {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
.article-section{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(40ch, 1fr));
|
||||
}
|
||||
#article_list_popup {
|
||||
.popup__header {
|
||||
grid-template-columns: auto 1fr auto;
|
||||
|
||||
113
index.html
113
index.html
@ -83,7 +83,7 @@
|
||||
</svg>
|
||||
</button>
|
||||
<text-field id="current_article_title"></text-field>
|
||||
<button class="icon-only" title="Show filters" onclick="toggleFilterPanel()">
|
||||
<button id="filter_button" class="icon-only" title="Show filters" onclick="toggleFilterPanel()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
@ -389,6 +389,38 @@
|
||||
<span class="label">Copy link</span>
|
||||
<sm-copy id="shared_url" clip-text></sm-copy>
|
||||
</sm-popup>
|
||||
<sm-popup id="publish_article_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
<div class="flex align-center">
|
||||
<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"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h3>Publish article</h3>
|
||||
</div>
|
||||
</header>
|
||||
<sm-form class="grid gap-1-5">
|
||||
<div class="grid gap-0-5">
|
||||
<h5>Select category</h5>
|
||||
<sm-select id="published_article_category">
|
||||
<sm-option value="entertainment">Entertainment</sm-option>
|
||||
<sm-option value="politics">Politics</sm-option>
|
||||
<sm-option value="science">Science</sm-option>
|
||||
<sm-option value="sports">Sports</sm-option>
|
||||
<sm-option value="tech">Tech</sm-option>
|
||||
</sm-select>
|
||||
</div>
|
||||
<div class="grid gap-0-5">
|
||||
<h5>Add tags</h5>
|
||||
<tags-input id="article_tags" limit="10" required></tags-input>
|
||||
</div>
|
||||
<sm-button variant="primary" onclick="publishArticle()">Request publishing</sm-button>
|
||||
</sm-form>
|
||||
</sm-popup>
|
||||
<template id="contributor_template">
|
||||
<div class="contributor grid">
|
||||
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@ -400,7 +432,9 @@
|
||||
</div>
|
||||
</template>
|
||||
<template id="section_template">
|
||||
<text-field class="heading"></text-field>
|
||||
<div class="heading flex align-center">
|
||||
<text-field></text-field>
|
||||
</div>
|
||||
<section class="article-section">
|
||||
<div class="content-card content-card--empty">
|
||||
<div class="content__area" data-type="origin" placeholder="Write something new or edit existing content"
|
||||
@ -448,16 +482,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="quote_template">
|
||||
<figure class="quote-template grid gap-0-5" contenteditable="false">
|
||||
<blockquote class="flex">
|
||||
<p class="quote" contenteditable="true">Words can be like X-rays, if you use them properly—they’ll go
|
||||
through anything. You read and you’re pierced.</p>
|
||||
</blockquote>
|
||||
<figcaption class="flex"><span class="by" contenteditable="true">Aldous Huxley</span><cite class="citation"
|
||||
contenteditable="true">Brave New World</cite></figcaption>
|
||||
</figure>
|
||||
</template>
|
||||
<template id="history_entry_template">
|
||||
<li class="history-entry grid gap-1">
|
||||
<div class="flex align-center space-between">
|
||||
@ -1166,7 +1190,7 @@
|
||||
const contributor = getRef('contributor_template').content.cloneNode(true)
|
||||
contributor.querySelector('.contributor__id').textContent = floID
|
||||
contributor.querySelector('.contributor__time').textContent = `Last edited: ${getFormattedTime(contributors[floID])}`
|
||||
frag.append(contributor)
|
||||
frag.prepend(contributor)
|
||||
}
|
||||
getRef('contributor_list').append(frag)
|
||||
showPopup('contributors_popup')
|
||||
@ -1285,6 +1309,12 @@
|
||||
window.location.hash = `#/preview?articleID=${currentArticle.id}`
|
||||
}
|
||||
|
||||
function getReadingTime(content) {
|
||||
const wpm = 225;
|
||||
const words = content.trim().split(/\s+/).length;
|
||||
return Math.ceil(words / wpm);
|
||||
}
|
||||
|
||||
|
||||
function downloadHTML(string, options = {}) {
|
||||
const { title } = options
|
||||
@ -1318,6 +1348,8 @@
|
||||
bodyTemplate.querySelector('#exported_title').textContent = articleTitle
|
||||
bodyTemplate.querySelector('#exported_time').textContent = `Exported on ${getFormattedTime(Date.now())}`
|
||||
bodyTemplate.querySelector('#export_body').innerHTML = getCleanExportContent()
|
||||
const readingTime = getReadingTime(bodyTemplate.querySelector('#export_body').textContent)
|
||||
bodyTemplate.querySelector('#reading_time').textContent = `${readingTime} min read`
|
||||
let bodyAttributes = ''
|
||||
let extraScripts = ''
|
||||
if (isSubAdmin) {
|
||||
@ -1389,6 +1421,10 @@
|
||||
|
||||
function publishArticle() {
|
||||
if (isSubAdmin) {
|
||||
const category = getRef('published_article_category').value
|
||||
const tags = getRef('article_tags').value
|
||||
console.log(category, tags)
|
||||
return
|
||||
getConfirmation('Request publishing?', {
|
||||
message: 'Send this article as publishing candidate on RanchiMall TImes',
|
||||
confirmText: 'Request'
|
||||
@ -1399,6 +1435,8 @@
|
||||
articleID: pagesData.params.articleID,
|
||||
title: floGlobals.appObjects.cc.articleList[currentArticle.id].title,
|
||||
content: getCleanExportContent(),
|
||||
category,
|
||||
tags,
|
||||
}, 'publishing_requests', {
|
||||
application: 'Test_RM_Times',
|
||||
receiverID: 'FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf'
|
||||
@ -1506,6 +1544,7 @@
|
||||
</script>
|
||||
<script>
|
||||
let currentArticle = {}
|
||||
|
||||
const render = {
|
||||
article(id) {
|
||||
currentArticle.id = id
|
||||
@ -1551,7 +1590,6 @@
|
||||
noOfContributors++
|
||||
if (noOfContributors === 1)
|
||||
firstContributor = contributor
|
||||
if (noOfContributors === 2) break
|
||||
}
|
||||
if (noOfContributors === 1) {
|
||||
clone.querySelector('.content__author').textContent = firstContributor
|
||||
@ -1604,14 +1642,20 @@
|
||||
if (isSubAdmin) {
|
||||
section.querySelector('.content-card--empty').remove()
|
||||
} else {
|
||||
section.querySelector('.heading').setAttribute('disabled', '')
|
||||
section.querySelector('text-field').setAttribute('disabled', '')
|
||||
}
|
||||
section.querySelector('.heading').setAttribute('value', title)
|
||||
currentArticle.sections[sectionID].uniqueEntries.forEach(entry => {
|
||||
section.querySelector('text-field').setAttribute('value', title)
|
||||
currentArticle.sections[sectionID].uniqueEntries.slice(0, maxCardsPerSection).forEach(entry => {
|
||||
const contentCard = render.contentCard(entry)
|
||||
if (contentCard)
|
||||
frag.append(contentCard)
|
||||
})
|
||||
if (currentArticle.sections[sectionID].uniqueEntries.length > maxCardsPerSection) {
|
||||
section.querySelector('.heading').append(createElement('button', {
|
||||
className: 'button hide-on-mobile',
|
||||
textContent: `See ${currentArticle.sections[sectionID].uniqueEntries.length - maxCardsPerSection} more`
|
||||
}))
|
||||
}
|
||||
section.querySelector('.article-section').append(frag)
|
||||
return section
|
||||
},
|
||||
@ -1722,7 +1766,9 @@
|
||||
emptyCard = section.firstElementChild.cloneNode(true)
|
||||
section.innerHTML = ''
|
||||
const frag = document.createDocumentFragment()
|
||||
currentArticle.sections[sectionID].uniqueEntries.forEach((entry, index) => frag.append(allContentCards[entry]))
|
||||
currentArticle.sections[sectionID].uniqueEntries.slice(0, maxCardsPerSection).forEach((entry, index) => {
|
||||
frag.append(allContentCards[entry] || render.contentCard(entry))
|
||||
})
|
||||
if (!isSubAdmin)
|
||||
section.append(emptyCard)
|
||||
section.append(frag)
|
||||
@ -2061,11 +2107,11 @@
|
||||
}
|
||||
}
|
||||
function createQuote() {
|
||||
const quote = getRef('quote_template').content.cloneNode(true)
|
||||
quote.querySelector('.quote').textContent = '"Words can be like X-rays, if you use them properly—they’ll go through anything. You read and you’re pierced."'
|
||||
quote.querySelector('.by').textContent = `- Aldous Huxley,`
|
||||
quote.querySelector('.citation').textContent = 'Brave New World'
|
||||
return quote
|
||||
return createElement('figure', {
|
||||
className: 'quote-template grid gap-0-5',
|
||||
attributes: { 'contenteditable': "false" },
|
||||
innerHTML: `<blockquote class="flex"> <p class="quote" contenteditable="true">Words can be like X-rays, if you use them properly—they’ll go through anything. You read and you’re pierced.</p> </blockquote> <figcaption class="flex"><span class="by" contenteditable="true">Aldous Huxley</span>, <cite class="citation" contenteditable="true">Brave New World</cite></figcaption>`
|
||||
})
|
||||
}
|
||||
function insertBlockquote() {
|
||||
insertNode(createQuote())
|
||||
@ -2073,6 +2119,8 @@
|
||||
</script>
|
||||
<script id="onLoadStartUp">
|
||||
let isSubAdmin = false
|
||||
let maxCardsPerSection = isSubAdmin ? 3 : 2
|
||||
|
||||
function onLoadStartUp() {
|
||||
|
||||
//floDapps.addStartUpFunction('Sample', Promised Function)
|
||||
@ -2093,7 +2141,7 @@
|
||||
<svg class="icon" 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> <rect fill="none" height="24" width="24" /> </g> <g> <path d="M18,15v3H6v-3H4v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3H18z M17,11l-1.41-1.41L13,12.17V4h-2v8.17L8.41,9.59L7,11l5,5 L17,11z" /> </g> </svg>
|
||||
</button>
|
||||
`: ''}
|
||||
<sm-button variant="primary" onclick="${isSubAdmin ? 'publishArticle()' : 'exportSelection()'}">
|
||||
<sm-button variant="primary" onclick="${isSubAdmin ? "showPopup('publish_article_popup')" : 'exportSelection()'}">
|
||||
${isSubAdmin ? `
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0V0z" fill="none" /> <path d="M5 4h14v2H5zm0 10h4v6h6v-6h4l-7-7-7 7zm8-2v6h-2v-6H9.83L12 9.83 14.17 12H13z" /> </svg>
|
||||
Publish
|
||||
@ -11588,14 +11636,14 @@
|
||||
|
||||
body {
|
||||
color: rgba(var(--text-color), 1);
|
||||
background: var(--foreground-color)
|
||||
background: rgba(var(--background-color), 1)
|
||||
}
|
||||
|
||||
body,
|
||||
body * {
|
||||
--accent-color: rgb(0, 156, 78);
|
||||
--text-color: 36, 36, 36;
|
||||
--background-color: 248, 248, 248;
|
||||
--background-color: 252, 252, 252;
|
||||
--foreground-color: rgb(255, 255, 255);
|
||||
--danger-color: rgb(255, 75, 75);
|
||||
--like-color: #e91e63;
|
||||
@ -11679,6 +11727,10 @@
|
||||
justify-self: end
|
||||
}
|
||||
|
||||
.align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
@ -11804,7 +11856,7 @@
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
background-color: var(--foreground-color);
|
||||
background-color: rgba(var(--background-color), 1);
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
@ -11878,7 +11930,8 @@
|
||||
height: 40vh
|
||||
}
|
||||
|
||||
time {
|
||||
time,
|
||||
#reading_time {
|
||||
font-size: .8rem
|
||||
}
|
||||
|
||||
@ -12065,7 +12118,9 @@
|
||||
</picture> -->
|
||||
<section class="hero-section">
|
||||
<h1 id="exported_title"></h1>
|
||||
<time id="exported_time"></time>
|
||||
<div class="flex align-center">
|
||||
<time id="exported_time"></time> • <span id="reading_time"></span>
|
||||
</div>
|
||||
</section>
|
||||
<section id="export_body" class="grid gap-1"></section>
|
||||
<section>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user