Compare commits

..
15 Commits
Author SHA1 Message Date
simon ebee3479b1 Load tags for the 'read more' section 2023-10-19 16:32:16 +01:00
simon ca4231f8b0 Add handlebars support for Prism 2023-10-19 16:30:19 +01:00
simon a28cc7cd39 Add comments 2023-10-19 14:51:43 +01:00
simon 9d6cc301e8 Add line before comments 2023-10-19 14:24:04 +01:00
simon 2b68602f86 Update prism 2023-10-18 18:03:54 +01:00
simon 32f457b4cd Update prism 2023-10-18 13:20:29 +01:00
simon 693bc08e61 Add all tags to output 2023-10-18 12:39:54 +01:00
simon be9686d40e Add prism and move Mastodon css to file 2023-10-18 11:24:20 +01:00
simon 5435e0c8c0 Open masto header links externally 2023-10-17 17:04:52 +01:00
simon e3df8db9bb Add fa fallback 2023-10-17 16:56:29 +01:00
simon 719012bb08 Add 'me' link for Masto 2023-10-17 16:42:16 +01:00
simon 74e9f9feaf Add favicon 2023-10-17 14:59:28 +01:00
simon 346f3de193 Remove unneeded settings 2023-10-17 14:46:43 +01:00
simon 54dd6d2a17 Mastodon improvements 2023-10-17 14:18:00 +01:00
simon 90e8a3b2a5 Update README 2023-10-17 10:19:33 +01:00
20 changed files with 271 additions and 153 deletions
+4 -2
View File
@@ -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
+89
View File
@@ -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;
}
+6
View File
@@ -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
View File
@@ -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
+70 -11
View File
@@ -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) {
const element = document.getElementById('mastodon-comments-list') url = `https://${MASTODON_HOST}/api/v1/accounts/${MASTODON_ACCOUNT_ID}/statuses?exclude_replies=true&exclude_reblogs=true`
const response = await fetch(`https://${MASTODON_HOST}/api/v1/accounts/${MASTODON_ACCOUNT_ID}/statuses?exclude_replies=true&exclude_reblogs=true`) }
const content = await response.json() // if there's a post ID and we're not a bot, we're expecting to load the replies from a specific toot
return renderMastodonContent(content, element) 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')
if (url && element) {
// populate the link to the source toot, if necessary (for replies)
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
View File
@@ -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
View File
@@ -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">
-29
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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">
+5 -5
View File
@@ -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}}
+9 -3
View File
@@ -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>
+26 -7
View File
@@ -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">