Compare commits
15
Commits
c7b9f9e67d
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebee3479b1
|
||
|
|
ca4231f8b0
|
||
|
|
a28cc7cd39
|
||
|
|
9d6cc301e8
|
||
|
|
2b68602f86
|
||
|
|
32f457b4cd
|
||
|
|
693bc08e61
|
||
|
|
be9686d40e
|
||
|
|
5435e0c8c0
|
||
|
|
e3df8db9bb
|
||
|
|
719012bb08
|
||
|
|
74e9f9feaf
|
||
|
|
346f3de193
|
||
|
|
54dd6d2a17
|
||
|
|
90e8a3b2a5
|
@@ -1,6 +1,8 @@
|
|||||||
# Source
|
# sd.ai Ghost Theme
|
||||||
|
|
||||||
The default theme for [Ghost](http://github.com/tryghost/ghost/). This is the latest development version of Source! If you're just looking to download the latest release, head over to the [releases](https://github.com/TryGhost/Source/releases) page.
|
Forked from [Source](https://github.com/TryGhost/Source) - the default theme for [Ghost](http://github.com/tryghost/ghost/).
|
||||||
|
|
||||||
|
Styles the site as it looked previously and adds Mastodon support and a theme switcher.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,89 @@
|
|||||||
|
.tootlink-tip {
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 1em;
|
||||||
|
padding-top: 0.3em;
|
||||||
|
}
|
||||||
|
.mastodon-comments-top {
|
||||||
|
padding-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
.mastodon-comment {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border-radius: var(--card-border-radius);
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
display: flex;
|
||||||
|
border-top: 1px solid var(--background-secondary);
|
||||||
|
.mastodon-body {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.mastodon-avatar {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.mastodon-avatar img {
|
||||||
|
margin-right: 1rem;
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
.mastodon-meta {
|
||||||
|
padding-top: 0;
|
||||||
|
display: flex;
|
||||||
|
.mastodon-author {
|
||||||
|
flex-grow: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
.mastodon-author-uid {
|
||||||
|
font-size: 80%;
|
||||||
|
color: var(--color-secondary-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.toot-link {
|
||||||
|
flex-shrink: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mastodon-comment-content {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.disabled {
|
||||||
|
color: var(--color-secondary-text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span.tootlink {
|
||||||
|
font-size: 0.7em;
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--background-secondary)
|
||||||
|
}
|
||||||
|
a.date {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--color-secondary-text)
|
||||||
|
}
|
||||||
|
span.tootlink::after {
|
||||||
|
content: "\f0c5";
|
||||||
|
font-family: "Font Awesome 6 Free";
|
||||||
|
font-weight: 900;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
.tootClick {
|
||||||
|
animation: tootClickFrames .6s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes tootClickFrames {
|
||||||
|
0% {
|
||||||
|
background-color: var(--background-secondary);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mastodon-emoji {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
.mastodon-comment-content p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
#toot-link-top {
|
||||||
|
color: var(--ghost-accent-color);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/* PrismJS 1.29.0
|
||||||
|
https://prismjs.com/download.html#themes=prism-twilight&languages=markup+css+clike+javascript+bash+go+go-module+handlebars+json+markup-templating+ruby+typescript+yaml&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard */
|
||||||
|
code[class*=language-],pre[class*=language-]{color:#fff;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;text-shadow:0 -.1em .2em #000;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}:not(pre)>code[class*=language-],pre[class*=language-]{background:#141414}pre[class*=language-]{border-radius:.5em;border:.3em solid #545454;box-shadow:1px 1px .5em #000 inset;margin:.5em 0;overflow:auto;padding:1em}pre[class*=language-]::-moz-selection{background:#27292a}pre[class*=language-]::selection{background:#27292a}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:hsla(0,0%,93%,.15)}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:hsla(0,0%,93%,.15)}:not(pre)>code[class*=language-]{border-radius:.3em;border:.13em solid #545454;box-shadow:1px 1px .3em -.1em #000 inset;padding:.15em .2em .05em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#777}.token.punctuation{opacity:.7}.token.namespace{opacity:.7}.token.boolean,.token.deleted,.token.number,.token.tag{color:#ce6849}.token.builtin,.token.constant,.token.keyword,.token.property,.token.selector,.token.symbol{color:#f9ed99}.language-css .token.string,.style .token.string,.token.attr-name,.token.attr-value,.token.char,.token.entity,.token.inserted,.token.operator,.token.string,.token.url,.token.variable{color:#909e6a}.token.atrule{color:#7385a5}.token.important,.token.regex{color:#e8c062}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.language-markup .token.attr-name,.language-markup .token.punctuation,.language-markup .token.tag{color:#ac885c}.token{position:relative;z-index:1}.line-highlight.line-highlight{background:hsla(0,0%,33%,.25);background:linear-gradient(to right,hsla(0,0%,33%,.1) 70%,hsla(0,0%,33%,0));border-bottom:1px dashed #545454;border-top:1px dashed #545454;margin-top:.75em;z-index:0}.line-highlight.line-highlight:before,.line-highlight.line-highlight[data-end]:after{background-color:#8693a6;color:#f4f1ef}
|
||||||
|
pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}@media print{.line-highlight{-webkit-print-color-adjust:exact;color-adjust:exact}}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}pre[id].linkable-line-numbers span.line-numbers-rows{pointer-events:all}pre[id].linkable-line-numbers span.line-numbers-rows>span:before{cursor:pointer}pre[id].linkable-line-numbers span.line-numbers-rows>span:hover:before{background-color:rgba(128,128,128,.2)}
|
||||||
|
pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
|
||||||
|
div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
|
||||||
+20
-59
@@ -47,6 +47,9 @@ production stylesheet in assets/built/screen.css
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "mastodon.css";
|
||||||
|
@import "prism.css";
|
||||||
|
|
||||||
/* 1. Variables
|
/* 1. Variables
|
||||||
/* ---------------------------------------------------------- */
|
/* ---------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -62,10 +65,10 @@ production stylesheet in assets/built/screen.css
|
|||||||
--color-secondary-text: rgb(0 0 0 / 0.5);
|
--color-secondary-text: rgb(0 0 0 / 0.5);
|
||||||
--color-border: rgb(0 0 0 / 0.08);
|
--color-border: rgb(0 0 0 / 0.08);
|
||||||
--color-dark-border: rgb(0 0 0 / 0.5);
|
--color-dark-border: rgb(0 0 0 / 0.5);
|
||||||
--font-sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
--font-sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif, "Font Awesome 6 Free", "Font Awesome 6 Brands";
|
||||||
--font-serif: "EB Garamond", Georgia, Times, serif;
|
--font-serif: "EB Garamond", Georgia, Times, serif, "Font Awesome 6 Free", "Font Awesome 6 Brands";
|
||||||
--font-serif-alt: Georgia, Times, serif;
|
--font-serif-alt: Georgia, Times, serif, "Font Awesome 6 Free", "Font Awesome 6 Brands";
|
||||||
--font-mono: "JetBrains Mono", Menlo, Consolas, Monaco, "Liberation Mono", "Lucida Console", monospace;
|
--font-mono: "JetBrains Mono", Menlo, Consolas, Monaco, "Liberation Mono", "Lucida Console", monospace, "Font Awesome 6 Free", "Font Awesome 6 Brands";
|
||||||
--container-width: 1320px;
|
--container-width: 1320px;
|
||||||
--container-gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);
|
--container-gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);
|
||||||
--grid-gap: 42px;
|
--grid-gap: 42px;
|
||||||
@@ -971,12 +974,10 @@ Search LOGO Login Subscribe
|
|||||||
}
|
}
|
||||||
|
|
||||||
.gh-card-tag {
|
.gh-card-tag {
|
||||||
display: none;
|
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gh-card-title {
|
.gh-card-title {
|
||||||
@@ -1017,6 +1018,10 @@ Search LOGO Login Subscribe
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gh-card-wrapper > .gh-card-meta:not(:empty) ~ .gh-card-meta:not(:empty) {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
.gh-card-author + .gh-card-date::before {
|
.gh-card-author + .gh-card-date::before {
|
||||||
content: "—";
|
content: "—";
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
@@ -1955,59 +1960,6 @@ Search LOGO Login Subscribe
|
|||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mastodon-comment {
|
|
||||||
background-color: var(--background-color);
|
|
||||||
border-radius: var(--card-border-radius);
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
display: flex;
|
|
||||||
border-top: 1px solid var(--background-secondary);
|
|
||||||
.mastodon-body {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
.mastodon-avatar {
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
.mastodon-avatar img {
|
|
||||||
margin-right: 1rem;
|
|
||||||
min-width: 60px;
|
|
||||||
}
|
|
||||||
.mastodon-meta {
|
|
||||||
padding-top: 0;
|
|
||||||
display: flex;
|
|
||||||
.mastodon-author {
|
|
||||||
flex-grow: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
.mastodon-author-uid {
|
|
||||||
font-size: 80%;
|
|
||||||
color: var(--ghost-accent-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.toot-link {
|
|
||||||
flex-shrink: 1;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mastodon-comment-content {
|
|
||||||
padding-top: 10px;
|
|
||||||
.tootlink {
|
|
||||||
font-size: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disabled {
|
|
||||||
color: var(--ghost-accent-color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mastodon-emoji {
|
|
||||||
display: inline-block;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
.mastodon-comment-content p:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 14. Post/page
|
/* 14. Post/page
|
||||||
/* ---------------------------------------------------------- */
|
/* ---------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -2022,15 +1974,24 @@ Search LOGO Login Subscribe
|
|||||||
.gh-article-header {
|
.gh-article-header {
|
||||||
margin: clamp(40px, 3.64vw + 25.45px, 72px) 0 40px;
|
margin: clamp(40px, 3.64vw + 25.45px, 72px) 0 40px;
|
||||||
}
|
}
|
||||||
|
.gh-article-tags {
|
||||||
|
|
||||||
|
}
|
||||||
.gh-article-tag {
|
.gh-article-tag {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.01em;
|
letter-spacing: 0.01em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
padding-right: 1em;
|
||||||
color: var(--ghost-accent-color);
|
color: var(--ghost-accent-color);
|
||||||
}
|
}
|
||||||
|
.gh-article-tag::before {
|
||||||
|
content: " ";
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
.gh-article-title {
|
.gh-article-title {
|
||||||
font-size: calc(clamp(3.4rem, 1.36vw + 2.85rem, 4.6rem) * var(--factor, 1));
|
font-size: calc(clamp(3.4rem, 1.36vw + 2.85rem, 4.6rem) * var(--factor, 1));
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
File diff suppressed because one or more lines are too long
+69
-10
@@ -1,10 +1,11 @@
|
|||||||
const MASTODON_ACCOUNT_ID = '109285376472065471'
|
const MASTODON_ACCOUNT_ID = '109285376472065471'
|
||||||
const MASTODON_HOST = 'social.sd.ai'
|
const MASTODON_HOST = 'social.sd.ai'
|
||||||
|
|
||||||
|
// Copies the text from an element to the clipboard, and flashes the element to provide visual feedback
|
||||||
async function copyElementTextToClipboard(e)
|
async function copyElementTextToClipboard(e)
|
||||||
{
|
{
|
||||||
const text = e.textContent
|
const text = e.textContent
|
||||||
await navigator.clipboard.write(text)
|
await navigator.clipboard.writeText(text)
|
||||||
|
|
||||||
e.classList.add('tootClick');
|
e.classList.add('tootClick');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -12,6 +13,7 @@ async function copyElementTextToClipboard(e)
|
|||||||
}, 600);
|
}, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanitise text content for display
|
||||||
function escapeHtml(unsafe) {
|
function escapeHtml(unsafe) {
|
||||||
return unsafe
|
return unsafe
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
@@ -21,14 +23,25 @@ function escapeHtml(unsafe) {
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMastodonContent(toots, parentElement) {
|
// renders the content - provides an array of toots, the element to add the content to and whether to show a copyable link for replies
|
||||||
|
function renderMastodonContent(toots, parentElement, showLink) {
|
||||||
|
// clear the parent element so that we can add the new content
|
||||||
|
parentElement.innerHTML = ''
|
||||||
|
// add a simple "no comments" message if there are no toots
|
||||||
if (!Array.isArray(toots) || toots.length === 0) {
|
if (!Array.isArray(toots) || toots.length === 0) {
|
||||||
document.getElementById('mastodon-comments-list').innerHTML = "<div class='mastodon-comment'>No comments (yet)!</div>"
|
document.getElementById('mastodon-comments-list').innerHTML = "<div class='mastodon-comment'>No comments (yet)!</div>"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// render each toot
|
||||||
for (const toot of toots) {
|
for (const toot of toots) {
|
||||||
|
if (toot.sensitive) {
|
||||||
|
// don't display toots marked as sensitive
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitise the toot content for display, including correctly rendering custom emojis
|
||||||
toot.account.display_name = escapeHtml(toot.account.display_name)
|
toot.account.display_name = escapeHtml(toot.account.display_name)
|
||||||
console.log(toot)
|
|
||||||
toot.account.emojis.forEach(emoji => {
|
toot.account.emojis.forEach(emoji => {
|
||||||
toot.account.display_name = toot.account.display_name.replace(`:${emoji.shortcode}:`,
|
toot.account.display_name = toot.account.display_name.replace(`:${emoji.shortcode}:`,
|
||||||
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" class="mastodon-emoji" />`);
|
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" class="mastodon-emoji" />`);
|
||||||
@@ -37,6 +50,8 @@ function renderMastodonContent(toots, parentElement) {
|
|||||||
toot.content = toot.content.replace(`:${emoji.shortcode}:`,
|
toot.content = toot.content.replace(`:${emoji.shortcode}:`,
|
||||||
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" class="mastodon-emoji" />`);
|
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" class="mastodon-emoji" />`);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// create a block of HTML content including the toot data
|
||||||
const comment =
|
const comment =
|
||||||
`<div class="mastodon-comment">
|
`<div class="mastodon-comment">
|
||||||
<div class="mastodon-avatar">
|
<div class="mastodon-avatar">
|
||||||
@@ -46,7 +61,7 @@ function renderMastodonContent(toots, parentElement) {
|
|||||||
<div class="mastodon-meta">
|
<div class="mastodon-meta">
|
||||||
<div class="mastodon-author">
|
<div class="mastodon-author">
|
||||||
<div class="mastodon-author-link">
|
<div class="mastodon-author-link">
|
||||||
<a href="${toot.account.url}" rel="nofollow">
|
<a href="${toot.account.url}" target="_blank" rel="nofollow">
|
||||||
<span>${toot.account.display_name}</span>
|
<span>${toot.account.display_name}</span>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -54,7 +69,7 @@ function renderMastodonContent(toots, parentElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="toot-link">
|
<div class="toot-link">
|
||||||
<a class="date" href="${toot.uri}" rel="nofollow">
|
<a class="date" href="${toot.uri}" rel="nofollow" target="_blank">
|
||||||
${toot.created_at.substring(0, 10)}
|
${toot.created_at.substring(0, 10)}
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -62,24 +77,68 @@ function renderMastodonContent(toots, parentElement) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="mastodon-comment-content">
|
<div class="mastodon-comment-content">
|
||||||
${toot.content}
|
${toot.content}
|
||||||
<span class="tootlink">${toot.uri}</span>
|
<span class="tootlink" ${showLink ? '' : 'style="display: none;"'}>${toot.uri}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
|
// Use DOMPurify to create a sanitised element for the toot
|
||||||
const child = DOMPurify.sanitize(comment, {'RETURN_DOM_FRAGMENT': true});
|
const child = DOMPurify.sanitize(comment, {'RETURN_DOM_FRAGMENT': true});
|
||||||
|
|
||||||
|
// make all toot links clickable
|
||||||
const links = child.querySelectorAll('.tootlink');
|
const links = child.querySelectorAll('.tootlink');
|
||||||
for (const link of links) {
|
for (const link of links) {
|
||||||
link.onclick = function() { return copyToClipboard(this); }
|
link.onclick = function() { return copyElementTextToClipboard(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insert the toot into the DOM
|
||||||
parentElement.appendChild(child);
|
parentElement.appendChild(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We set this in the "code injection" footer for any page for which we want to enable comments
|
||||||
|
let MASTODON_POST_ID
|
||||||
|
|
||||||
|
// when the page has finished loading, send a request for the toots
|
||||||
document.addEventListener("DOMContentLoaded", async (event) => {
|
document.addEventListener("DOMContentLoaded", async (event) => {
|
||||||
|
let url, isComments
|
||||||
|
// if we're being crawled, don't render comments - may help against spam
|
||||||
|
const isBot = /bot|google|baidu|bing|msn|teoma|slurp|yandex/i
|
||||||
|
.test(navigator.userAgent)
|
||||||
|
|
||||||
|
// if there is a sidebar, we're expecting to load the toots from the main account
|
||||||
if (document.getElementsByClassName('gh-sidebar').length > 0) {
|
if (document.getElementsByClassName('gh-sidebar').length > 0) {
|
||||||
|
url = `https://${MASTODON_HOST}/api/v1/accounts/${MASTODON_ACCOUNT_ID}/statuses?exclude_replies=true&exclude_reblogs=true`
|
||||||
|
}
|
||||||
|
// if there's a post ID and we're not a bot, we're expecting to load the replies from a specific toot
|
||||||
|
if (MASTODON_POST_ID && !isBot) {
|
||||||
|
url = `https://${MASTODON_HOST}/api/v1/statuses/${MASTODON_POST_ID}/context`
|
||||||
|
isComments = true
|
||||||
|
}
|
||||||
|
// find the element to append the content to - if there isn't one, we don't need to query
|
||||||
const element = document.getElementById('mastodon-comments-list')
|
const element = document.getElementById('mastodon-comments-list')
|
||||||
const response = await fetch(`https://${MASTODON_HOST}/api/v1/accounts/${MASTODON_ACCOUNT_ID}/statuses?exclude_replies=true&exclude_reblogs=true`)
|
if (url && element) {
|
||||||
const content = await response.json()
|
// populate the link to the source toot, if necessary (for replies)
|
||||||
return renderMastodonContent(content, element)
|
const linkElement = document.getElementById('toot-link-top')
|
||||||
|
const clipElement = document.getElementById('toot-link-clip')
|
||||||
|
const tootUrl = `https://${MASTODON_HOST}/@s/${MASTODON_POST_ID}`
|
||||||
|
if (linkElement) {
|
||||||
|
linkElement.href = tootUrl
|
||||||
|
}
|
||||||
|
if (clipElement) {
|
||||||
|
clipElement.innerText = tootUrl
|
||||||
|
}
|
||||||
|
// fetch the data from Mastodon
|
||||||
|
const response = await fetch(url)
|
||||||
|
let content = await response.json()
|
||||||
|
if (isComments) {
|
||||||
|
content = content.descendants
|
||||||
|
}
|
||||||
|
// render the content into the page
|
||||||
|
const header = document.getElementById('mastodon-comments-header')
|
||||||
|
if (header) {
|
||||||
|
header.style.display = ''
|
||||||
|
}
|
||||||
|
return renderMastodonContent(content, element, isComments)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ const localTheme = window.localStorage && window.localStorage.getItem("lightThem
|
|||||||
const themeToggle = document.querySelector(".theme-toggle")
|
const themeToggle = document.querySelector(".theme-toggle")
|
||||||
|
|
||||||
function changeFavicon() {
|
function changeFavicon() {
|
||||||
const src = document.documentElement.classList.contains("dark-theme") ? "/img/favicon-dark.png" : "/img/favicon.png";
|
const src = document.documentElement.classList.contains("dark-theme") ? "/assets/images/favicon-dark.png" : "/assets/images/favicon.png";
|
||||||
const link = document.createElement('link'),
|
const link = document.createElement('link'),
|
||||||
oldLink = document.getElementById('dynamic-favicon');
|
oldLink = document.getElementById('dynamic-favicon');
|
||||||
link.id = 'dynamic-favicon';
|
link.id = 'dynamic-favicon';
|
||||||
|
|||||||
+7
-22
@@ -7,6 +7,12 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/webfonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||||
|
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/webfonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||||
|
|
||||||
|
<link rel="me" href="https://social.sd.ai/@s" />
|
||||||
|
|
||||||
{{!-- Preload main styles and scripts for better performance --}}
|
{{!-- Preload main styles and scripts for better performance --}}
|
||||||
<link rel="preload" as="style" href="{{asset "built/screen.css"}}">
|
<link rel="preload" as="style" href="{{asset "built/screen.css"}}">
|
||||||
<link rel="preload" as="script" href="{{asset "built/source.js"}}">
|
<link rel="preload" as="script" href="{{asset "built/source.js"}}">
|
||||||
@@ -14,32 +20,11 @@
|
|||||||
{{!-- Theme assets - use the {{asset}} helper to reference styles & scripts, this will take care of caching and cache-busting automatically --}}
|
{{!-- Theme assets - use the {{asset}} helper to reference styles & scripts, this will take care of caching and cache-busting automatically --}}
|
||||||
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}">
|
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}">
|
||||||
|
|
||||||
{{!-- Custom background color --}}
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--background-color: {{@custom.site_background_color}}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/* The script for calculating the color contrast has been taken from
|
|
||||||
https://gomakethings.com/dynamically-changing-the-text-color-based-on-background-color-contrast-with-vanilla-js/ */
|
|
||||||
var accentColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color');
|
|
||||||
accentColor = accentColor.trim().slice(1);
|
|
||||||
var r = parseInt(accentColor.substr(0, 2), 16);
|
|
||||||
var g = parseInt(accentColor.substr(2, 2), 16);
|
|
||||||
var b = parseInt(accentColor.substr(4, 2), 16);
|
|
||||||
var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
|
|
||||||
var textColor = (yiq >= 128) ? 'dark' : 'light';
|
|
||||||
|
|
||||||
document.documentElement.className = `has-${textColor}-text`;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings, it should always be the last tag before the closing head tag --}}
|
{{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings, it should always be the last tag before the closing head tag --}}
|
||||||
{{ghost_head}}
|
{{ghost_head}}
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class="{{body_class}} has-{{#match @custom.title_font "Elegant serif"}}serif{{else match @custom.title_font "Consistent mono"}}mono{{else}}sans{{/match}}-title has-{{#match @custom.body_font "Elegant serif"}}serif{{else}}sans{{/match}}-body">
|
<body class="{{body_class}} has-sans-title has-sans-body">
|
||||||
|
|
||||||
<div class="gh-viewport">
|
<div class="gh-viewport">
|
||||||
|
|
||||||
|
|||||||
@@ -84,35 +84,6 @@
|
|||||||
],
|
],
|
||||||
"default": "Logo in the middle"
|
"default": "Logo in the middle"
|
||||||
},
|
},
|
||||||
"site_background_color": {
|
|
||||||
"type": "color",
|
|
||||||
"default": "#ffffff"
|
|
||||||
},
|
|
||||||
"header_and_footer_color": {
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"Background color",
|
|
||||||
"Accent color"
|
|
||||||
],
|
|
||||||
"default": "Background color"
|
|
||||||
},
|
|
||||||
"title_font": {
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"Modern sans-serif",
|
|
||||||
"Elegant serif",
|
|
||||||
"Consistent mono"
|
|
||||||
],
|
|
||||||
"default": "Modern sans-serif"
|
|
||||||
},
|
|
||||||
"body_font": {
|
|
||||||
"type": "select",
|
|
||||||
"options": [
|
|
||||||
"Modern sans-serif",
|
|
||||||
"Elegant serif"
|
|
||||||
],
|
|
||||||
"default": "Modern sans-serif"
|
|
||||||
},
|
|
||||||
"signup_heading": {
|
"signup_heading": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"description": "Used in your footer across your theme, defaults to site title when empty"
|
"description": "Used in your footer across your theme, defaults to site title when empty"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<footer class="gh-footer{{#match @custom.header_and_footer_color "Accent color"}} has-accent-color{{/match}} gh-outer">
|
<footer class="gh-footer gh-outer">
|
||||||
<div class="gh-footer-inner gh-inner">
|
<div class="gh-footer-inner gh-inner">
|
||||||
|
|
||||||
<div class="gh-footer-bar">
|
<div class="gh-footer-bar">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<header id="gh-navigation" class="gh-navigation is-{{#match navigationLayout "Logo on the left"}}left-logo{{else match navigationLayout "Stacked"}}stacked{{else}}middle-logo{{/match}}{{#match @custom.header_and_footer_color "Accent color"}} has-accent-color{{/match}} gh-outer">
|
<header id="gh-navigation" class="gh-navigation is-{{#match navigationLayout "Logo on the left"}}left-logo{{else match navigationLayout "Stacked"}}stacked{{else}}middle-logo{{/match}} gh-outer">
|
||||||
<div class="gh-navigation-inner gh-inner">
|
<div class="gh-navigation-inner gh-inner">
|
||||||
|
|
||||||
<div class="gh-navigation-brand">
|
<div class="gh-navigation-brand">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{{#match @custom.header_style "Highlight"}}
|
{{#match @custom.header_style "Highlight"}}
|
||||||
{{#if @custom.show_featured_posts}}
|
{{#if @custom.show_featured_posts}}
|
||||||
{{#match posts.length ">=" 4}}
|
{{#match posts.length ">=" 4}}
|
||||||
{{#get "posts" include="authors" limit="16"}}
|
{{#get "posts" include="authors,tags" limit="16"}}
|
||||||
{{#foreach posts from="5" limit="12"}}
|
{{#foreach posts from="5" limit="12"}}
|
||||||
{{> "post-card" lazyLoad=true}}
|
{{> "post-card" lazyLoad=true}}
|
||||||
{{/foreach}}
|
{{/foreach}}
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
{{/match}}
|
{{/match}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#match posts.length ">=" 10}}
|
{{#match posts.length ">=" 10}}
|
||||||
{{#get "posts" include="authors" limit="22"}}
|
{{#get "posts" include="authors,tags" limit="22"}}
|
||||||
{{#foreach posts from="11" limit="12"}}
|
{{#foreach posts from="11" limit="12"}}
|
||||||
{{> "post-card" lazyLoad=true}}
|
{{> "post-card" lazyLoad=true}}
|
||||||
{{/foreach}}
|
{{/foreach}}
|
||||||
@@ -40,14 +40,14 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
{{else match @custom.header_style "Magazine"}}
|
{{else match @custom.header_style "Magazine"}}
|
||||||
{{#match posts.length ">=" 7}}
|
{{#match posts.length ">=" 7}}
|
||||||
{{#get "posts" include="authors" limit="19"}}
|
{{#get "posts" include="authors,tags" limit="19"}}
|
||||||
{{#foreach posts from="8" limit="12"}}
|
{{#foreach posts from="8" limit="12"}}
|
||||||
{{> "post-card" lazyLoad=true}}
|
{{> "post-card" lazyLoad=true}}
|
||||||
{{/foreach}}
|
{{/foreach}}
|
||||||
{{/get}}
|
{{/get}}
|
||||||
{{/match}}
|
{{/match}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#get "posts" include="authors" limit="12"}}
|
{{#get "posts" include="authors,tags" limit="12"}}
|
||||||
{{#foreach posts}}
|
{{#foreach posts}}
|
||||||
{{> "post-card" lazyLoad=true}}
|
{{> "post-card" lazyLoad=true}}
|
||||||
{{/foreach}}
|
{{/foreach}}
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
{{!-- All posts --}}
|
{{!-- All posts --}}
|
||||||
{{#match feed "index"}}
|
{{#match feed "index"}}
|
||||||
{{#match pagination.page 2}}
|
{{#match pagination.page 2}}
|
||||||
{{#get "posts" include="authors" limit=@config.posts_per_page as |recent|}}
|
{{#get "posts" include="authors,tags" limit=@config.posts_per_page as |recent|}}
|
||||||
{{#foreach recent}}
|
{{#foreach recent}}
|
||||||
{{> "post-card"}}
|
{{> "post-card"}}
|
||||||
{{/foreach}}
|
{{/foreach}}
|
||||||
|
|||||||
@@ -17,9 +17,6 @@
|
|||||||
</figure>
|
</figure>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="gh-card-wrapper">
|
<div class="gh-card-wrapper">
|
||||||
{{#if primary_tag}}
|
|
||||||
<p class="gh-card-tag">{{primary_tag.name}}</p>
|
|
||||||
{{/if}}
|
|
||||||
<h3 class="gh-card-title is-title">{{title}}</h3>
|
<h3 class="gh-card-title is-title">{{title}}</h3>
|
||||||
{{#if excerpt}}
|
{{#if excerpt}}
|
||||||
<p class="gh-card-excerpt is-body">{{excerpt}}</p>
|
<p class="gh-card-excerpt is-body">{{excerpt}}</p>
|
||||||
@@ -31,6 +28,15 @@
|
|||||||
{{#if @custom.show_publish_date}}
|
{{#if @custom.show_publish_date}}
|
||||||
<time class="gh-card-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
|
<time class="gh-card-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
|
||||||
{{/if}}<!--
|
{{/if}}<!--
|
||||||
|
--></footer>
|
||||||
|
<footer class="gh-card-meta"><!--
|
||||||
|
--><div class="gh-card-tags">
|
||||||
|
Filed under:
|
||||||
|
{{#foreach tags}}
|
||||||
|
{{#if @index}}, {{/if}}
|
||||||
|
<span class="gh-card-tag">{{name}}</span>
|
||||||
|
{{/foreach}}
|
||||||
|
</div><!--
|
||||||
--></footer>
|
--></footer>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -9,13 +9,12 @@
|
|||||||
|
|
||||||
<header class="gh-article-header gh-canvas">
|
<header class="gh-article-header gh-canvas">
|
||||||
|
|
||||||
{{#if primary_tag}}
|
<div class="gh-article-tags">
|
||||||
<a class="gh-article-tag" href="{{primary_tag.url}}">{{primary_tag.name}}</a>
|
{{#foreach tags}}
|
||||||
{{/if}}
|
<a class="gh-article-tag" href="{{url}}">{{name}}</a>
|
||||||
|
{{/foreach}}
|
||||||
|
</div>
|
||||||
<h1 class="gh-article-title is-title">{{title}}</h1>
|
<h1 class="gh-article-title is-title">{{title}}</h1>
|
||||||
{{#if custom_excerpt}}
|
|
||||||
<p class="gh-article-excerpt is-body">{{custom_excerpt}}</p>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="gh-article-meta">
|
<div class="gh-article-meta">
|
||||||
<div class="gh-article-author-image">
|
<div class="gh-article-author-image">
|
||||||
@@ -50,6 +49,26 @@
|
|||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<section class="gh-comments gh-canvas">
|
||||||
|
|
||||||
|
<div id="mastodon-comments-header" style="display: none;">
|
||||||
|
|
||||||
|
<div class="mastodon-comments-top">
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Comments</h2>
|
||||||
|
<p>Comments powered by Mastodon. Reply to <a id="toot-link-top">this status</a> to comment.</p>
|
||||||
|
<div class="tootlink-tip">
|
||||||
|
<b>Tip:</b> paste this URL into the search bar of your Mastodon client:<br/>
|
||||||
|
<span id="toot-link-clip" class="tootlink" onclick="copyElementTextToClipboard(this)"></span> (click to copy)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<noscript><p>You need JavaScript to view the comments.</p></noscript>
|
||||||
|
<div id="mastodon-comments-list"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{{#if comments}}
|
{{#if comments}}
|
||||||
<div class="gh-comments gh-canvas">
|
<div class="gh-comments gh-canvas">
|
||||||
{{comments}}
|
{{comments}}
|
||||||
@@ -60,7 +79,7 @@
|
|||||||
|
|
||||||
{{/post}}
|
{{/post}}
|
||||||
|
|
||||||
{{#get "posts" include="authors" filter="id:-{{post.id}}" limit="4" as |next|}}
|
{{#get "posts" include="authors,tags" filter="id:-{{post.id}}" limit="4" as |next|}}
|
||||||
{{#if next}}
|
{{#if next}}
|
||||||
<section class="gh-container is-grid gh-outer">
|
<section class="gh-container is-grid gh-outer">
|
||||||
<div class="gh-container-inner gh-inner">
|
<div class="gh-container-inner gh-inner">
|
||||||
|
|||||||
Reference in New Issue
Block a user