feat: add support for Isso comments

This commit is contained in:
welpo
2023-07-26 01:47:26 +02:00
parent e1dfd2ea07
commit 9a98789922
13 changed files with 561 additions and 31 deletions

322
static/isso.css Normal file
View File

@@ -0,0 +1,322 @@
/* ========================================================================== */
/* Generic styling */
/* ========================================================================== */
#isso-thread * {
/* Reset */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* ========================================================================== */
/* Thread heading area */
/* ========================================================================== */
#isso-thread {
padding: 0;
margin: 0 auto;
color: var(--text-color);
font-family: var(--sans-serif-font);
font-size: 0.9em;
width: 100%;
}
h4.isso-thread-heading {
font-size: 1.2rem;
color: var(--text-color);
padding-bottom: 0.2em;
}
.isso-feedlink {
float: right;
padding-left: 1em;
}
.isso-feedlink a {
font-size: 0.8em;
vertical-align: bottom;
}
/* ========================================================================== */
/* Comments */
/* ========================================================================== */
.isso-comment {
max-width: 68em;
margin: 0 auto;
}
.isso-preview .isso-comment {
padding-top: 0;
margin: 0;
}
.isso-comment:not(:first-of-type),
.isso-follow-up .isso-comment {
border-top: 1px solid rgba(0, 0, 0, 0.1);
margin-bottom: 0.5em;
}
.isso-avatar {
display: block;
float: left;
margin: 0.95em 0.95em 0;
}
.isso-avatar svg {
max-width: 48px;
max-height: 48px;
width: 100%;
height: 100%;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.isso-text-wrapper {
display: block;
padding: 0.3em;
}
.isso-follow-up {
padding-left: calc(7% + 20px);
}
.isso-comment-footer {
font-size: 0.95em;
}
.isso-comment-header {
font-size: 0.85em;
}
.isso-comment-header a {
text-decoration: none;
}
/* Only for comment header, spacer between up-/downvote should have no padding */
.isso-comment-header .isso-spacer {
padding: 0 6px;
}
.isso-spacer,
.isso-permalink,
.isso-note,
.isso-parent {
color: var(--meta-color);
font-weight: normal;
text-shadow: none;
}
.isso-spacer:hover,
.isso-permalink:hover,
.isso-note:hover,
.isso-parent:hover {
color: #606060;
}
.isso-note {
float: right;
}
.isso-author {
font-weight: 500;
color: var(--text-color);
}
.isso-page-author-suffix {
font-weight: bold;
color: var(--text-color-high-contrast);
}
/* Style author comments and replies */
.isso-is-page-author > .isso-text-wrapper {
background-color: var(--bg-1);
}
.isso-textarea,
.isso-preview {
width: 100%;
padding: 10px;
border: none;
font-family: var(--sans-serif-font);
color: var(--text-color);
background-color: var(--bg-2);
font-size: 0.8em;
}
.isso-text p {
margin-top: -0.4em;
}
.isso-text p:last-child {
margin-bottom: 0.2em;
}
.isso-text h1,
.isso-text h2,
.isso-text h3,
.isso-text h4,
.isso-text h5,
.isso-text h6 {
font-size: 130%;
font-weight: bold;
}
.isso-comment-footer {
font-size: 0.80em;
color: gray;
clear: left;
}
.isso-feedlink,
.isso-comment-footer a {
font-weight: bold;
text-decoration: none;
margin: 0.4em;
padding: 0.1em;
}
.isso-comment-footer .isso-votes {
color: gray;
}
.isso-upvote svg,
.isso-downvote svg {
position: relative;
top: .2em;
}
/* Reply postbox under existing comment */
.isso-comment .isso-postbox {
margin-top: 0.8em;
}
.isso-comment.isso-no-votes > * > .isso-comment-footer .isso-votes {
display: none;
}
/* ========================================================================== */
/* Postbox */
/* ========================================================================== */
.isso-postbox {
max-width: 68em;
margin: 0 auto 2em;
clear: right;
}
.isso-form-wrapper {
display: flex;
flex-direction: column;
}
.isso-textarea,
.isso-preview {
margin-top: 0.2em;
width: 100%;
border: var(--border-color);
border-radius: 5px;
box-shadow: 0 0 2px #888;
}
.isso-textarea {
outline: 0;
width: 100%;
resize: none;
}
.isso-form-wrapper input[type=checkbox] {
vertical-align: middle;
position: relative;
bottom: 1px;
margin-left: 0;
}
.isso-notification-section {
font-size: 0.90em;
padding-top: .3em;
display: none;
padding-bottom: 10px;
}
.isso-auth-section {
display: flex;
flex-direction: row;
}
.isso-textarea:focus,
.isso-auth-section input:focus {
border-color: rgba(0, 0, 0, 0.8);
}
.isso-input-wrapper {
display: inline-block;
position: relative;
font-family: var(--sans-serif-font);
font-size: 0.9em;
max-width: 25%;
margin: 0;
}
.isso-input-wrapper input {
max-width: 100%;
line-height: 1.2em;
padding: 0.3em;
border-radius: 5px;
width: 90%;
font-family: var(--sans-serif-font);
color: var(--text-color);
background-color: var(--bg-2);
border: var(--border-color);
box-shadow: 0 0 2px #888;
}
.isso-input-wrapper label {
display: inline-block;
line-height: 1.4em;
height: 1.4em;
}
.isso-post-action {
display: block;
margin: 0 auto;
align-self: flex-end;
margin-bottom: 0.3em;
}
.isso-post-action > input {
font-size: 0.8rem;
background-color: var(--primary-color);
color: var(--background-color);
border: none;
border-radius: 5px;
cursor: pointer;
padding: 0.6em 1em;
margin: 0.1em;
cursor: pointer;
}
.isso-post-action > input:hover {
background-color: var(--primary-color-dark);
}
/* ========================================================================== */
/* Postbox (preview mode) */
/* ========================================================================== */
.isso-preview,
.isso-post-action input[name="edit"],
.isso-postbox.isso-preview-mode > .isso-form-wrapper input[name="preview"],
.isso-postbox.isso-preview-mode > .isso-form-wrapper .isso-textarea {
display: none;
}
.isso-postbox.isso-preview-mode > .isso-form-wrapper .isso-preview {
display: block;
}
.isso-postbox.isso-preview-mode > .isso-form-wrapper input[name="edit"] {
display: inline;
}
.isso-preview {
background-color: var(--bg-0);
background: repeating-linear-gradient(
-45deg,
var(--bg-0),
var(--bg-0) 10px,
var(--bg-2) 10px,
var(--bg-2) 20px
);
}
/* ========================================================================== */
/* Animations */
/* ========================================================================== */
/* "target" means the comment that's being linked to, for example:
* https://example.com/blog/example/#isso-15
*/
.isso-target {
animation: isso-target-fade 5s ease-out;
}
@keyframes isso-target-fade {
0% { background-color: var(--divider-color) }
}
/* ========================================================================== */
/* Media queries */
/* ========================================================================== */
@media screen and (max-width:600px) {
.isso-auth-section {
flex-direction: column;
text-align: center;
}
.isso-input-wrapper {
display: block;
max-width: 100%;
margin: 0 0 .4em;
}
.isso-input-wrapper input {
width: 100%;
}
.isso-post-action {
margin: 0.4em auto;
width: 60%;
}
}

1
static/isso.min.css vendored Normal file
View File

@@ -0,0 +1 @@
#isso-thread *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#isso-thread{padding:0;margin:0 auto;color:var(--text-color);font-family:var(--sans-serif-font);font-size:.9em;width:100%}h4.isso-thread-heading{font-size:1.2rem;color:var(--text-color);padding-bottom:.2em}.isso-feedlink,.isso-note{float:right}.isso-feedlink a{font-size:.8em;vertical-align:bottom}.isso-comment{max-width:68em;margin:0 auto}.isso-preview .isso-comment{padding-top:0;margin:0}.isso-comment:not(:first-of-type),.isso-follow-up .isso-comment{border-top:1px solid rgba(0,0,0,.1);margin-bottom:.5em}.isso-avatar{display:block;float:left;margin:.95em .95em 0}.isso-avatar svg{max-width:48px;max-height:48px;width:100%;height:100%;border:1px solid rgba(0,0,0,.2);border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.1)}.isso-text-wrapper{display:block;padding:.3em}.isso-follow-up{padding-left:calc(7% + 20px)}.isso-comment-header{font-size:.85em}.isso-comment-header a{text-decoration:none}.isso-comment-header .isso-spacer{padding:0 6px}.isso-note,.isso-parent,.isso-permalink,.isso-spacer{color:var(--meta-color);font-weight:400;text-shadow:none}.isso-note:hover,.isso-parent:hover,.isso-permalink:hover,.isso-spacer:hover{color:#606060}.isso-author{font-weight:500;color:var(--text-color)}.isso-page-author-suffix{font-weight:700;color:var(--text-color-high-contrast)}.isso-input-wrapper input,.isso-preview,.isso-textarea{font-family:var(--sans-serif-font);color:var(--text-color);background-color:var(--bg-2)}.isso-is-page-author>.isso-text-wrapper{background-color:var(--bg-1)}.isso-preview,.isso-textarea{padding:10px;border:none;font-size:.8em}.isso-text p{margin-top:-.4em}.isso-text p:last-child{margin-bottom:.2em}.isso-text h1,.isso-text h2,.isso-text h3,.isso-text h4,.isso-text h5,.isso-text h6{font-size:130%;font-weight:700}.isso-comment-footer{font-size:.8em;color:gray;clear:left}.isso-comment-footer a,.isso-feedlink{font-weight:700;text-decoration:none;margin:.4em;padding:.1em}.isso-comment-footer .isso-votes{color:gray}.isso-downvote svg,.isso-upvote svg{position:relative;top:.2em}.isso-comment .isso-postbox{margin-top:.8em}.isso-comment.isso-no-votes>*>.isso-comment-footer .isso-votes,.isso-post-action input[name=edit],.isso-postbox.isso-preview-mode>.isso-form-wrapper .isso-textarea,.isso-postbox.isso-preview-mode>.isso-form-wrapper input[name=preview],.isso-preview{display:none}.isso-postbox{max-width:68em;margin:0 auto 2em;clear:right}.isso-form-wrapper{display:flex;flex-direction:column}.isso-preview,.isso-textarea{margin-top:.2em;width:100%;border:var(--border-color);border-radius:5px;box-shadow:0 0 2px #888}.isso-textarea{outline:0;width:100%;resize:none}.isso-form-wrapper input[type=checkbox]{vertical-align:middle;position:relative;bottom:1px;margin-left:0}.isso-notification-section{font-size:.9em;padding-top:.3em;display:none;padding-bottom:10px}.isso-auth-section{display:flex;flex-direction:row}.isso-auth-section input:focus,.isso-textarea:focus{border-color:rgba(0,0,0,.8)}.isso-input-wrapper{display:inline-block;position:relative;font-family:var(--sans-serif-font);font-size:.9em;max-width:25%;margin:0}.isso-input-wrapper input{max-width:100%;line-height:1.2em;padding:.3em;border-radius:5px;width:90%;border:var(--border-color);box-shadow:0 0 2px #888}.isso-input-wrapper label{display:inline-block;line-height:1.4em;height:1.4em}.isso-post-action{display:block;margin:0 auto .3em;align-self:flex-end}.isso-post-action>input{font-size:.8rem;background-color:var(--primary-color);color:var(--background-color);border:none;border-radius:5px;padding:.6em 1em;margin:.1em;cursor:pointer}.isso-post-action>input:hover{background-color:var(--primary-color-dark)}.isso-postbox.isso-preview-mode>.isso-form-wrapper .isso-preview{display:block}.isso-postbox.isso-preview-mode>.isso-form-wrapper input[name=edit]{display:inline}.isso-preview{background-color:var(--bg-0);background:repeating-linear-gradient(-45deg,var(--bg-0),var(--bg-0) 10px,var(--bg-2) 10px,var(--bg-2) 20px)}.isso-target{animation:5s ease-out isso-target-fade}@keyframes isso-target-fade{0%{background-color:var(--divider-color)}}@media screen and (max-width:600px){.isso-auth-section{flex-direction:column;text-align:center}.isso-input-wrapper{display:block;max-width:100%;margin:0 0 .4em}.isso-input-wrapper input{width:100%}.isso-post-action{margin:.4em auto;width:60%}}

80
static/js/isso.js Normal file
View File

@@ -0,0 +1,80 @@
// Function to initialise Isso.
function initIsso() {
// Get the div that will contain the comments.
const commentsDiv = document.querySelector('.comments');
if (commentsDiv) {
// Get the lazy-loading setting from the div.
const lazyLoading = commentsDiv.getAttribute('data-lazy-loading') === "true";
// If lazy-loading is enabled, create an Intersection Observer and use it.
if (lazyLoading) {
const observer = new IntersectionObserver(entries => {
// Loop over the entries.
entries.forEach(entry => {
// If the element is in the viewport, initialize Isso.
if (entry.isIntersecting) {
loadIsso(commentsDiv);
// Once the Isso is loaded, we don't need to observe the element anymore.
observer.unobserve(commentsDiv);
}
});
});
// Start observing the comments div.
observer.observe(commentsDiv);
} else {
// If lazy-loading is not enabled, initialise Isso immediately.
loadIsso(commentsDiv);
}
}
}
// Function to load Isso.
function loadIsso(commentsDiv) {
// Get the various settings from data attributes on the div.
const endpointUrl = commentsDiv.getAttribute('data-endpoint-url');
const pageId = commentsDiv.getAttribute('data-isso-id');
const title = commentsDiv.getAttribute('data-title');
const lang = commentsDiv.getAttribute('data-page-language');
const maxCommentsTop = commentsDiv.getAttribute('data-max-comments-top');
const maxCommentsNested = commentsDiv.getAttribute('data-max-comments-nested');
const avatar = commentsDiv.getAttribute('data-avatar');
const voting = commentsDiv.getAttribute('data-voting');
const hashes = commentsDiv.getAttribute('data-page-author-hashes');
// Create a new script tag that will load the Isso script.
const script = document.createElement('script');
script.src = endpointUrl + 'js/embed.min.js';
script.async = true;
// Set the various settings as data attributes on the script tag.
script.setAttribute('data-isso', endpointUrl);
script.setAttribute('data-isso-lang', lang);
script.setAttribute('data-isso-max-comments-top', maxCommentsTop);
script.setAttribute('data-isso-avatar', avatar);
script.setAttribute('data-isso-vote', voting);
script.setAttribute('data-isso-page-author-hashes', hashes);
script.setAttribute('data-isso-css', 'false');
// Set the id and data-isso-id of the Isso thread.
const section = document.createElement('section');
section.id = 'isso-thread';
section.setAttribute('data-isso-id', pageId);
section.setAttribute('data-title', title);
commentsDiv.appendChild(section);
// Add the script tag to the div.
commentsDiv.appendChild(script);
// Create a link tag for the Isso CSS.
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '/isso.min.css';
// Add the CSS link tag to the head of the document.
document.head.appendChild(link);
}
// Initialize Isso.
initIsso();

1
static/js/isso.min.js vendored Normal file
View File

@@ -0,0 +1 @@
function initIsso(){const e=document.querySelector(".comments");if(e)if("true"===e.getAttribute("data-lazy-loading")){const a=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&(loadIsso(e),a.unobserve(e))})});a.observe(e)}else loadIsso(e)}function loadIsso(t){var e=t.getAttribute("data-endpoint-url"),a=t.getAttribute("data-isso-id"),s=t.getAttribute("data-title"),i=t.getAttribute("data-page-language"),o=t.getAttribute("data-max-comments-top"),r=(t.getAttribute("data-max-comments-nested"),t.getAttribute("data-avatar")),d=t.getAttribute("data-voting"),n=t.getAttribute("data-page-author-hashes"),u=document.createElement("script"),e=(u.src=e+"js/embed.min.js",u.async=!0,u.setAttribute("data-isso",e),u.setAttribute("data-isso-lang",i),u.setAttribute("data-isso-max-comments-top",o),u.setAttribute("data-isso-avatar",r),u.setAttribute("data-isso-vote",d),u.setAttribute("data-isso-page-author-hashes",n),u.setAttribute("data-isso-css","false"),document.createElement("section")),i=(e.id="isso-thread",e.setAttribute("data-isso-id",a),e.setAttribute("data-title",s),t.appendChild(e),t.appendChild(u),document.createElement("link"));i.rel="stylesheet",i.type="text/css",i.href="/isso.min.css",document.head.appendChild(i)}initIsso();

View File

@@ -13,7 +13,7 @@ function setTheme(theme, saveToLocalStorage = false) {
localStorage.setItem("theme", theme);
}
// Dispatch a custom event for utterances and giscus.
// Dispatch a custom event for comment systems.
const event = new CustomEvent("themeChanged", {
detail: { theme: theme }
});