A spectre is haunting Europe. This is its website's theme. π» Ghost theme for websites and blogs affiliated with Die Linke.
Live Demo | Download |
---|
Ghost uses a simple templating language called Handlebars for its themes.
The main files are:
default.hbs
- The parent template file, which includes your global header/footerhome.hbs
- The homepageindex.hbs
- The main template to generate a list of postspost.hbs
- The template used to render individual postspage.hbs
- Used for individual pagestag.hbs
- Used for tag archives, eg. "all posts tagged withnews
"author.hbs
- Used for author archives, eg. "all posts written by Jamie"
One neat trick is that you can also create custom one-off templates by adding the slug of a page to a template file. For example:
page-about.hbs
- Custom template for an/about/
pagetag-news.hbs
- Custom template for/tag/news/
archiveauthor-ines.hbs
- Custom template for/author/ines/
archive
This website offers a onepager homepage as well as a blog. You'll need to update your routes in order to make the homepage work.
This is how your routes.yaml file could look like:
routes:
/:
template: page
data: page.start
/sitemap/:
template: sitemap
content_type: text/html
collections:
/presse/mitteilungen/:
permalink: /presse/mitteilungen/{year}/{slug}/
template: search-pressemitteilungen
filter: 'tag:hash-pressemitteilung'
/termine/archiv/:
permalink: /termine/{year}/{slug}/
template: search-termine
filter: 'tag:hash-termin'
/blog/:
permalink: /blog/{slug}/
template: home
taxonomies:
tag: /tag/{slug}/
author: /autor_in/{slug}/
Caution: Collections must be specified in the correct order. Posts that have already been assigned to the previously mentioned collection with a filter (e.g. all with the tag #termin
or hash-termin
(as you would write it in the routes file)) cannot be part of the subsequent collections (e.g. /blog/
). Therefore, a filter that excludes press releases and events no longer needs to be specified for /blog/
.
Example: If the collection /blog/
in the example above were defined above the collection /termine/archiv/
(with the filter #termin
or hash-termin
), the appointments collection would be completely empty because the posts specified with the filter have already been assigned to another collection.
More information about collections can be found in the official documentation.
As you can see in the routes.yaml
example code, this theme supports custom pages for events and press releases. This way, those kinds of posts don't clutter the blog index view.
Add the following lines to the collection object inside routes.yaml
:
collections:
/termine/archiv/:
permalink: /termine/{year}/{slug}/
template: search-termine
filter: 'tag:hash-termin'
Simply create a page using the editor, name it (e.g. "Events") and fill it with additional information. Now, select the page template named Termine
in the page options sidebar. From now on, the page displays the 5 latest events on its bottom.
To add an event, simply create a new post and fill in the event information. It's recommended to put the event date in the title. Now tag your event post with the internal tag #termin
. This ensures the event isn't displayed in the main blog index and only on the event page (as well as the event archive page).
Add the following lines to the collection object inside routes.yaml
:
collections:
/presse/mitteilungen/:
permalink: /presse/mitteilungen/{year}/{slug}/
template: search-pressemitteilungen
filter: 'tag:hash-pressemitteilung'
Simply create a page using the editor, name it (e.g. "Presse") and fill it with additional information. Now, select the page template named Presse
in the page options sidebar. From now on, the page displays the 5 latest press releases on its bottom.
To add a press release, simply create a new post. Now tag your event post with the internal tag #pressemitteilung
. This ensures the event isn't displayed in the main blog index and only on the press releases page (as well as the press releases archive page).
This Theme allows privacy-friendly and GDPR-compliant YouTube video embeds using light-yt.js by Amit Agarwal.
- Copy the YouTube video ID (if the video URL is
https://www.youtube.com/watch?v=dQw4w9WgXcQ
, the ID isdQw4w9WgXcQ
) - Inside the editor, insert an HTML block where you want to place the video
- Paste the following code into the HTML block and replace
VideoID
with the ID you copied:<div class="youtube-player" data-id="VideoID"></div>
(=><div class="youtube-player" data-id="dQw4w9WgXcQ"></div>
)
It is recommended to save the finished HTML block with the embedded video as a snippet so that you do not have to look up the required code the next time.
This theme can generate sitemaps compatible with Google News. Just set a route using the sitemap template like it's shown in the example routes file:
routes:
/sitemap/:
template: sitemap
content_type: text/html
After that, you can use Google Search Console to submit your sitemap. In this case, the sitemap URL would be https://your-site.com/sitemap/
.
For speed optimization, it is recommended to upload your own logo in SVG format. However, if this is not the case, Spectre generates a logo based on the site's title.
Spectre styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need Node, Yarn and Gulp installed globally. After that, from the theme's root directory:
# install dependencies
yarn install
# run development server
yarn dev
Now you can edit /assets/css/
files, which will be compiled to /assets/built/
automatically.
The zip
Gulp task packages the theme files into dist/<theme-name>.zip
, which you can then upload to your site.
# create .zip file
yarn zip
- Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser.
Spectre employs various techniques to optimize loading times. These include preloading important resources, combining multiple CSS and JS files into single, compressed files, critical inline CSS, and embedding important icons as SVGs (instead of e.g. icon fonts).
This theme uses penthouse to generate inline CSS for the post, page, tag, and index pages. This reduces the time to First Contentful Paint dramatically. The respective inline CSS files are included via Handlebars partials (see default.hbs and partials/components/inline-css.hbs).
Inline styles can be manually regenerated using yarn critical
.
Spectre uses inline SVG icons, which are included via Handlebars partials. All icons are located in /partials/icons
. To use an icon, simply include the name of the corresponding file, e.g., to include the SVG icon in /partials/icons/rss.hbs
, use {{> "icons/rss"}}
.
Additional SVG icons can be added in the same manner.
In the default configuration, both Ghost and light-yt.js (the plugin I use for privacy-friendly YouTube embeds) make requests to third parties. From a data protection perspective, these are unproblematic. However, they can be circumvented as well.
For the portal, search, and (if activated) the comments function, Ghost includes scripts and stylesheets from JSDelivr. However, it is also possible to specify custom URLs in the configuration file config.[env].json
(π official documentation).
I have written a Cloudflare Worker that proxies and caches requests to JSDelivr. If you make this available via the route my-ghost-website.com/cdn-jsdelivr/*
, under the same domain as the Ghost instance, third-party requests can be avoided. In this case, you would only need to extend the configuration file with the following lines:
{
"url": "http://localhost:2368",
"server": {
"port": 2368,
"host": "::"
},
[...]
"portal": {
"url": "/cdn-jsdelivr/npm/@tryghost/portal@~{version}/umd/portal.min.js"
},
"sodoSearch": {
"url": "/cdn-jsdelivr/npm/@tryghost/sodo-search@~{version}/umd/sodo-search.min.js",
"styles": "/cdn-jsdelivr/npm/@tryghost/sodo-search@~{version}/umd/main.css"
},
"comments": {
"url": "/cdn-jsdelivr/npm/@tryghost/comments-ui@~{version}/umd/comments-ui.min.js",
"styles": "/cdn-jsdelivr/npm/@tryghost/comments-ui@~{version}/umd/main.css"
}
[...]
}
When you access a page with a YouTube video embedded using light-yt.js, the plugin makes two requests:
- A JSON object with information about the embedded video is retrieved from
https://www.youtube-nocookie.com
- The thumbnail is loaded from
https://i.ytimg.com
These requests can also be proxied using a Cloudflare Worker. If you make the worker available using a route, e.g., my-ghost-website.com/yt-proxy/*
(under the same domain as the Ghost instance), you can specify the alternative URLs for loading this data using a script tag in the global site header:
<script>
// load YouTube video data via proxy
const YT_DATA_URL_PREFIX = "/yt-proxy/data";
// load YouTube Thumbnails via proxy
const YT_THUMBNAIL_URL_PREFIX = "/yt-proxy/thumbnail";
</script>
Copyright (c) 2013β2023 Ghost Foundation; 2023β2024 Jannis Hutt. This theme is based on Ghost Foundation's theme Source and released under the MIT license.