Fix syndication and webmention with mastodon
This commit is contained in:
@@ -1,3 +1,33 @@
|
||||
:root {
|
||||
--blockquote-border-size: 4px;
|
||||
--blockquote-background-color: rgb(248 248 248);
|
||||
|
||||
--heading-border-size: 4px;
|
||||
|
||||
--link-background-color: 189, 195, 199;
|
||||
--link-background-opacity: 0.5;
|
||||
--link-background-opacity-hover: 0.7;
|
||||
|
||||
--pre-background-color: #272822;
|
||||
--pre-text-color: #f8f8f2;
|
||||
|
||||
--code-background-color: rgba(0, 0, 0, 0.12);
|
||||
--code-text-color: #808080;
|
||||
|
||||
--table-border-color: #dadada;
|
||||
--tr-even-background-color: #efefee;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--code-background-color: #272822;
|
||||
--code-text-color: rgba(255, 255, 255, 0.9);
|
||||
|
||||
--table-border-color: #717171;
|
||||
--tr-even-background-color: #545454;
|
||||
|
||||
--blockquote-background-color: rgb(75 75 75);
|
||||
}
|
||||
}
|
||||
|
||||
.author {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -50,3 +80,155 @@
|
||||
transform-origin: left top;
|
||||
}
|
||||
}
|
||||
|
||||
small,
|
||||
aside p {
|
||||
font-size: smaller;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
section#comments {
|
||||
#comments-wrapper {
|
||||
margin: 1.5em 0;
|
||||
padding: 0 var(--card-padding);
|
||||
}
|
||||
|
||||
.comment {
|
||||
display: grid;
|
||||
column-gap: 1rem;
|
||||
grid-template-areas:
|
||||
"avatar name"
|
||||
"avatar time"
|
||||
"avatar post"
|
||||
"...... interactions";
|
||||
grid-template-columns: min-content;
|
||||
justify-items: start;
|
||||
margin: 0em auto 0em -1em;
|
||||
padding: 0.5em;
|
||||
|
||||
&.comment-reply {
|
||||
margin: 0em auto 0em 1em;
|
||||
}
|
||||
|
||||
.avatar-link {
|
||||
grid-area: avatar;
|
||||
height: 4rem;
|
||||
position: relative;
|
||||
width: 4rem;
|
||||
|
||||
.avatar {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 20%;
|
||||
}
|
||||
|
||||
&.op::after {
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 50%;
|
||||
bottom: -0.25rem;
|
||||
color: var(--accent-color-text);
|
||||
content: "✓";
|
||||
display: block;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
height: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
position: absolute;
|
||||
right: -0.25rem;
|
||||
text-align: center;
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.author {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-weight: bold;
|
||||
gap: 0.5em;
|
||||
grid-area: name;
|
||||
|
||||
.instance {
|
||||
background-color: var(--code-background-color);
|
||||
border-radius: 9999px;
|
||||
color: var(--neutral);
|
||||
font-size: smaller;
|
||||
font-weight: normal;
|
||||
padding: 0.25em 0.75em;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.op {
|
||||
background-color: var(
|
||||
--code-background-color
|
||||
);
|
||||
color: var(--accent-color-text);
|
||||
|
||||
&::before {
|
||||
content: "✓";
|
||||
font-weight: bold;
|
||||
margin-inline-end: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time {
|
||||
@extend small;
|
||||
|
||||
grid-area: time;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
main {
|
||||
grid-area: post;
|
||||
|
||||
p:first-child {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
@extend small;
|
||||
|
||||
grid-area: interactions;
|
||||
|
||||
.faves {
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
color: red;
|
||||
content: "♥";
|
||||
font-size: 2rem;
|
||||
margin-inline-end: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
display: inline;
|
||||
height: 1.25em;
|
||||
vertical-align: middle;
|
||||
width: 1.25em;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ellipsis::after {
|
||||
content: "…";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ bookmark:
|
||||
comments:
|
||||
host: mastodon.social
|
||||
username: fundor333
|
||||
id:
|
||||
id: 114689964896474095
|
||||
---
|
||||
|
||||
Thanks and i like the new _querystring_ tag
|
||||
|
||||
@@ -25,7 +25,7 @@ bookmark:
|
||||
comments:
|
||||
host: mastodon.social
|
||||
username: fundor333
|
||||
id:
|
||||
id: 114690259109867675
|
||||
---
|
||||
|
||||
I have a friend who read my blog using my feed. And sometime he pings me for some problem with the feed, like a drop of all the article as new
|
||||
|
||||
@@ -3,19 +3,16 @@
|
||||
<hr>
|
||||
<h3>Comments</h3>
|
||||
|
||||
<p>To reply to this post, you can send a <a href="https://indieweb.org/Webmention" target="_blank">Webmention</a> or you can toot me at <a href="https://mastodon.social/@fundor333">fundor333@mastodon.social</a>
|
||||
|
||||
{{ with .Params.comments }}
|
||||
{{if .id}}
|
||||
<p>With an account on the Fediverse or Mastodon, you can respond to this <a href="https://{{ .host }}/@{{ .username }}/{{ .id }}">post</a>. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.</p>
|
||||
{{end}}
|
||||
{{ end }}
|
||||
|
||||
<br>
|
||||
|
||||
<p>To reply to this post, you can send a <a href="https://indieweb.org/Webmention" target="_blank">Webmention</a> or you can toot me at <a href="https://mastodon.social/@fundor333" target="_blank">fundor333@mastodon.social</a>
|
||||
|
||||
{{ partial "webmention" . }}
|
||||
|
||||
{{ $params := .Params.comments }}
|
||||
{{ with .Params.comments.id}}
|
||||
{{ partial "mastodon" $params }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<a href='https://brid.gy/publish/bluesky'></a>
|
||||
<a href='https://brid.gy/publish/mastodon'></a>
|
||||
{{end}}
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
<div class="footer_social-icons flex">
|
||||
{{- partial "socialIcons.html" site.Params.socialIcons -}}
|
||||
<p class="flex justify-center">
|
||||
<a href='https://webring.recurse.com' target='_blank'>
|
||||
<img loading="lazy" src='https://webring.recurse.com/icon.png' width="30" height="30" />
|
||||
</a>
|
||||
<a href='https://webring.xxiivv.com/#random' target='_blank'>
|
||||
<img loading="lazy" width=" 30" height="30" src='https://webring.xxiivv.com/icon.white.svg' />
|
||||
</a>
|
||||
|
||||
190
layouts/partials/mastodon.html
Normal file
190
layouts/partials/mastodon.html
Normal file
@@ -0,0 +1,190 @@
|
||||
|
||||
|
||||
<section id="comments" class="article-content">
|
||||
<p>With an account on the Fediverse or Mastodon, you can respond to this <a target="_blank" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">post</a>. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.</p>
|
||||
<p>Learn how this is implemented <a target="_blank" class="link" href="https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/">here.</a></p>
|
||||
|
||||
<p id="mastodon-comments-list"></p>
|
||||
<div id="comments-wrapper">
|
||||
<noscript><p>Loading comments relies on JavaScript. Try enabling JavaScript and reloading, or visit <a target="_blank" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">the original post</a> on Mastodon.</p></noscript>
|
||||
</div>
|
||||
<noscript>You need JavaScript to view the comments.</noscript>
|
||||
<script src="/js/purify.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
function escapeHtml(unsafe) {
|
||||
return unsafe
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
function emojify(input, emojis) {
|
||||
let output = input;
|
||||
|
||||
emojis.forEach(emoji => {
|
||||
let picture = document.createElement("picture");
|
||||
|
||||
let source = document.createElement("source");
|
||||
source.setAttribute("srcset", escapeHtml(emoji.url));
|
||||
source.setAttribute("media", "(prefers-reduced-motion: no-preference)");
|
||||
|
||||
let img = document.createElement("img");
|
||||
img.className = "emoji";
|
||||
img.setAttribute("src", escapeHtml(emoji.static_url));
|
||||
img.setAttribute("alt", `:${ emoji.shortcode }:`);
|
||||
img.setAttribute("title", `:${ emoji.shortcode }:`);
|
||||
img.setAttribute("width", "20");
|
||||
img.setAttribute("height", "20");
|
||||
|
||||
picture.appendChild(source);
|
||||
picture.appendChild(img);
|
||||
|
||||
output = output.replace(`:${ emoji.shortcode }:`, picture.outerHTML);
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function loadComments() {
|
||||
let commentsWrapper = document.getElementById("comments-wrapper");
|
||||
fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function(data) {
|
||||
let descendants = data['descendants'];
|
||||
if(
|
||||
descendants &&
|
||||
Array.isArray(descendants) &&
|
||||
descendants.length > 0
|
||||
) {
|
||||
commentsWrapper.innerHTML = "";
|
||||
|
||||
descendants.forEach(function(status) {
|
||||
console.log(descendants)
|
||||
if( status.account.display_name.length > 0 ) {
|
||||
status.account.display_name = escapeHtml(status.account.display_name);
|
||||
status.account.display_name = emojify(status.account.display_name, status.account.emojis);
|
||||
} else {
|
||||
status.account.display_name = status.account.username;
|
||||
};
|
||||
|
||||
let instance = "";
|
||||
if( status.account.acct.includes("@") ) {
|
||||
instance = status.account.acct.split("@")[1];
|
||||
} else {
|
||||
instance = "{{ .host }}";
|
||||
}
|
||||
|
||||
const isReply = status.in_reply_to_id !== "{{ .id }}";
|
||||
|
||||
let op = false;
|
||||
if( status.account.acct == "{{ .username }}" ) {
|
||||
op = true;
|
||||
}
|
||||
|
||||
status.content = emojify(status.content, status.emojis);
|
||||
|
||||
let avatarSource = document.createElement("source");
|
||||
avatarSource.setAttribute("srcset", escapeHtml(status.account.avatar));
|
||||
avatarSource.setAttribute("media", "(prefers-reduced-motion: no-preference)");
|
||||
|
||||
let avatarImg = document.createElement("img");
|
||||
avatarImg.className = "avatar";
|
||||
avatarImg.setAttribute("src", escapeHtml(status.account.avatar_static));
|
||||
avatarImg.setAttribute("alt", `@${ status.account.username }@${ instance } avatar`);
|
||||
|
||||
let avatarPicture = document.createElement("picture");
|
||||
avatarPicture.appendChild(avatarSource);
|
||||
avatarPicture.appendChild(avatarImg);
|
||||
|
||||
let avatar = document.createElement("a");
|
||||
avatar.className = "avatar-link";
|
||||
avatar.setAttribute("href", status.account.url);
|
||||
avatar.setAttribute("rel", "external nofollow");
|
||||
avatar.setAttribute("title", `View profile at @${ status.account.username }@${ instance }`);
|
||||
avatar.appendChild(avatarPicture);
|
||||
|
||||
let instanceBadge = document.createElement("a");
|
||||
instanceBadge.className = "instance";
|
||||
instanceBadge.setAttribute("href", status.account.url);
|
||||
instanceBadge.setAttribute("title", `@${ status.account.username }@${ instance }`);
|
||||
instanceBadge.setAttribute("rel", "external nofollow");
|
||||
instanceBadge.textContent = instance;
|
||||
|
||||
let display = document.createElement("span");
|
||||
display.className = "display";
|
||||
display.setAttribute("itemprop", "author");
|
||||
display.setAttribute("itemtype", "http://schema.org/Person");
|
||||
display.innerHTML = status.account.display_name;
|
||||
|
||||
let header = document.createElement("header");
|
||||
header.className = "author";
|
||||
header.appendChild(display);
|
||||
header.appendChild(instanceBadge);
|
||||
|
||||
let permalink = document.createElement("a");
|
||||
permalink.setAttribute("href", status.url);
|
||||
permalink.setAttribute("itemprop", "url");
|
||||
permalink.setAttribute("title", `View comment at ${ instance }`);
|
||||
permalink.setAttribute("rel", "external nofollow");
|
||||
permalink.textContent = new Date( status.created_at ).toLocaleString('en-US', {
|
||||
dateStyle: "long",
|
||||
timeStyle: "short",
|
||||
});
|
||||
|
||||
let timestamp = document.createElement("time");
|
||||
timestamp.setAttribute("datetime", status.created_at);
|
||||
timestamp.appendChild(permalink);
|
||||
|
||||
let main = document.createElement("main");
|
||||
main.setAttribute("itemprop", "text");
|
||||
main.innerHTML = status.content;
|
||||
|
||||
let interactions = document.createElement("footer");
|
||||
if(status.favourites_count > 0) {
|
||||
let faves = document.createElement("a");
|
||||
faves.className = "faves";
|
||||
faves.setAttribute("href", `${ status.url }/favourites`);
|
||||
faves.setAttribute("title", `Favorites from ${ instance }`);
|
||||
faves.textContent = status.favourites_count;
|
||||
|
||||
interactions.appendChild(faves);
|
||||
}
|
||||
|
||||
let comment = document.createElement("article");
|
||||
comment.id = `comment-${ status.id }`;
|
||||
comment.className = isReply ? "comment comment-reply" : "comment";
|
||||
comment.setAttribute("itemprop", "comment");
|
||||
comment.setAttribute("itemtype", "http://schema.org/Comment");
|
||||
comment.appendChild(avatar);
|
||||
comment.appendChild(header);
|
||||
comment.appendChild(timestamp);
|
||||
comment.appendChild(main);
|
||||
comment.appendChild(interactions);
|
||||
|
||||
if(op === true) {
|
||||
comment.classList.add("op");
|
||||
|
||||
avatar.classList.add("op");
|
||||
avatar.setAttribute(
|
||||
"title",
|
||||
"Blog post author; " + avatar.getAttribute("title")
|
||||
);
|
||||
|
||||
instanceBadge.classList.add("op");
|
||||
instanceBadge.setAttribute(
|
||||
"title",
|
||||
"Blog post author: " + instanceBadge.getAttribute("title")
|
||||
);
|
||||
}
|
||||
|
||||
commentsWrapper.innerHTML += DOMPurify.sanitize(comment.outerHTML);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", loadComments);
|
||||
</script>
|
||||
</section>
|
||||
@@ -1 +1 @@
|
||||
.author{margin:0}.center-img{display:flex;justify-content:center;width:80%}.menu .trigger{float:left;display:flex;align-items:center}@media screen and (max-width:768px){.menu .menu-icon{position:relative}}@keyframes enterIn{0%{opacity:0}100%{opacity:100}}@media only screen and (min-width:768px){#pridecodes-code-corner-svg{width:150px}}@media only screen and (max-width:767px){#pridecodes-code-corner-svg{width:75px}}#pridecodes-code-corner-svg{animation:enterIn 2s;transition:all .2s ease-in-out}#pridecodes-code-corner-svg:hover{transform:scale(1.1);transform-origin:left top}
|
||||
@charset "UTF-8";:root{--blockquote-border-size:4px;--blockquote-background-color:rgb(248 248 248);--heading-border-size:4px;--link-background-color:189, 195, 199;--link-background-opacity:0.5;--link-background-opacity-hover:0.7;--pre-background-color:#272822;--pre-text-color:#f8f8f2;--code-background-color:rgba(0, 0, 0, 0.12);--code-text-color:#808080;--table-border-color:#dadada;--tr-even-background-color:#efefee}@media(prefers-color-scheme:dark){:root{--code-background-color:#272822;--code-text-color:rgba(255, 255, 255, 0.9);--table-border-color:#717171;--tr-even-background-color:#545454;--blockquote-background-color:rgb(75 75 75)}}.author{margin:0}.center-img{display:flex;justify-content:center;width:80%}.menu .trigger{float:left;display:flex;align-items:center}@media screen and (max-width:768px){.menu .menu-icon{position:relative}}@keyframes enterIn{0%{opacity:0}100%{opacity:100}}@media only screen and (min-width:768px){#pridecodes-code-corner-svg{width:150px}}@media only screen and (max-width:767px){#pridecodes-code-corner-svg{width:75px}}#pridecodes-code-corner-svg{animation:enterIn 2s;transition:all .2s ease-in-out}#pridecodes-code-corner-svg:hover{transform:scale(1.1);transform-origin:left top}small,section#comments .comment footer,section#comments .comment time,aside p{font-size:smaller;opacity:.9}section#comments #comments-wrapper{margin:1.5em 0;padding:0 var(--card-padding)}section#comments .comment{display:grid;column-gap:1rem;grid-template-areas:"avatar name" "avatar time" "avatar post" "...... interactions";grid-template-columns:min-content;justify-items:start;margin:0 auto 0 -1em;padding:.5em}section#comments .comment.comment-reply{margin:0 auto 0 1em}section#comments .comment .avatar-link{grid-area:avatar;height:4rem;position:relative;width:4rem}section#comments .comment .avatar-link .avatar{height:100%;width:100%;border-radius:20%}section#comments .comment .avatar-link.op::after{background-color:var(--accent-color);border-radius:50%;bottom:-.25rem;color:var(--accent-color-text);content:"✓";display:block;font-size:1.25rem;font-weight:700;height:1.5rem;line-height:1.5rem;position:absolute;right:-.25rem;text-align:center;width:1.5rem}section#comments .comment .author{align-items:center;display:flex;font-weight:700;gap:.5em;grid-area:name}section#comments .comment .author .instance{background-color:var(--code-background-color);border-radius:9999px;color:var(--neutral);font-size:smaller;font-weight:400;padding:.25em .75em}section#comments .comment .author .instance:hover{opacity:.8;text-decoration:none}section#comments .comment .author .instance.op{background-color:var(--code-background-color);color:var(--accent-color-text)}section#comments .comment .author .instance.op::before{content:"✓";font-weight:700;margin-inline-end:.25em}section#comments .comment time{grid-area:time;line-height:1.5rem}section#comments .comment main{grid-area:post}section#comments .comment main p:first-child{margin-top:.25em}section#comments .comment main p:last-child{margin-bottom:0}section#comments .comment footer{grid-area:interactions}section#comments .comment footer .faves{color:inherit}section#comments .comment footer .faves:hover{opacity:.8;text-decoration:none}section#comments .comment footer .faves::before{color:red;content:"♥";font-size:2rem;margin-inline-end:.25em}section#comments .comment .emoji{display:inline;height:1.25em;vertical-align:middle;width:1.25em}section#comments .comment .invisible{display:none}section#comments .comment .ellipsis::after{content:"…"}
|
||||
@@ -1 +1 @@
|
||||
{"Target":"add.min.1614b22ffc753c46d640698bbd7b8e1d6b1b0a31e41720333709b996afe4207d.css","MediaType":"text/css","Data":{"Integrity":"sha256-FhSyL/x1PEbWQGmLvXuOHWsbCjHkFyAzNwm5lq/kIH0="}}
|
||||
{"Target":"add.min.0708d69cf4c633cfe5d60afda02ceb7004fb0e5a4c21c84212b5c96068fbc416.css","MediaType":"text/css","Data":{"Integrity":"sha256-BwjWnPTGM8/l1gr9oCzrcAT7DlpMIchCErXJYGj7xBY="}}
|
||||
@@ -4,7 +4,6 @@ from rich.console import Console
|
||||
from rich.text import Text
|
||||
|
||||
feed_url = [
|
||||
"https://micro.fundor333.com/index.xml",
|
||||
"http://fundor333.com/index.xml",
|
||||
]
|
||||
|
||||
|
||||
3
static/js/purify.min.js
vendored
Normal file
3
static/js/purify.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user