feature and UI update

- implemented giving multiple categories to articles
- testing new fonts
-minor bug fixes
This commit is contained in:
sairaj mote 2022-02-17 16:39:44 +05:30
parent edd35f992d
commit 67f6671444
4 changed files with 293 additions and 127 deletions

View File

@ -2,7 +2,7 @@
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Archivo", sans-serif;
font-family: "Roboto", sans-serif;
}
:root {
@ -175,6 +175,17 @@ img {
width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 400;
letter-spacing: 0.01em;
font-family: "Calistoga", cursive;
}
.overflow-ellipsis {
width: 100%;
overflow: hidden;
@ -454,6 +465,10 @@ h3 {
stroke: none;
}
details {
border-top: thin rgba(var(--text-color), 0.1) solid;
border-bottom: thin rgba(var(--text-color), 0.1) solid;
}
details summary {
display: flex;
-webkit-user-select: none;
@ -461,7 +476,8 @@ details summary {
-ms-user-select: none;
user-select: none;
cursor: pointer;
padding: 0.5rem 0;
padding: 0.8rem 0;
color: var(--accent-color);
}
details[open] > summary .down-arrow {
transform: rotate(180deg);
@ -681,7 +697,7 @@ theme-toggle {
grid-template-columns: 5rem 1fr;
grid-template-rows: auto 1fr;
align-items: flex-start;
grid-template-areas: "img title" "img content";
grid-template-areas: "img title" "img categories";
min-height: 5rem;
}
.article-card img {
@ -691,20 +707,20 @@ theme-toggle {
height: 5rem;
width: 5rem;
}
.article-card a {
.article-card .article-link {
grid-area: title;
color: inherit;
}
.article-card .article-link {
gap: 0.5rem;
}
.article-card__title {
line-height: 1.4;
}
.article-card .flex {
grid-area: content;
.article-card .meta-data {
font-size: 0.75rem;
}
.article-card__categories {
grid-area: categories;
}
.article-card__category {
background-color: #256eff08;
@ -920,17 +936,17 @@ theme-toggle {
}
#dashboard {
height: -webkit-max-content;
height: -moz-max-content;
height: max-content;
height: 100%;
padding: 1.5rem 0;
grid-template-rows: auto 1fr;
align-items: flex-start;
}
#publishing_requests,
#article_analytics {
margin-top: 2rem;
align-content: flex-start;
padding-bottom: 3rem;
}
.request-card,
@ -947,7 +963,7 @@ theme-toggle {
#preview_popup h1,
#article h1 {
font-weight: 800;
font-weight: 700;
font-size: 1.7rem;
line-height: 1.1;
}
@ -1038,6 +1054,50 @@ theme-toggle {
margin-left: 0.5rem;
}
#edit_category {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
border: none;
}
.category-chip {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.3rem 0.5rem;
border-radius: 0.3rem;
font-size: 0.75rem;
border: solid thin rgba(var(--text-color), 0.2);
font-weight: 700;
text-transform: uppercase;
}
.category-chip:focus {
outline: solid var(--accent-color);
}
.category-chip input {
display: none;
}
.category-chip span {
transition: transform 0.2s;
transform: translateX(-0.8rem);
}
.category-chip .icon {
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
margin-right: 0.3rem;
fill: var(--accent-color);
transform: translateX(0.5rem);
}
.category-chip input:checked ~ .icon {
opacity: 1;
transform: translateX(0);
}
.category-chip input:checked ~ span {
color: var(--accent-color);
transform: translateX(0);
}
#user_popup {
overflow: hidden;
}

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Archivo", sans-serif;
font-family: "Roboto", sans-serif;
}
:root {
@ -165,6 +165,17 @@ img {
width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 400;
letter-spacing: 0.01em;
font-family: "Calistoga", cursive;
}
.overflow-ellipsis {
width: 100%;
overflow: hidden;
@ -437,11 +448,14 @@ h3 {
}
}
details {
border-top: thin rgba(var(--text-color), 0.1) solid;
border-bottom: thin rgba(var(--text-color), 0.1) solid;
summary {
display: flex;
user-select: none;
cursor: pointer;
padding: 0.5rem 0;
padding: 0.8rem 0;
color: var(--accent-color);
}
&[open] > summary {
@ -642,7 +656,7 @@ theme-toggle {
grid-template-columns: 5rem 1fr;
grid-template-rows: auto 1fr;
align-items: flex-start;
grid-template-areas: "img title" "img content";
grid-template-areas: "img title" "img categories";
min-height: 5rem;
img {
left: 0;
@ -651,20 +665,20 @@ theme-toggle {
height: 5rem;
width: 5rem;
}
a {
.article-link {
grid-area: title;
color: inherit;
}
.article-link {
gap: 0.5rem;
}
&__title {
line-height: 1.4;
}
.flex {
grid-area: content;
.meta-data {
font-size: 0.75rem;
}
&__categories {
grid-area: categories;
}
}
.article-card__category {
background-color: #256eff08;
@ -877,14 +891,16 @@ theme-toggle {
}
#dashboard {
height: max-content;
height: 100%;
padding: 1.5rem 0;
grid-template-rows: auto 1fr;
align-items: flex-start;
}
#publishing_requests,
#article_analytics {
margin-top: 2rem;
align-content: flex-start;
padding-bottom: 3rem;
}
.request-card,
@ -901,7 +917,7 @@ theme-toggle {
#preview_popup,
#article {
h1 {
font-weight: 800;
font-weight: 700;
font-size: 1.7rem;
line-height: 1.1;
}
@ -984,6 +1000,49 @@ theme-toggle {
margin-left: 0.5rem;
}
}
#edit_category {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
border: none;
}
.category-chip {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.3rem 0.5rem;
border-radius: 0.3rem;
font-size: 0.75rem;
border: solid thin rgba(var(--text-color), 0.2);
font-weight: 700;
text-transform: uppercase;
&:focus {
outline: solid var(--accent-color);
}
input {
display: none;
}
span {
transition: transform 0.2s;
transform: translateX(-0.8rem);
}
.icon {
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
margin-right: 0.3rem;
fill: var(--accent-color);
transform: translateX(0.5rem);
}
input:checked ~ .icon {
opacity: 1;
transform: translateX(0);
}
input:checked ~ span {
color: var(--accent-color);
transform: translateX(0);
}
}
#user_popup {
overflow: hidden;
header {

View File

@ -10,8 +10,11 @@
<link rel="stylesheet" href="css/main.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- <link
href="https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,400..900;1,400..900&family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"> -->
<link
href="https://fonts.googleapis.com/css2?family=Archivo:wght@400..900&family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
href="https://fonts.googleapis.com/css2?family=Calistoga&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
rel="stylesheet">
<script src="purify.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.4.6" defer></script>
@ -169,7 +172,7 @@
</div>
<a class="button" href="#/explore?type=recent">See all</a>
</div>
<ul id="latest_articles_list" class="grid gap-1-5"></ul>
<ul id="latest_articles_list" class="grid gap-2"></ul>
</section>
</article>
<article id="explore" class="page page-layout hide">
@ -454,12 +457,13 @@
</div>
<div class="grid gap-0-5">
<h5>Select category</h5>
<sm-select id="edit_category"></sm-select>
<fieldset id="edit_category"></fieldset>
</div>
<label class="grid gap-0-5">
<h5>Select Hero image</h5>
<img src="" alt="" id="preview_image">
<input id="select_image" type="file" accept="image">
<h5>Hero image URL</h5>
<!-- <img src="" alt="" id="preview_image">
<input id="select_image" type="file" accept="image"> -->
<sm-input id="get_hero_image" type="url"></sm-input>
</label>
</div>
<div class="grid gap-1-5">
@ -558,29 +562,29 @@
<div class="trending-article grid gap-0-5">
<a class="article-card--highlight grid gap-0-5" href="" style="color: inherit">
<img class="trending-article__image" src="" alt="" loading="lazy">
<div class="flex align-center" style="margin-top: 0.3rem;">
<time class="trending-article__published h5"></time>
<span class="bullet-point"></span>
<span class="trending-article__read-time h5"></span>
</div>
<h3 class="trending-article__title"></h3>
<p class="trending-article__summary"></p>
</a>
<div class="flex align-center" style="margin-top: 0.3rem;">
<a href="" class="article-card__category interact"></a>
<time class="trending-article__published h5"></time>
<span class="bullet-point"></span>
<span class="trending-article__read-time h5"></span>
</div>
<div class="flex align-center trending-article__categories flex-wrap" style="margin-top: 0.3rem;"></div>
</div>
</template>
<template id="article_card_template">
<li class="article-card grid">
<a href="" class="grid article-link">
<img class="article-card__image" src="" alt="" loading="lazy">
<div class="flex align-center meta-data">
<time class="article-card__published"></time>
<span class="bullet-point"></span>
<span class="article-card__read-time"></span>
</div>
<h4 class="article-card__title"></h4>
</a>
<div class="flex align-center" style="margin-top: 0.3rem;">
<a href="" class="article-card__category interact"></a>
<time class="article-card__published"></time>
<span class="bullet-point"></span>
<span class="article-card__read-time"></span>
</div>
<div class="flex align-center article-card__categories flex-wrap" style="margin-top: 0.3rem;"></div>
</li>
</template>
<template id="article_row_template">
@ -589,13 +593,14 @@
<h4 class="article-card__title"></h4>
<div class="flex space-between align-center gap-0-5">
<div class="flex align-center">
<span class="article-row__votes"></span>
<svg class="icon button__icon--right" xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 0 24 24" width="24px" fill="#000000">
<svg class="icon button__icon--left" style="fill: var(--like-color);"
xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
</svg>
<span class="article-row__votes"></span>
</div>
<div class="flex gap-0-5">
<button class="icon-only edit-article">
@ -1007,7 +1012,7 @@
}
if (targetPage === 'article') {
setTimeout(() => {
getRef('article').scroll({ top: 0 })
window.scroll({ top: 0 })
}, 0)
mobileQuery.addListener(handleMobileChange)
handleMobileChange(mobileQuery)
@ -1121,10 +1126,17 @@
const relativeTime = new RelativeTime({ style: 'narrow' });
const render = {
articleCard(details) {
const { uid: articleID, category, title, readTime, published, heroImage } = details
const { uid: articleID, categories, title, readTime, published, heroImage } = details
const clone = getRef('article_card_template').content.cloneNode(true).firstElementChild
clone.querySelector('.article-card__category').textContent = category
clone.querySelector('.article-card__category').href = `#/explore?type=category&query=${category}`
const frag = document.createDocumentFragment()
categories.forEach(category => {
frag.append(createElement('a', {
className: 'article-card__category interact',
attributes: { href: `#/explore?type=category&query=${category}` },
textContent: category
}))
})
clone.querySelector('.article-card__categories').append(frag)
clone.querySelector('.article-link').href = `#/article?articleID=${articleID}`
clone.querySelector('.article-card__image').src = heroImage
clone.querySelector('.article-card__title').textContent = title
@ -1133,10 +1145,17 @@
return clone
},
trendingArticleCard(details) {
const { uid: articleID, category, title, readTime, published, summary, heroImage } = details
const { uid: articleID, categories, title, readTime, published, summary, heroImage } = details
const clone = getRef('trending_article_template').content.cloneNode(true).firstElementChild
clone.querySelector('.article-card__category').textContent = category
clone.querySelector('.article-card__category').href = `#/explore?type=category&query=${category}`
const frag = document.createDocumentFragment()
categories.forEach(category => {
frag.append(createElement('a', {
className: 'article-card__category interact',
attributes: { href: `#/explore?type=category&query=${category}` },
textContent: category
}))
})
clone.querySelector('.trending-article__categories').append(frag)
clone.querySelector('.article-card--highlight').href = `#/article?articleID=${articleID}`
clone.querySelector('.trending-article__image').src = heroImage
clone.querySelector('.trending-article__title').textContent = title
@ -1146,7 +1165,7 @@
return clone
},
requestCard(details) {
const { senderID, message: { articleID, category, title }, time, vectorClock } = details
const { senderID, message: { articleID, title }, time, vectorClock } = details
const { publishedVc, rejectedVc, approvedID } = floGlobals.appObjects.adminData
const shouldRender = approvedID.hasOwnProperty(senderID) && !publishedVc.hasOwnProperty(vectorClock) && !rejectedVc.hasOwnProperty(vectorClock)
if (shouldRender) {
@ -1159,7 +1178,7 @@
}
},
articleRow(articleID) {
const { category, title, published, votes } = floGlobals.appObjects.rmTimes.articles[articleID]
const { title, published, votes } = floGlobals.appObjects.rmTimes.articles[articleID]
const clone = getRef('article_row_template').content.cloneNode(true).firstElementChild
clone.dataset.articleId = articleID
clone.querySelector('.article-card__title').textContent = title
@ -1186,7 +1205,7 @@
async homepage() {
const frag = document.createDocumentFragment()
// Render article topics
categories.forEach(({ title, icon }) => frag.append(createElement('a', {
allCategories.forEach(({ title, icon }) => frag.append(createElement('a', {
attributes: { href: `#/explore?type=category&query=${title.toLowerCase()}` },
className: 'category interact',
innerHTML: `${icon}<div>${title}</div>`,
@ -1219,9 +1238,16 @@
async article(articleID, firstLoad = true) {
const frag = document.createDocumentFragment()
const [allArticles, allImages] = await Promise.all([compactIDB.readData('appObjects', 'articlesContent'), compactIDB.readAllData('images')])
const { title, published, readTime, contributors, updated, summary, category } = floGlobals.appObjects.rmTimes.articles[articleID]
getRef('article_category').textContent = category
getRef('article_category').href = `#/explore?type=category&query=${category}`
const { title, published, readTime, contributors, updated, summary, categories } = floGlobals.appObjects.rmTimes.articles[articleID]
categories.forEach(category => {
frag.append(createElement('a', {
className: 'article-card__category interact',
attributes: { href: `#/explore?type=category&query=${category}` },
textContent: category
}))
})
getRef('article_category').innerHTML = ''
getRef('article_category').append(frag)
getRef('article_title').textContent = title
getRef('article_summary').textContent = summary
getRef('published_time').textContent = `${getFormattedTime(published, 'date-only')}${updated ? `, Updated ${relativeTime.from(updated)}` : ''}`
@ -1253,8 +1279,8 @@
getRef('article_contributors').innerHTML = ''
getRef('article_contributors').append(frag)
const fuse = new Fuse(getArrayOfObj(floGlobals.appObjects.rmTimes.articles), { keys: ['category'], threshold: 0 })
const searchResult = fuse.search(category).map(v => v.item).filter(v => v.uid !== articleID)
const fuse = new Fuse(getArrayOfObj(floGlobals.appObjects.rmTimes.articles), { keys: ['categories'], threshold: 0, useExtendedSearch: true })
const searchResult = fuse.search(categories.join('|')).map(v => v.item).filter(v => v.uid !== articleID)
let randomNumbers = []
if (searchResult.length > 3) {
// generate non-repeating random numbers
@ -1311,7 +1337,7 @@
}))
})
} else {
const options = (type === 'category') ? { keys: ['category'], threshold: 0 } : { keys: ['title', 'category', 'tags'], threshold: 0.3 }
const options = (type === 'category') ? { keys: ['categories'], threshold: 0 } : { keys: ['title', 'categories', 'tags'], threshold: 0.3 }
const fuse = new Fuse(sortedByTime, options)
const searchResult = fuse.search(query).map(v => v.item)
searchResult.forEach(articleDetail => {
@ -1384,7 +1410,7 @@
return arr
}
const categories = [
const allCategories = [
{
title: 'Culture',
icon: `<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><g><g><g><path d="M12,22C6.49,22,2,17.51,2,12S6.49,2,12,2s10,4.04,10,9c0,3.31-2.69,6-6,6h-1.77c-0.28,0-0.5,0.22-0.5,0.5 c0,0.12,0.05,0.23,0.13,0.33c0.41,0.47,0.64,1.06,0.64,1.67C14.5,20.88,13.38,22,12,22z M12,4c-4.41,0-8,3.59-8,8s3.59,8,8,8 c0.28,0,0.5-0.22,0.5-0.5c0-0.16-0.08-0.28-0.14-0.35c-0.41-0.46-0.63-1.05-0.63-1.65c0-1.38,1.12-2.5,2.5-2.5H16 c2.21,0,4-1.79,4-4C20,7.14,16.41,4,12,4z"/><circle cx="6.5" cy="11.5" r="1.5"/><circle cx="9.5" cy="7.5" r="1.5"/><circle cx="14.5" cy="7.5" r="1.5"/><circle cx="17.5" cy="11.5" r="1.5"/></g></g></g></g></svg>`
@ -1429,6 +1455,10 @@
title: 'Tech',
icon: `<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="M19.93,8.35l-3.6,1.68L14,7.7V6.3l2.33-2.33l3.6,1.68c0.38,0.18,0.82,0.01,1-0.36c0.18-0.38,0.01-0.82-0.36-1l-3.92-1.83 c-0.38-0.18-0.83-0.1-1.13,0.2L13.78,4.4C13.6,4.16,13.32,4,13,4c-0.55,0-1,0.45-1,1v1H8.82C8.4,4.84,7.3,4,6,4C4.34,4,3,5.34,3,7 c0,1.1,0.6,2.05,1.48,2.58L7.08,18H6c-1.1,0-2,0.9-2,2v1h13v-1c0-1.1-0.9-2-2-2h-1.62L8.41,8.77C8.58,8.53,8.72,8.28,8.82,8H12v1 c0,0.55,0.45,1,1,1c0.32,0,0.6-0.16,0.78-0.4l1.74,1.74c0.3,0.3,0.75,0.38,1.13,0.2l3.92-1.83c0.38-0.18,0.54-0.62,0.36-1 C20.75,8.34,20.31,8.17,19.93,8.35z M6,8C5.45,8,5,7.55,5,7c0-0.55,0.45-1,1-1s1,0.45,1,1C7,7.55,6.55,8,6,8z M11.11,18H9.17 l-2.46-8h0.1L11.11,18z"/></g></svg>`
},
{
title: 'World',
icon: `<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-.61.08-1.21.21-1.78L8.99 15v1c0 1.1.9 2 2 2v1.93C7.06 19.43 4 16.07 4 12zm13.89 5.4c-.26-.81-1-1.4-1.9-1.4h-1v-3c0-.55-.45-1-1-1h-6v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41C17.92 5.77 20 8.65 20 12c0 2.08-.81 3.98-2.11 5.4z"/></svg>`
},
]
const headingObserver = new IntersectionObserver(entries => {
@ -1504,7 +1534,7 @@
const searchKey = e.target.value.trim()
if (searchKey !== '') {
const options = {
keys: ['title', 'tags', 'category'],
keys: ['title', 'tags', 'categories'],
threshold: 0.3
}
const fuse = new Fuse(getArrayOfObj(floGlobals.appObjects.rmTimes.articles).sort((a, b) => b.published - a.published), options)
@ -1537,7 +1567,7 @@
} else {
getRef('search_suggestions').classList.add('hide')
}
}, 100))
}, 200))
getRef('search_articles').addEventListener('keyup', e => {
// detect enter key press
@ -1865,10 +1895,15 @@
getRef('approved_ids').innerHTML = ''
getRef('approved_ids').append(frag)
categories.forEach(({ title }) => {
frag.append(createElement('sm-option', {
textContent: title,
attributes: { value: title.toLowerCase() }
allCategories.forEach(({ title }) => {
frag.append(createElement('label', {
className: 'category-chip interact',
attributes: { tabindex: 0 },
innerHTML: `
<input type="checkbox" name="category" value="${title.toLowerCase()}" />
<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="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
<span class="checkmark">${title}</span>
`
}))
})
getRef('edit_category').innerHTML = ''
@ -1880,7 +1915,7 @@
const isPublished = floGlobals.appObjects.rmTimes.articles.hasOwnProperty(articleID)
getConfirmation(`${isPublished ? 'Update' : 'Publish'} article?`).then(async res => {
if (res) {
const { title, category, summary, published, tags, contributors, heroImage } = getArticleMetaData()
const { title, categories, summary, published, tags, contributors, heroImage } = getArticleMetaData()
floGlobals.appObjects.adminData.publishedVc[vectorClock] = true
floGlobals.appObjects.articlesContent[articleID] = content
if (isPublished) {
@ -1893,17 +1928,18 @@
}
floGlobals.appObjects.adminData.articleVotes[articleID] = { votes: {} }
}
floGlobals.appObjects.rmTimes.articles[articleID].category = category
floGlobals.appObjects.rmTimes.articles[articleID].categories = categories
floGlobals.appObjects.rmTimes.articles[articleID].contributors = contributors
floGlobals.appObjects.rmTimes.articles[articleID].title = title
floGlobals.appObjects.rmTimes.articles[articleID].heroImage = heroImage
floGlobals.appObjects.rmTimes.articles[articleID].tags = tags
floGlobals.appObjects.rmTimes.articles[articleID].readTime = readTime
floGlobals.appObjects.rmTimes.articles[articleID].summary = summary
compactIDB.writeData('images', { heroImage }, articleID)
const response = await floCloudAPI.sendApplicationData(heroImage, 'images')
for (const key in response) {
floGlobals.appObjects.rmTimes.articles[articleID].heroImage = response[key].vectorClock
}
// compactIDB.writeData('images', { heroImage }, articleID)
// const response = await floCloudAPI.sendApplicationData(heroImage, 'images')
// for (const key in response) {
// floGlobals.appObjects.rmTimes.articles[articleID].heroImage = response[key].vectorClock
// }
Promise.all([
floCloudAPI.updateObjectData('rmTimes'),
floCloudAPI.updateObjectData('adminData'),
@ -1964,18 +2000,28 @@
}
}
function setSelectedCategories(categories = []) {
getRef('edit_category').querySelectorAll(`[name="category"]`).forEach(checkbox => {
checkbox.checked = categories.includes(checkbox.value)
})
}
function getSelectedCategories() {
return [...getRef('edit_category').querySelectorAll('input:checked')].map(input => input.value)
}
async function setArticleMetaData(details, articleID) {
const { category, title, tags, summary, published, contributors } = details
const articleImages = await compactIDB.readData('images', articleID)
if (articleImages) {
getRef('preview_image').src = articleImages.heroImage.thumbnail
getRef('select_image').value = '';
} else {
getRef('preview_image').src = ''
}
const { categories, title, tags, summary, published, contributors, heroImage } = details
// const articleImages = await compactIDB.readData('images', articleID)
// if (articleImages) {
// getRef('preview_image').src = articleImages.heroImage.thumbnail
// getRef('select_image').value = '';
// } else {
// getRef('preview_image').src = ''
// }
getRef('get_hero_image').value = heroImage
getRef('edit_title').value = title;
getRef('edit_summary').value = summary || '';
getRef('edit_category').value = category || '';
setSelectedCategories(categories || '');
getRef('edit_contributors').value = contributors || [];
getRef('edit_tags').value = tags || [];
const now = Date.now()
@ -1984,8 +2030,8 @@
function getArticleMetaData() {
return {
title: getRef('edit_title').value.trim(),
category: getRef('edit_category').value,
heroImage: currentSelectedImage,
categories: getSelectedCategories(),
heroImage: getRef('get_hero_image').value.trim(),
summary: getRef('edit_summary').value.trim(),
published: new Date(getRef('edit_published').value).getTime(),
contributors: getRef('edit_contributors').value,
@ -2030,17 +2076,18 @@
function updateArticleMetaData(articleID) {
getConfirmation('Update article meta data?').then(async res => {
if (res) {
const { title, category, summary, published, tags, contributors, heroImage } = getArticleMetaData()
floGlobals.appObjects.rmTimes.articles[articleID].category = category
const { title, categories, summary, published, tags, contributors, heroImage } = getArticleMetaData()
floGlobals.appObjects.rmTimes.articles[articleID].categories = categories
floGlobals.appObjects.rmTimes.articles[articleID].title = title
floGlobals.appObjects.rmTimes.articles[articleID].heroImage = heroImage
floGlobals.appObjects.rmTimes.articles[articleID].tags = tags
floGlobals.appObjects.rmTimes.articles[articleID].summary = summary
floGlobals.appObjects.rmTimes.articles[articleID].contributors = contributors
compactIDB.writeData('images', { heroImage }, articleID)
const response = await floCloudAPI.sendApplicationData(heroImage, 'images')
for (const key in response) {
floGlobals.appObjects.rmTimes.articles[articleID].heroImage = response[key].vectorClock
}
// compactIDB.writeData('images', { heroImage }, articleID)
// const response = await floCloudAPI.sendApplicationData(heroImage, 'images')
// for (const key in response) {
// floGlobals.appObjects.rmTimes.articles[articleID].heroImage = response[key].vectorClock
// }
floCloudAPI.updateObjectData('rmTimes').then(() => {
notify(`Updated article meta data`, 'success')
hidePopup()
@ -2236,44 +2283,44 @@
}
}
let currentSelectedImage = {}
getRef('select_image').addEventListener('change', function (e) {
currentSelectedImage = {}
if (this.files.length === 0) return
const selectedFile = this.files[0]
const reader = new FileReader();
reader.onload = function (e) {
// show selected image in the preview
getRef('preview_image').src = e.target.result;
getRef('preview_image').addEventListener('load', function (event) {
// Dynamically create a canvas element
const canvas = createElement("canvas");
const context = canvas.getContext("2d");
const originalWidth = getRef('preview_image').width;
const originalHeight = getRef('preview_image').height;
const resizingFactor = parseFloat((1 / (originalWidth / 600)).toFixed(2));
// let currentSelectedImage = {}
// getRef('select_image').addEventListener('change', function (e) {
// currentSelectedImage = {}
// if (this.files.length === 0) return
// const selectedFile = this.files[0]
// const reader = new FileReader();
// reader.onload = function (e) {
// // show selected image in the preview
// getRef('preview_image').src = e.target.result;
// getRef('preview_image').addEventListener('load', function (event) {
// // Dynamically create a canvas element
// const canvas = createElement("canvas");
// const context = canvas.getContext("2d");
// const originalWidth = getRef('preview_image').width;
// const originalHeight = getRef('preview_image').height;
// const resizingFactor = parseFloat((1 / (originalWidth / 600)).toFixed(2));
const canvasWidth = originalWidth * resizingFactor;
const canvasHeight = originalHeight * resizingFactor;
// const canvasWidth = originalWidth * resizingFactor;
// const canvasHeight = originalHeight * resizingFactor;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// canvas.width = canvasWidth;
// canvas.height = canvasHeight;
context.drawImage(
getRef('preview_image'),
0,
0,
originalWidth * resizingFactor,
originalHeight * resizingFactor
);
currentSelectedImage['thumbnail'] = canvas.toDataURL(selectedFile.type);
}, { once: true });
currentSelectedImage.name = selectedFile.name
currentSelectedImage.type = selectedFile.type
currentSelectedImage.full = e.target.result
}
reader.readAsDataURL(this.files[0]);
})
// context.drawImage(
// getRef('preview_image'),
// 0,
// 0,
// originalWidth * resizingFactor,
// originalHeight * resizingFactor
// );
// currentSelectedImage['thumbnail'] = canvas.toDataURL(selectedFile.type);
// }, { once: true });
// currentSelectedImage.name = selectedFile.name
// currentSelectedImage.type = selectedFile.type
// currentSelectedImage.full = e.target.result
// }
// reader.readAsDataURL(this.files[0]);
// })
</script>
<script id="onLoadStartUp">