Compare commits

..
25 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
simon c7b9f9e67d Add Mastodon toots to main page 2023-10-17 10:17:37 +01:00
simon a84195497e Fix error in theme switcher 2023-10-16 19:55:08 +01:00
simon ab61ad1a67 Fix colours 2023-10-16 19:05:59 +01:00
simon 9b04b09f33 Add logo 2023-10-16 18:53:40 +01:00
simon 328473e596 Add theme switcher 2023-10-16 17:04:36 +01:00
simon a9b861a6aa Update package.json 2023-10-16 15:06:45 +01:00
Sodbileg Gansukh 4b347f1b0d v1.0.1 2023-10-11 09:31:12 +08:00
Sodbileg Gansukh dedc9cbc3d Fixed pagination not working on tag templates
refs https://github.com/TryGhost/Source/issues/10
2023-10-11 09:30:48 +08:00
Daniel Lockyer e0483fd7f4 v1.0.0 2023-10-03 13:10:09 +02:00
Daniel Lockyer 98a35f9488 Updated built assets 2023-10-03 13:09:12 +02:00
27 changed files with 551 additions and 129 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
Executable → Regular
+28 -1
View File
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}
+114 -11
View File
@@ -47,6 +47,9 @@ production stylesheet in assets/built/screen.css
*/
@import "mastodon.css";
@import "prism.css";
/* 1. Variables
/* ---------------------------------------------------------- */
@@ -62,20 +65,42 @@ production stylesheet in assets/built/screen.css
--color-secondary-text: rgb(0 0 0 / 0.5);
--color-border: rgb(0 0 0 / 0.08);
--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-serif: "EB Garamond", Georgia, Times, serif;
--font-serif-alt: Georgia, Times, serif;
--font-mono: "JetBrains Mono", Menlo, Consolas, Monaco, "Liberation Mono", "Lucida Console", monospace;
--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 Awesome 6 Free", "Font Awesome 6 Brands";
--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 Awesome 6 Free", "Font Awesome 6 Brands";
--container-width: 1320px;
--container-gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);
--grid-gap: 42px;
--card-border-radius: 5px;
}
:root.light-theme {
/* light theme color */
--background-color: #fff;
--background-secondary: #eaeaea;
--header: #fafafa;
--color-primary-text: #222;
--color-secondary-text: #999;
--border-color: #dcdcdc;
--ghost-accent-color: #007700;
}
:root.dark-theme {
/* dark theme colors */
--background-color: #292a2d;
--background-secondary: #3b3d42;
--header: #252627;
--color-primary-text: #a9a9b3;
--color-secondary-text: #73747b;
--border-color: #4a4b50;
--ghost-accent-color: #77bb77;
}
:root.has-light-text,
:is(.gh-navigation, .gh-footer).has-accent-color {
--color-lighter-gray: rgb(255 255 255 / 0.1);
--color-darker-gray: #fff;
--color-secondary-text: rgb(255 255 255 / 0.64);
--color-darker-gray: var(--color-primary-text);
--color-border: rgb(255 255 255 / 0.15);
--color-dark-border: rgb(255 255 255 / 0.5);
}
@@ -369,7 +394,7 @@ button.gh-form-input {
.gh-form {
font-size: 1.6rem;
}
.gh-form .gh-button {
padding-inline: 12px;
}
@@ -949,12 +974,10 @@ Search LOGO Login Subscribe
}
.gh-card-tag {
display: none;
margin-bottom: 4px;
font-size: 1.2rem;
font-weight: 500;
letter-spacing: 0.01em;
text-transform: uppercase;
}
.gh-card-title {
@@ -995,6 +1018,10 @@ Search LOGO Login Subscribe
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 {
content: "—";
margin-right: 4px;
@@ -1002,6 +1029,73 @@ Search LOGO Login Subscribe
/* 8. Header
/* ---------------------------------------------------------- */
.gh-navigation-logo {
display: flex;
align-items: center;
flex: 0 0 auto;
text-decoration: none;
font-weight: bold;
color: var(--color-secondary-text)
}
.logo-mark {
display: inline-flex;
align-items: center;
margin-right: 5px;
height: 0.8em;
}
.logo-text {
font-size: 0.8em;
font-family: var(--font-mono);
}
.logo-cursor {
display: inline-block;
width: 0.4em;
height: 0.8em;
background: var(--color-secondary-text);
margin-left: 5px;
border-radius: 1px;
animation: cursor 1.5s infinite;
}
.greater-icon {
width: 0.6em;
height: 0.6em;
}
.greater-icon path {
stroke: currentColor;
stroke-width: .95rem;
}
@keyframes cursor {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
#svglogo {
height: 2.5em;
width: 2.5em;
}
#svglogo use {
fill: var(--color-primary-text);
}
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
cursor: pointer;
}
.theme-toggler {
fill: currentColor;
}
.gh-header {
position: relative;
@@ -1638,12 +1732,12 @@ Search LOGO Login Subscribe
/* 11.1. With sidebar */
.gh-container.has-sidebar .gh-main {
grid-column: 1 / span 12;
grid-column: 1 / span 11;
position: relative;
}
.gh-container.has-sidebar .gh-sidebar {
grid-column: 13 / -1;
grid-column: 12 / -1;
}
.gh-container.has-sidebar .gh-main::after {
@@ -1880,15 +1974,24 @@ Search LOGO Login Subscribe
.gh-article-header {
margin: clamp(40px, 3.64vw + 25.45px, 72px) 0 40px;
}
.gh-article-tags {
}
.gh-article-tag {
margin-bottom: 12px;
font-size: 1.3rem;
font-weight: 500;
letter-spacing: 0.01em;
text-transform: uppercase;
padding-right: 1em;
color: var(--ghost-accent-color);
}
.gh-article-tag::before {
content: " ";
font-weight: 900;
font-size: 0.8em;
padding-right: 0.3em;
}
.gh-article-title {
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

+1 -1
View File
@@ -40,7 +40,7 @@
/* Infinite scroll pagination */
(function () {
if (document.body.classList.contains('paged')) {
if (!document.body.classList.contains('post-template')) {
pagination();
}
})();
File diff suppressed because one or more lines are too long
+3
View File
File diff suppressed because one or more lines are too long
+144
View File
@@ -0,0 +1,144 @@
const MASTODON_ACCOUNT_ID = '109285376472065471'
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)
{
const text = e.textContent
await navigator.clipboard.writeText(text)
e.classList.add('tootClick');
setTimeout(() => {
e.classList.remove('tootClick');
}, 600);
}
// sanitise text content for display
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
// 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) {
document.getElementById('mastodon-comments-list').innerHTML = "<div class='mastodon-comment'>No comments (yet)!</div>"
return
}
// render each toot
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.emojis.forEach(emoji => {
toot.account.display_name = toot.account.display_name.replace(`:${emoji.shortcode}:`,
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" class="mastodon-emoji" />`);
})
toot.emojis.forEach(emoji => {
toot.content = toot.content.replace(`:${emoji.shortcode}:`,
`<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 =
`<div class="mastodon-comment">
<div class="mastodon-avatar">
<img src="${escapeHtml(toot.account.avatar_static)}" height=60 width=60 alt="${escapeHtml(toot.account.display_name)}'s avatar">
</div>
<div class="mastodon-body">
<div class="mastodon-meta">
<div class="mastodon-author">
<div class="mastodon-author-link">
<a href="${toot.account.url}" target="_blank" rel="nofollow">
<span>${toot.account.display_name}</span>
</a>
<br/>
<span class="mastodon-author-uid">(@${escapeHtml(toot.account.acct === 's' ? 's@sd.ai' : toot.account.acct)})</span>
</div>
</div>
<div class="toot-link">
<a class="date" href="${toot.uri}" rel="nofollow" target="_blank">
${toot.created_at.substring(0, 10)}
</a>
<br/>
</div>
</div>
<div class="mastodon-comment-content">
${toot.content}
<span class="tootlink" ${showLink ? '' : 'style="display: none;"'}>${toot.uri}</span>
</div>
</div>
</div>`
// Use DOMPurify to create a sanitised element for the toot
const child = DOMPurify.sanitize(comment, {'RETURN_DOM_FRAGMENT': true});
// make all toot links clickable
const links = child.querySelectorAll('.tootlink');
for (const link of links) {
link.onclick = function() { return copyElementTextToClipboard(this); }
}
// insert the toot into the DOM
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) => {
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) {
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')
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)
}
})
+45
View File
@@ -0,0 +1,45 @@
// Toggle theme
const isOSLight = window.matchMedia("(prefers-color-scheme: light)").matches
const localTheme = window.localStorage && window.localStorage.getItem("lightTheme")
const themeToggle = document.querySelector(".theme-toggle")
function changeFavicon() {
const src = document.documentElement.classList.contains("dark-theme") ? "/assets/images/favicon-dark.png" : "/assets/images/favicon.png";
const link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = src;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
function changeTheme(useLight) {
document.documentElement.classList.remove('light-theme', 'dark-theme', 'has-light-text', 'has-dark-text')
if (useLight) {
document.documentElement.classList.add('light-theme', 'has-dark-text')
} else {
document.documentElement.classList.add('dark-theme', 'has-light-text')
}
if (window.localStorage) {
window.localStorage.setItem(
"lightTheme",
useLight ? "light" : "dark")
}
changeFavicon()
}
themeToggle.addEventListener("click", () => {
changeTheme(document.documentElement.classList.contains('dark-theme'))
});
if (localTheme === "light") {
changeTheme(true)
} else {
changeTheme(isOSLight)
}
+11 -26
View File
@@ -6,7 +6,13 @@
<title>{{meta_title}}</title>
<meta charset="utf-8">
<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 --}}
<link rel="preload" as="style" href="{{asset "built/screen.css"}}">
<link rel="preload" as="script" href="{{asset "built/source.js"}}">
@@ -14,41 +20,20 @@
{{!-- 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"}}">
{{!-- 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 --}}
{{ghost_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">
{{> "components/navigation" navigationLayout=@custom.navigation_layout}}
{{{body}}}
{{> "components/footer"}}
</div>
{{#is "post, page"}}
+7 -45
View File
@@ -1,7 +1,7 @@
{
"name": "source",
"description": "A default theme for the Ghost publishing platform",
"demo": "https://source.ghost.io",
"name": "sd-ai",
"description": "Theme for sd.ai, forked from Source theme",
"demo": "https://sd.ai/",
"version": "1.0.0",
"engines": {
"ghost": ">=5.0.0"
@@ -18,16 +18,9 @@
"postship": "git fetch && gulp release"
},
"author": {
"name": "Ghost Foundation",
"email": "hello@ghost.org",
"url": "https://ghost.org/"
},
"gpm": {
"type": "theme",
"categories": [
"Minimal",
"Magazine"
]
"name": "Simon Detheridge",
"email": "s@sd.ai",
"url": "https://sd.ai/"
},
"keywords": [
"ghost",
@@ -36,10 +29,8 @@
],
"repository": {
"type": "git",
"url": "https://github.com/TryGhost/Source.git"
"url": "https://git.sd.ai/simon/ghost-theme-sd.ai"
},
"bugs": "https://github.com/TryGhost/Source/issues",
"contributors": "https://github.com/TryGhost/Source/graphs/contributors",
"devDependencies": {
"@tryghost/release-utils": "0.8.1",
"autoprefixer": "10.4.7",
@@ -93,35 +84,6 @@
],
"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": {
"type": "text",
"description": "Used in your footer across your theme, defaults to site title when empty"
+4 -2
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-bar">
@@ -14,9 +14,11 @@
</nav>
<div class="gh-footer-copyright">
Powered by <a href="https://ghost.org/" target="_blank" rel="noopener">Ghost</a>
:
<a href="https://git.sd.ai/simon/ghost-theme-sd.ai" target="_blank" rel="noopener">Theme</a>
</div>
</div>
{{#if @site.members_enabled}}
{{#unless @member}}
<section class="gh-footer-signup">
+5
View File
@@ -0,0 +1,5 @@
{{> "icons/svglogo"}}
<span class="logo-mark">{{> "icons/greater-icon"}}</span>
<span class="logo-text">sd.ai</span>
<span class="logo-cursor"></span>
+3 -2
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-brand">
@@ -6,7 +6,7 @@
{{#if @site.logo}}
<img src="{{@site.logo}}" alt="{{@site.title}}">
{{else}}
{{@site.title}}
{{> "components/logo"}}
{{/if}}
</a>
{{> "search-toggle"}}
@@ -47,6 +47,7 @@
{{/unless}}
</div>
{{/unless}}
{{> "theme-switcher"}}
</div>
</div>
+8 -26
View File
@@ -8,7 +8,7 @@
<section class="gh-container is-{{#match postFeedStyle "List"}}list{{else}}grid{{/match}}{{#if showSidebar}} has-sidebar{{/if}}{{#unless @custom.show_images_in_feed}} no-image{{/unless}} gh-outer">
<div class="gh-container-inner gh-inner">
{{#if showTitle}}
<h2 class="gh-container-title">
{{#unless title}}Latest{{else}}{{title}}{{/unless}}
@@ -23,7 +23,7 @@
{{#match @custom.header_style "Highlight"}}
{{#if @custom.show_featured_posts}}
{{#match posts.length ">=" 4}}
{{#get "posts" include="authors" limit="16"}}
{{#get "posts" include="authors,tags" limit="16"}}
{{#foreach posts from="5" limit="12"}}
{{> "post-card" lazyLoad=true}}
{{/foreach}}
@@ -31,7 +31,7 @@
{{/match}}
{{else}}
{{#match posts.length ">=" 10}}
{{#get "posts" include="authors" limit="22"}}
{{#get "posts" include="authors,tags" limit="22"}}
{{#foreach posts from="11" limit="12"}}
{{> "post-card" lazyLoad=true}}
{{/foreach}}
@@ -40,14 +40,14 @@
{{/if}}
{{else match @custom.header_style "Magazine"}}
{{#match posts.length ">=" 7}}
{{#get "posts" include="authors" limit="19"}}
{{#get "posts" include="authors,tags" limit="19"}}
{{#foreach posts from="8" limit="12"}}
{{> "post-card" lazyLoad=true}}
{{/foreach}}
{{/get}}
{{/match}}
{{else}}
{{#get "posts" include="authors" limit="12"}}
{{#get "posts" include="authors,tags" limit="12"}}
{{#foreach posts}}
{{> "post-card" lazyLoad=true}}
{{/foreach}}
@@ -58,7 +58,7 @@
{{!-- All posts --}}
{{#match feed "index"}}
{{#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}}
{{> "post-card"}}
{{/foreach}}
@@ -81,26 +81,8 @@
{{#if showSidebar}}
<aside class="gh-sidebar">
<section class="gh-about">
{{#if @site.icon}}
<img class="gh-about-icon" src="{{@site.icon}}" alt="{{@site.title}}" loading="lazy">
{{/if}}
<h3 class="gh-about-title is-title">{{@site.title}}</h3>
{{#if @site.description}}
<p class="gh-about-description is-body">{{@site.description}}</p>
{{/if}}
{{#if @site.members_enabled}}
{{#unless @member}}
<button class="gh-button" data-portal="signup">Subscribe</button>
{{else}}
{{#if @site.paid_members_enabled}}
{{#unless @member.paid}}
<button class="gh-button" data-portal="upgrade">Upgrade</button>
{{/unless}}
{{/if}}
{{/unless}}
{{/if}}
</section>
<h3 class="gh-card-title is-title"><a href="https://social.sd.ai/@s" target="_blank" rel="noopener">Latest From Mastodon</a></h3>
<div id="mastodon-comments-list"></div>
</aside>
{{/if}}
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="greater-icon" viewBox="0 0 44 44">
<path fill="none" d="M15 8l14.729 14.382L15 35.367" />
</svg>

After

Width:  |  Height:  |  Size: 146 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 78 KiB

+14
View File
@@ -0,0 +1,14 @@
<svg
class="theme-toggler"
width="24"
height="24"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M22 41C32.4934 41 41 32.4934 41 22C41 11.5066 32.4934 3 22
3C11.5066 3 3 11.5066 3 22C3 32.4934 11.5066 41 22 41ZM7 22C7
13.7157 13.7157 7 22 7V37C13.7157 37 7 30.2843 7 22Z"
/>
</svg>

After

Width:  |  Height:  |  Size: 337 B

+9 -3
View File
@@ -17,9 +17,6 @@
</figure>
{{/if}}
<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>
{{#if excerpt}}
<p class="gh-card-excerpt is-body">{{excerpt}}</p>
@@ -31,6 +28,15 @@
{{#if @custom.show_publish_date}}
<time class="gh-card-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
{{/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>
</div>
</a>
+3
View File
@@ -0,0 +1,3 @@
<button class="theme-toggle gh-icon-button" aria-label="Change theme">
{{> "icons/theme-icon"}}
</button>
+26 -7
View File
@@ -9,13 +9,12 @@
<header class="gh-article-header gh-canvas">
{{#if primary_tag}}
<a class="gh-article-tag" href="{{primary_tag.url}}">{{primary_tag.name}}</a>
{{/if}}
<div class="gh-article-tags">
{{#foreach tags}}
<a class="gh-article-tag" href="{{url}}">{{name}}</a>
{{/foreach}}
</div>
<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-author-image">
@@ -50,6 +49,26 @@
</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}}
<div class="gh-comments gh-canvas">
{{comments}}
@@ -60,7 +79,7 @@
{{/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}}
<section class="gh-container is-grid gh-outer">
<div class="gh-container-inner gh-inner">