Adding hero image uploading feature

This commit is contained in:
sairaj mote 2022-02-07 00:19:42 +05:30
parent 5848e22bf5
commit 219b1e27bc
5 changed files with 203 additions and 105 deletions

View File

@ -3735,4 +3735,4 @@ customElements.define('tags-input', class extends HTMLElement {
this.input.removeEventListener('keydown', this.handleKeydown) this.input.removeEventListener('keydown', this.handleKeydown)
this.tagsWrapper.removeEventListener('click', this.handleClick) this.tagsWrapper.removeEventListener('click', this.handleClick)
} }
}) })

View File

@ -2,7 +2,7 @@
padding: 0; padding: 0;
margin: 0; margin: 0;
box-sizing: border-box; box-sizing: border-box;
font-family: "Inter", sans-serif; font-family: "Archivo", sans-serif;
} }
:root { :root {
@ -21,8 +21,8 @@ body {
body, body,
body * { body * {
--accent-color: #256eff; --accent-color: #256eff;
--text-color: 36, 36, 36; --text-color: 20, 20, 20;
--background-color: 248, 248, 248; --background-color: 255, 255, 255;
--foreground-color: rgb(255, 255, 255); --foreground-color: rgb(255, 255, 255);
--danger-color: rgb(255, 75, 75); --danger-color: rgb(255, 75, 75);
--green: #1cad59; --green: #1cad59;
@ -208,8 +208,9 @@ img {
font-size: 1.2rem; font-size: 1.2rem;
} }
.h3 { h3 {
font-size: 1rem; font-size: 1.2rem;
line-height: 1.3;
} }
.h4 { .h4 {
@ -362,7 +363,7 @@ img {
height: 0.4ch; height: 0.4ch;
width: 0.4ch; width: 0.4ch;
border-radius: 0.5em; border-radius: 0.5em;
background-color: currentColor; background-color: var(--accent-color);
} }
.icon { .icon {
@ -596,7 +597,6 @@ sm-copy {
grid-template-columns: auto 1fr auto auto; grid-template-columns: auto 1fr auto auto;
background-color: rgba(var(--background-color), 1); background-color: rgba(var(--background-color), 1);
z-index: 2; z-index: 2;
border-bottom: thin solid rgba(var(--text-color), 0.1);
} }
#expanding_search { #expanding_search {
@ -663,11 +663,11 @@ theme-toggle {
border-radius: 0.5rem; border-radius: 0.5rem;
width: 5.2rem; width: 5.2rem;
text-align: center; text-align: center;
background-color: rgba(var(--text-color), 0.02); background-color: #e6352f08;
} }
.category .icon { .category .icon {
margin-bottom: 1rem; margin-bottom: 1rem;
transition: transform 0.3s; transition: transform 0.3s, background-color 0.3s;
transform-origin: top; transform-origin: top;
} }
.category:hover .icon { .category:hover .icon {
@ -687,20 +687,21 @@ theme-toggle {
.article-card__title { .article-card__title {
line-height: 1.4; line-height: 1.4;
} }
.article-card .flex {
font-size: 0.75rem;
}
.article-card__category { .article-card__category {
background-color: rgba(var(--text-color), 0.06); background-color: #256eff08;
margin-right: 0.5rem; margin-right: 0.5rem;
border-radius: 0.2rem; border-radius: 0.2rem;
font-size: 0.75rem; font-size: 0.75rem;
padding: 0.2rem 0.4rem; padding: 0.2rem 0.4rem;
font-weight: 500; font-weight: 500;
color: rgba(var(--text-color), 0.8); color: var(--accent-color) !important;
justify-self: flex-start; justify-self: flex-start;
text-transform: capitalize; text-transform: capitalize;
} }
.article-card .flex {
font-size: 0.75rem;
}
#trending_article_container, #trending_article_container,
#query_results_list, #query_results_list,
@ -711,7 +712,6 @@ theme-toggle {
} }
.trending-article { .trending-article {
counter-increment: trending;
gap: 0.5rem 1.5rem; gap: 0.5rem 1.5rem;
} }
.trending-article a:first-of-type { .trending-article a:first-of-type {
@ -762,8 +762,7 @@ theme-toggle {
#article { #article {
display: flex; display: flex;
padding: 1.5rem; flex-wrap: wrap;
max-height: 100%;
overflow-y: auto; overflow-y: auto;
} }
#article main > section:last-of-type { #article main > section:last-of-type {
@ -793,9 +792,25 @@ theme-toggle {
} }
.hero-section { .hero-section {
position: relative;
display: grid; display: grid;
gap: 0.5rem; gap: 0.5rem;
grid-template-columns: minmax(0, 1fr); margin-top: 1.5rem;
align-content: flex-end;
width: 100%;
}
.hero-section p {
color: inherit;
}
.hero-section .overlay {
position: absolute;
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0));
z-index: -1;
} }
#article_image { #article_image {
@ -930,7 +945,7 @@ theme-toggle {
#preview_popup h1, #preview_popup h1,
#article h1 { #article h1 {
font-size: 1.6rem; font-size: 1.6rem;
line-height: 1.3; line-height: 1.1;
} }
#preview_popup h3:not(:first-of-type), #preview_popup h3:not(:first-of-type),
#article h3:not(:first-of-type) { #article h3:not(:first-of-type) {
@ -946,8 +961,7 @@ theme-toggle {
} }
#preview_popup p, #preview_popup p,
#article p { #article p {
font-family: "noto serif", serif; font-size: 1.1rem;
font-size: 1rem;
line-height: 1.8; line-height: 1.8;
} }
#preview_popup p > *, #preview_popup p > *,
@ -1072,6 +1086,10 @@ theme-toggle {
justify-self: flex-end; justify-self: flex-end;
} }
#article main {
padding: 0 1.5rem;
}
.writer-card .writer-profile { .writer-card .writer-profile {
height: 2.5rem; height: 2.5rem;
width: 2.5rem; width: 2.5rem;
@ -1169,22 +1187,26 @@ theme-toggle {
#preview_popup h1, #preview_popup h1,
#article h1 { #article h1 {
font-size: 2rem; font-size: 2.2rem;
font-weight: 800;
}
#preview_popup h3,
#article h3 {
font-size: 1.4rem;
line-height: 1.3;
} }
#article { #article {
gap: 6vw; padding: 0 4vw;
padding: 0;
grid-template-columns: 16rem 1fr;
} }
#article main { #article main {
width: 60ch; width: 60ch;
padding: 1.5rem 0; margin-left: 4vw;
} }
#article_aside { #article_aside {
width: 20rem; width: 20rem;
padding: 1.5rem 2rem; padding: 1.5rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: -webkit-sticky; position: -webkit-sticky;
@ -1259,7 +1281,7 @@ button:not(.button--primary) {
} }
.interact:hover, .interact:hover,
button:not(.button--primary):hover { button:not(.button--primary):hover {
background-color: rgba(var(--text-color), 0.06); background-color: #4885ff10;
} }
.button--primary { .button--primary {

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; padding: 0;
margin: 0; margin: 0;
box-sizing: border-box; box-sizing: border-box;
font-family: "Inter", sans-serif; font-family: "Archivo", sans-serif;
} }
:root { :root {
@ -18,8 +18,8 @@ body {
&, &,
* { * {
--accent-color: #256eff; --accent-color: #256eff;
--text-color: 36, 36, 36; --text-color: 20, 20, 20;
--background-color: 248, 248, 248; --background-color: 255, 255, 255;
--foreground-color: rgb(255, 255, 255); --foreground-color: rgb(255, 255, 255);
--danger-color: rgb(255, 75, 75); --danger-color: rgb(255, 75, 75);
--green: #1cad59; --green: #1cad59;
@ -199,8 +199,9 @@ img {
font-size: 1.2rem; font-size: 1.2rem;
} }
.h3 { h3 {
font-size: 1rem; font-size: 1.2rem;
line-height: 1.3;
} }
.h4 { .h4 {
@ -210,7 +211,13 @@ img {
.h5 { .h5 {
font-size: 0.75rem; font-size: 0.75rem;
} }
h1,
h2,
h3,
h4,
h5 {
// font-family: "Spectral", serif;
}
.uppercase { .uppercase {
text-transform: uppercase; text-transform: uppercase;
} }
@ -352,7 +359,7 @@ img {
height: 0.4ch; height: 0.4ch;
width: 0.4ch; width: 0.4ch;
border-radius: 0.5em; border-radius: 0.5em;
background-color: currentColor; background-color: var(--accent-color);
} }
} }
.icon { .icon {
@ -563,7 +570,6 @@ sm-copy {
grid-template-columns: auto 1fr auto auto; grid-template-columns: auto 1fr auto auto;
background-color: rgba(var(--background-color), 1); background-color: rgba(var(--background-color), 1);
z-index: 2; z-index: 2;
border-bottom: thin solid rgba(var(--text-color), 0.1);
} }
#expanding_search { #expanding_search {
position: absolute; position: absolute;
@ -624,10 +630,10 @@ theme-toggle {
border-radius: 0.5rem; border-radius: 0.5rem;
width: 5.2rem; width: 5.2rem;
text-align: center; text-align: center;
background-color: rgba(var(--text-color), 0.02); background-color: #e6352f08;
.icon { .icon {
margin-bottom: 1rem; margin-bottom: 1rem;
transition: transform 0.3s; transition: transform 0.3s, background-color 0.3s;
transform-origin: top; transform-origin: top;
} }
&:hover { &:hover {
@ -649,21 +655,21 @@ theme-toggle {
&__title { &__title {
line-height: 1.4; line-height: 1.4;
} }
&__category {
background-color: rgba(var(--text-color), 0.06);
margin-right: 0.5rem;
border-radius: 0.2rem;
font-size: 0.75rem;
padding: 0.2rem 0.4rem;
font-weight: 500;
color: rgba(var(--text-color), 0.8);
justify-self: flex-start;
text-transform: capitalize;
}
.flex { .flex {
font-size: 0.75rem; font-size: 0.75rem;
} }
} }
.article-card__category {
background-color: #256eff08;
margin-right: 0.5rem;
border-radius: 0.2rem;
font-size: 0.75rem;
padding: 0.2rem 0.4rem;
font-weight: 500;
color: var(--accent-color) !important;
justify-self: flex-start;
text-transform: capitalize;
}
#trending_article_container, #trending_article_container,
#query_results_list, #query_results_list,
@ -673,7 +679,6 @@ theme-toggle {
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
} }
.trending-article { .trending-article {
counter-increment: trending;
gap: 0.5rem 1.5rem; gap: 0.5rem 1.5rem;
a:first-of-type { a:first-of-type {
position: relative; position: relative;
@ -723,8 +728,7 @@ theme-toggle {
#article { #article {
display: flex; display: flex;
padding: 1.5rem; flex-wrap: wrap;
max-height: 100%;
overflow-y: auto; overflow-y: auto;
main { main {
& > section:last-of-type { & > section:last-of-type {
@ -753,9 +757,25 @@ theme-toggle {
} }
} }
.hero-section { .hero-section {
position: relative;
display: grid; display: grid;
gap: 0.5rem; gap: 0.5rem;
grid-template-columns: minmax(0, 1fr); margin-top: 1.5rem;
align-content: flex-end;
width: 100%;
p {
color: inherit;
}
.overlay {
position: absolute;
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0));
z-index: -1;
}
} }
#article_image { #article_image {
margin-top: 1.5rem; margin-top: 1.5rem;
@ -888,7 +908,7 @@ theme-toggle {
#article { #article {
h1 { h1 {
font-size: 1.6rem; font-size: 1.6rem;
line-height: 1.3; line-height: 1.1;
} }
h3:not(:first-of-type) { h3:not(:first-of-type) {
@ -901,8 +921,8 @@ theme-toggle {
} }
} }
p { p {
font-family: "noto serif", serif; // font-family: "Roboto", sans-serif;
font-size: 1rem; font-size: 1.1rem;
line-height: 1.8; line-height: 1.8;
& > * { & > * {
font-family: inherit; font-family: inherit;
@ -1017,6 +1037,11 @@ theme-toggle {
#search_button { #search_button {
justify-self: flex-end; justify-self: flex-end;
} }
#article {
main {
padding: 0 1.5rem;
}
}
.writer-card { .writer-card {
.writer-profile { .writer-profile {
height: 2.5rem; height: 2.5rem;
@ -1104,21 +1129,24 @@ theme-toggle {
#preview_popup, #preview_popup,
#article { #article {
h1 { h1 {
font-size: 2rem; font-size: 2.2rem;
font-weight: 800;
}
h3 {
font-size: 1.4rem;
line-height: 1.3;
} }
} }
#article { #article {
gap: 6vw; padding: 0 4vw;
padding: 0;
grid-template-columns: 16rem 1fr;
main { main {
width: 60ch; width: 60ch;
padding: 1.5rem 0; margin-left: 4vw;
} }
} }
#article_aside { #article_aside {
width: 20rem; width: 20rem;
padding: 1.5rem 2rem; padding: 1.5rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: sticky; position: sticky;
@ -1186,7 +1214,7 @@ theme-toggle {
button:not(.button--primary) { button:not(.button--primary) {
transition: background-color 0.3s; transition: background-color 0.3s;
&:hover { &:hover {
background-color: rgba(var(--text-color), 0.06); background-color: #4885ff10;
} }
} }
.button--primary { .button--primary {

View File

@ -13,6 +13,9 @@
<link <link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"> rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400..700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Merriweather+Sans:wght@400..800&display=swap" rel="stylesheet">
<script src="purify.min.js" defer></script> <script src="purify.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.4.6" defer></script> <script src="https://cdn.jsdelivr.net/npm/fuse.js@6.4.6" defer></script>
<script id="floGlobals"> <script id="floGlobals">
@ -259,6 +262,7 @@
<div id="article_contributors" class="flex"></div> <div id="article_contributors" class="flex"></div>
</section> </section>
</main> </main>
<button id="go_to_top" class="floating-button hide" onclick="goToTop()"> <button id="go_to_top" class="floating-button hide" onclick="goToTop()">
<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"
fill="#000000"> fill="#000000">
@ -430,6 +434,11 @@
</header> </header>
<section class="grid gap-1-5"> <section class="grid gap-1-5">
<div class="grid gap-1-5"> <div class="grid gap-1-5">
<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">
</label>
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<h5>Title</h5> <h5>Title</h5>
<sm-input id="edit_title" required></sm-input> <sm-input id="edit_title" required></sm-input>
@ -438,16 +447,12 @@
<h5>Select category</h5> <h5>Select category</h5>
<sm-select id="edit_category"></sm-select> <sm-select id="edit_category"></sm-select>
</div> </div>
<div class="grid gap-0-5"> </div>
<h5>Hero image URL</h5> <div class="grid gap-1-5">
<sm-input id="edit_image" type="url"></sm-input>
</div>
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<h5>Summary</h5> <h5>Summary</h5>
<sm-textarea id="edit_summary" rows="4"></sm-textarea> <sm-textarea id="edit_summary" rows="4"></sm-textarea>
</div> </div>
</div>
<div class="grid gap-1-5">
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<h5>Add tags</h5> <h5>Add tags</h5>
<tags-input id="edit_tags" limit="10"></tags-input> <tags-input id="edit_tags" limit="10"></tags-input>
@ -544,8 +549,9 @@
</a> </a>
<div class="flex align-center" style="margin-top: 0.3rem;"> <div class="flex align-center" style="margin-top: 0.3rem;">
<a href="" class="article-card__category interact"></a> <a href="" class="article-card__category interact"></a>
<span class="trending-article__read-time h5"></span><span class="bullet-point"></span><time <time class="trending-article__published h5"></time>
class="trending-article__published h5"></time> <span class="bullet-point"></span>
<span class="trending-article__read-time h5"></span>
</div> </div>
</div> </div>
</template> </template>
@ -556,8 +562,9 @@
</a> </a>
<div class="flex align-center" style="margin-top: 0.3rem;"> <div class="flex align-center" style="margin-top: 0.3rem;">
<a href="" class="article-card__category interact"></a> <a href="" class="article-card__category interact"></a>
<span class="article-card__read-time"></span><span class="bullet-point"></span>
<time class="article-card__published"></time> <time class="article-card__published"></time>
<span class="bullet-point"></span>
<span class="article-card__read-time"></span>
</div> </div>
</li> </li>
</template> </template>
@ -1164,11 +1171,13 @@
getRef('news_categories_list').innerHTML = '' getRef('news_categories_list').innerHTML = ''
getRef('news_categories_list').append(frag) getRef('news_categories_list').append(frag)
const arrOfArticles = getArrayOfObj(floGlobals.appObjects.rmTimes.articles) const arrOfArticles = getArrayOfObj(floGlobals.appObjects.rmTimes.articles)
// Render trending article card
let sortedByVotes = arrOfArticles.sort((a, b) => b.votes - a.votes) let sortedByVotes = arrOfArticles.sort((a, b) => b.votes - a.votes)
sortedByVotes.slice(0, 4).forEach(articleDetail => frag.append(render.trendingArticleCard(articleDetail))) // Render trending article card
getRef('trending_article_container').innerHTML = '' compactIDB.readData('appObjects', 'heroImages').then(heroImages => {
getRef('trending_article_container').append(frag) sortedByVotes.slice(0, 4).forEach(articleDetail => frag.append(render.trendingArticleCard({ ...articleDetail, heroImage: heroImages[articleDetail.uid].thumbnail })))
getRef('trending_article_container').innerHTML = ''
getRef('trending_article_container').append(frag)
})
// render latest articles // render latest articles
const sortedArticles = sortedByVotes.slice(4).sort((a, b) => b.published - a.published) const sortedArticles = sortedByVotes.slice(4).sort((a, b) => b.published - a.published)
sortedArticles.forEach(articleDetail => frag.append(render.articleCard(articleDetail))) sortedArticles.forEach(articleDetail => frag.append(render.articleCard(articleDetail)))
@ -1177,9 +1186,9 @@
}, },
async article(articleID, firstLoad = true) { async article(articleID, firstLoad = true) {
const frag = document.createDocumentFragment() const frag = document.createDocumentFragment()
const allArticles = await compactIDB.readData('appObjects', 'articlesContent') const [allArticles, heroImages] = await Promise.all([compactIDB.readData('appObjects', 'articlesContent'), compactIDB.readData('appObjects', 'heroImages')])
const { title, published, readTime, contributors, updated, summary, heroImage } = floGlobals.appObjects.rmTimes.articles[articleID] const { title, published, readTime, contributors, updated, summary } = floGlobals.appObjects.rmTimes.articles[articleID]
getRef('article_image').src = heroImage getRef('article_image').src = heroImages[articleID].full
getRef('article_title').textContent = title getRef('article_title').textContent = title
getRef('article_summary').textContent = summary getRef('article_summary').textContent = summary
getRef('published_time').textContent = `${getFormattedTime(published, 'date-only')}${updated ? `, Updated ${relativeTime.from(updated)}` : ''}` getRef('published_time').textContent = `${getFormattedTime(published, 'date-only')}${updated ? `, Updated ${relativeTime.from(updated)}` : ''}`
@ -1276,8 +1285,10 @@
Promise.all([ Promise.all([
floCloudAPI.requestObjectData('rmTimes'), floCloudAPI.requestObjectData('rmTimes'),
floCloudAPI.requestObjectData('articlesContent'), floCloudAPI.requestObjectData('articlesContent'),
floCloudAPI.requestObjectData('heroImages'),
]).then(() => { ]).then(() => {
delete floGlobals.appObjects.articlesContent delete floGlobals.appObjects.articlesContent
delete floGlobals.appObjects.heroImages
showPage(window.location.hash, { firstLoad: true }) showPage(window.location.hash, { firstLoad: true })
}) })
} }
@ -1294,19 +1305,6 @@
return arr return arr
} }
// implement image resizing
function resizeImage(img, maxWidth, maxHeight) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const ratio = 1
canvas.width = img.width * ratio
canvas.height = img.height * ratio
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
const dataURL = canvas.toDataURL('image/jpeg', 0.5)
return dataURL
}
const categories = [ const categories = [
{ {
title: 'Culture', title: 'Culture',
@ -1797,7 +1795,7 @@
const isPublished = floGlobals.appObjects.rmTimes.articles.hasOwnProperty(articleID) const isPublished = floGlobals.appObjects.rmTimes.articles.hasOwnProperty(articleID)
getConfirmation(`${isPublished ? 'Update' : 'Publish'} article?`).then(res => { getConfirmation(`${isPublished ? 'Update' : 'Publish'} article?`).then(res => {
if (res) { if (res) {
const { title, category, summary, published, tags, contributors } = getArticleMetaData() const { title, category, summary, published, tags, contributors, heroImage } = getArticleMetaData()
floGlobals.appObjects.adminData.publishedVc[vectorClock] = true floGlobals.appObjects.adminData.publishedVc[vectorClock] = true
floGlobals.appObjects.articlesContent[articleID] = content floGlobals.appObjects.articlesContent[articleID] = content
if (isPublished) { if (isPublished) {
@ -1816,10 +1814,12 @@
floGlobals.appObjects.rmTimes.articles[articleID].tags = tags floGlobals.appObjects.rmTimes.articles[articleID].tags = tags
floGlobals.appObjects.rmTimes.articles[articleID].readTime = readTime floGlobals.appObjects.rmTimes.articles[articleID].readTime = readTime
floGlobals.appObjects.rmTimes.articles[articleID].summary = summary floGlobals.appObjects.rmTimes.articles[articleID].summary = summary
floGlobals.appObjects.heroImages[articleID] = heroImage
Promise.all([ Promise.all([
floCloudAPI.updateObjectData('rmTimes'), floCloudAPI.updateObjectData('rmTimes'),
floCloudAPI.updateObjectData('adminData'), floCloudAPI.updateObjectData('adminData'),
floCloudAPI.updateObjectData('articlesContent'), floCloudAPI.updateObjectData('articlesContent'),
floCloudAPI.updateObjectData('heroImages'),
]).then(() => { ]).then(() => {
notify(`${isPublished ? 'Updated' : 'Published'} article`, 'success') notify(`${isPublished ? 'Updated' : 'Published'} article`, 'success')
if (!isPublished) { if (!isPublished) {
@ -1838,9 +1838,9 @@
const { message: { articleID, title, contributors } } = floGlobals.generalData[`publishing_requests|${floGlobals.adminID}|${floGlobals.application}`][vc] const { message: { articleID, title, contributors } } = floGlobals.generalData[`publishing_requests|${floGlobals.adminID}|${floGlobals.application}`][vc]
const isPublished = floGlobals.appObjects.rmTimes.articles.hasOwnProperty(articleID) const isPublished = floGlobals.appObjects.rmTimes.articles.hasOwnProperty(articleID)
if (isPublished) if (isPublished)
setArticleMetaData(floGlobals.appObjects.rmTimes.articles[articleID]) setArticleMetaData(floGlobals.appObjects.rmTimes.articles[articleID], articleID)
else else
setArticleMetaData({ title, contributors }) setArticleMetaData({ title, contributors }, articleID)
floGlobals.subAdminData = { floGlobals.subAdminData = {
actionType: 'request', actionType: 'request',
articleID, articleID,
@ -1876,10 +1876,16 @@
} }
} }
function setArticleMetaData(details) { async function setArticleMetaData(details, articleID) {
const { category, title, tags, summary, published, contributors, heroImage } = details const { category, title, tags, summary, published, contributors } = details
const heroImage = floGlobals.appObjects.heroImages[articleID]
getRef('edit_title').value = title; getRef('edit_title').value = title;
getRef('edit_image').value = heroImage || ''; if (heroImage) {
getRef('preview_image').src = heroImage.thumbnail
getRef('select_image').value = '';
} else {
getRef('preview_image').src = ''
}
getRef('edit_summary').value = summary || ''; getRef('edit_summary').value = summary || '';
getRef('edit_category').value = category || ''; getRef('edit_category').value = category || '';
getRef('edit_contributors').value = contributors || []; getRef('edit_contributors').value = contributors || [];
@ -1891,7 +1897,7 @@
return { return {
title: getRef('edit_title').value.trim(), title: getRef('edit_title').value.trim(),
category: getRef('edit_category').value, category: getRef('edit_category').value,
heroImage: getRef('edit_image').value, heroImage: currentSelectedImage,
summary: getRef('edit_summary').value.trim(), summary: getRef('edit_summary').value.trim(),
published: new Date(getRef('edit_published').value).getTime(), published: new Date(getRef('edit_published').value).getTime(),
contributors: getRef('edit_contributors').value, contributors: getRef('edit_contributors').value,
@ -1902,7 +1908,7 @@
if (e.target.closest('.edit-article')) { if (e.target.closest('.edit-article')) {
const button = e.target.closest('.edit-article'); const button = e.target.closest('.edit-article');
const articleID = button.dataset.articleId; const articleID = button.dataset.articleId;
setArticleMetaData(floGlobals.appObjects.rmTimes.articles[articleID]) setArticleMetaData(floGlobals.appObjects.rmTimes.articles[articleID], articleID)
floGlobals.subAdminData = { floGlobals.subAdminData = {
actionType: 'analytics', actionType: 'analytics',
articleID, articleID,
@ -1921,11 +1927,11 @@
floGlobals.appObjects.rmTimes.articles[articleID].title = title floGlobals.appObjects.rmTimes.articles[articleID].title = title
floGlobals.appObjects.rmTimes.articles[articleID].tags = tags floGlobals.appObjects.rmTimes.articles[articleID].tags = tags
floGlobals.appObjects.rmTimes.articles[articleID].summary = summary floGlobals.appObjects.rmTimes.articles[articleID].summary = summary
floGlobals.appObjects.rmTimes.articles[articleID].heroImage = heroImage
floGlobals.appObjects.rmTimes.articles[articleID].contributors = contributors floGlobals.appObjects.rmTimes.articles[articleID].contributors = contributors
floGlobals.appObjects.heroImages[articleID] = heroImage
Promise.all([ Promise.all([
floCloudAPI.updateObjectData('rmTimes'), floCloudAPI.updateObjectData('rmTimes'),
floCloudAPI.updateObjectData('adminData'), floCloudAPI.updateObjectData('heroImages'),
]).then(() => { ]).then(() => {
notify(`Updated article meta data`, 'success') notify(`Updated article meta data`, 'success')
hidePopup() hidePopup()
@ -1991,7 +1997,10 @@
console.log('calculated votes') console.log('calculated votes')
}) })
}) })
floGlobals.appObjects.articlesContent = await compactIDB.readData('appObjects', 'articlesContent') Promise.all([compactIDB.readData('appObjects', 'articlesContent'), compactIDB.readData('appObjects', 'heroImages')]).then(res => {
floGlobals.appObjects.articlesContent = res[0];
floGlobals.appObjects.heroImages = res[1];
})
} }
getRef('section_selector').addEventListener('change', e => { getRef('section_selector').addEventListener('change', e => {
@ -2118,6 +2127,45 @@
} }
} }
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;
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]);
})
</script> </script>
<script id="onLoadStartUp"> <script id="onLoadStartUp">
function onLoadStartUp() { function onLoadStartUp() {