summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2022-12-10 08:15:44 +0100
committerache <ache@ache.one>2022-12-10 08:15:44 +0100
commit045b3f3c21bf9c0f9b728fe14ce75e4d2a90944a (patch)
treef1ffd05522f351eba8561410548b404e10cfa23a
parentShow date on each article (diff)
First implementation of Likes
-rw-r--r--src/build/index.mjs4
-rwxr-xr-xsrc/css/_contenu.scss111
-rw-r--r--src/js/love.js113
-rw-r--r--src/templates/article.tmpl2
-rw-r--r--src/templates/likes.tmpl17
5 files changed, 245 insertions, 2 deletions
diff --git a/src/build/index.mjs b/src/build/index.mjs
index a8fac14..54a0b02 100644
--- a/src/build/index.mjs
+++ b/src/build/index.mjs
@@ -103,6 +103,7 @@ const loadMD = (listFile, suffix) => {
};
const leftPanelTmpl = fs.readFileSync('src/templates/left.tmpl', 'utf8');
+const likesTmpl = fs.readFileSync('src/templates/likes.tmpl', 'utf8');
const headerTmpl = fs.readFileSync('src/templates/header.tmpl', 'utf8');
const articleTmpl = fs.readFileSync('src/templates/article.tmpl', 'utf8');
const indexTmpl = fs.readFileSync('src/templates/index.tmpl', 'utf8');
@@ -113,13 +114,12 @@ const baseUrl = 'https://ache.one/';
const partials = {
header: headerTmpl,
leftPanel: leftPanelTmpl,
+ likesButton: likesTmpl,
hid: hidTmpl,
};
const svg = loadSVG();
-
const articles = loadMD(listArticles, 'articles');
-
const tagsArticle = new Map();
for (const article of articles) {
diff --git a/src/css/_contenu.scss b/src/css/_contenu.scss
index 4dab365..c261aff 100755
--- a/src/css/_contenu.scss
+++ b/src/css/_contenu.scss
@@ -281,6 +281,116 @@ code {
}
}
+section.likes {
+ display: flex;
+ justify-content: center;
+
+ .likesBox {
+ padding: 20px;
+ border-radius: 8px;
+ background-color: #CDE3EC;
+ display: flex;
+
+ .likesTitle {
+ font: monospace;
+ font-family: Source Sans Pro,Segoe UI,Trebuchet MS,Helvetica,Helvetica Neue,Arial,sans-serif;
+ font-weight: 800;
+ }
+ .likesText {
+ font-size: 0.8em;
+ }
+ .likesNotes {
+ font-size: 0.8em;
+ color: #777;
+ &.err {
+ color: red;
+ }
+ }
+
+
+ .icon {
+ fill: transparent;
+ stroke: pink;
+ stroke-width: 20;
+ cursor: pointer;
+ position: relative;
+ svg {
+ overflow: visible;
+ width: 10rem;
+ }
+
+ path {
+ stroke-dashoffset: 0;
+ stroke-dasharray: 1550;
+ transform-origin: center;
+ }
+
+ .hear-main {
+ z-index: 2;
+ }
+ .heart-background {
+ position: absolute;
+ left: 0;
+ right: 0;
+ z-index: 1;
+ stroke: none;
+ }
+ .heart-main path.anim {
+ animation: stroke-animation 2s ease-in-out forwards;
+ }
+
+ .heart-main ~ .heart-background path.anim-click {
+ animation: fade-animation 0.35s ease-in-out forwards;
+ }
+ .nbLikes {
+ font-family: Source Sans Pro,Segoe UI,Trebuchet MS,Helvetica,Helvetica Neue,Arial,sans-serif;
+ color: #00324D;
+ text-align: center;
+ position: relative;
+ top: -10px;
+ height: 0;
+ }
+ }
+
+ @keyframes stroke-animation {
+ 0% {
+ fill: transparent;
+ transform: scale(1);
+ }
+ 50% {
+ fill: pink;
+ transform: scale(1.1);
+ }
+ 70% {
+ transform: scale(1);
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ fill: pink;
+ }
+ }
+
+ @keyframes fade-animation {
+ 0% {
+ fill: transparent;
+ transform: scale(1);
+ }
+ 13% {
+ fill: lightpink;
+ transform: scale(1.2);
+ opacity: 1;
+ }
+ 66% {
+ opacity: 0.8;
+ }
+ 100% {
+ transform: scale(2);
+ opacity: 0;
+ }
+ }
+ }
+}
+
.tags {
display: flex;
gap: 10px;
@@ -293,6 +403,7 @@ code {
padding: 0px 8px;
border-radius: 3px;
}
+
}
.inline-tag {
position: relative;
diff --git a/src/js/love.js b/src/js/love.js
new file mode 100644
index 0000000..5706c95
--- /dev/null
+++ b/src/js/love.js
@@ -0,0 +1,113 @@
+window.addEventListener('DOMContentLoaded', () => {
+ // This script insert a love button at the end of an article page
+
+ const articles = document.querySelectorAll('article');
+
+ const config = {
+ likesEndPointBase: 'localhost:3000',
+ };
+
+ function getLikeEndPoint() {
+ let currentArticleName = window.location.pathname.split('/')[2];
+ if (currentArticleName.indexOf('.') > 0) {
+ currentArticleName = currentArticleName.slice(0, currentArticleName.lastIndexOf('.'))
+ }
+ return `${window.location.protocol}//${config.likesEndPointBase}/like/${currentArticleName}`;
+ }
+
+ // The front page have multiple articles
+ if (articles.length === 1) {
+ const article = articles[0];
+ const likes = article.querySelector('.likes');
+ const nbLikes = article.querySelector('.nbLikes');
+ const footnotes = article.querySelector('.footnotes');
+
+ likes.style="display: 'block';";
+ const updateNbLikes = () => {
+ fetch(getLikeEndPoint(), {
+ method: 'GET',
+ headers: {
+ 'i-love-what-you-do': '<3',
+ },
+ }).then((res) => {
+ if (res.ok) {
+ res.text().then((text) => nbLikes.textContent = text);
+ } else {
+ nbLikes.textContent = "";
+ }
+ });
+ };
+
+ updateNbLikes();
+
+ if (footnotes) {
+ // We want: article.insertBefore(likes, footnotes);
+ footnotes.before(likes);
+ }
+
+ const icon = likes.querySelector('.icon');
+ const messagesLike = likes.querySelector('.likesNotes');
+
+ icon.addEventListener('mouseover', () => {
+ for (const c of icon.children) {
+ const path = c.querySelector('path');
+ path?.classList.add('anim');
+ }
+ });
+
+ icon.addEventListener('mouseout', () => {
+ for (const c of icon.children) {
+ const path = c.querySelector('path');
+ path?.classList.remove('anim');
+ }
+ });
+
+ let timeOut;
+ let messageText;
+ icon.addEventListener('click', () => {
+ const c = icon.children[1];
+ {
+ const path = c.querySelector('path');
+ console.log(path)
+ path.classList.add('anim-click');
+ path.getAnimations().forEach(anim => {
+ anim.cancel();
+ anim.play();
+ });
+
+ fetch(getLikeEndPoint(), {
+ method: 'POST',
+ headers: {
+ 'i-love-what-you-do': '<3',
+ },
+ }).then(response => {
+ const currentText = messagesLike.textContent;
+ const t = response.text().then(text => {
+ messagesLike.textContent = text;
+ return text;
+ });
+
+ if (response.ok) {
+ messagesLike.classList.remove('err');
+ t.then((t) => messageText = t);
+ updateNbLikes();
+ } else {
+ if (!messageText) {
+ messageText = currentText;
+ }
+
+ messagesLike.classList.add('err');
+ setTimeout(() => {
+ messagesLike.classList.remove('err');
+ messagesLike.textContent = messageText;
+ }, 3000);
+ }
+ }).catch(() => {
+ messagesLike.classList.add('err');
+ messagesLike.textContent = 'Désolé, le service est indisponible';
+ messageText = '';
+ });
+ }
+ });
+ }
+});
diff --git a/src/templates/article.tmpl b/src/templates/article.tmpl
index e5267ff..6b1b628 100644
--- a/src/templates/article.tmpl
+++ b/src/templates/article.tmpl
@@ -6,7 +6,9 @@
<div class="marge"></div>
<article class="post" id="{{domTitle}}_article">
<div class="tags">{{# metaData.tags }}<a href="/tag/{{{ . }}}" class="tag">{{{ . }}}</a>{{/ metaData.tags }}</div>
+ <div class="pubdate">{{ metaData.pubDateISO }}</div>
{{{ content }}}
+ {{> likesButton }}
</article>
<div class="sidenotes"></div>
</div>
diff --git a/src/templates/likes.tmpl b/src/templates/likes.tmpl
new file mode 100644
index 0000000..a0018d9
--- /dev/null
+++ b/src/templates/likes.tmpl
@@ -0,0 +1,17 @@
+<section class="likes" style="display: none">
+ <span class="likesBox">
+ <div class="icon">
+ <svg class="heart-main" viewBox="0 0 512 512" title="heart" z-index="1" height="100">
+ <path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z" class=""></path>
+ </svg>
+ <svg class="heart-background" viewBox="0 0 512 512" title="heart" z-index="1" height="100">
+ <path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z" class=""></path>
+ </svg>
+ <div class="nbLikes"><div></div></div>
+ </div>
+ <div>
+ <span class="likesTitle">Si vous avez aimez cet article cliquez sur le cœur !</span>
+ <p class="likesText">Vous pouvez même envoyez plusieurs cœurs ! <br><span class="likesNotes">Le délais d'attente entre deux cœurs double à chaque fois.</span></p>
+ </div></span>
+
+ </section>