Compare commits
25
Commits
3aa4afbee1
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebee3479b1
|
||
|
|
ca4231f8b0
|
||
|
|
a28cc7cd39
|
||
|
|
9d6cc301e8
|
||
|
|
2b68602f86
|
||
|
|
32f457b4cd
|
||
|
|
693bc08e61
|
||
|
|
be9686d40e
|
||
|
|
5435e0c8c0
|
||
|
|
e3df8db9bb
|
||
|
|
719012bb08
|
||
|
|
74e9f9feaf
|
||
|
|
346f3de193
|
||
|
|
54dd6d2a17
|
||
|
|
90e8a3b2a5
|
||
|
|
c7b9f9e67d
|
||
|
|
a84195497e
|
||
|
|
ab61ad1a67
|
||
|
|
9b04b09f33
|
||
|
|
328473e596
|
||
|
|
a9b861a6aa
|
||
|
|
4b347f1b0d | ||
|
|
dedc9cbc3d | ||
|
|
e0483fd7f4 | ||
|
|
98a35f9488 |
@@ -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
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}
|
||||
+113
-10
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
Vendored
+3
File diff suppressed because one or more lines are too long
@@ -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, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
})
|
||||
@@ -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)
|
||||
}
|
||||
+7
-22
@@ -7,6 +7,12 @@
|
||||
<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,32 +20,11 @@
|
||||
{{!-- 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">
|
||||
|
||||
|
||||
+7
-45
@@ -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"
|
||||
|
||||
@@ -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,6 +14,8 @@
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<button class="theme-toggle gh-icon-button" aria-label="Change theme">
|
||||
{{> "icons/theme-icon"}}
|
||||
</button>
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user