Compare commits

...

15 Commits
v1.0.0 ... main

Author SHA1 Message Date
Jean Viscogliosi-Pate cd3abbf188 Removing title from TOC, fixes #19 2025-03-20 20:05:01 -07:00
Jean Viscogliosi-Pate a685e4c2a7 Styling tables to theme properly 2025-03-20 20:05:01 -07:00
Jean Viscogliosi-Pate 74e079bb2a Add back Ghost Foundation copyright to LICENSE because I'm stupid 2024-12-18 23:36:19 -05:00
Jean Viscogliosi-Pate a8ad1c51ec Updating color of burger menu, fixes #17 2024-10-21 18:20:55 -07:00
Jean Viscogliosi-Pate b8efa1b6fa Fixed typo in README 2024-09-01 02:47:12 -04:00
Jean Viscogliosi-Pate 089308d5bd Updated README to include documentation for usage, fixes #14 2024-09-01 02:43:48 -04:00
Jean Viscogliosi-Pate 32d73e56ba Adding error page, fixes #15 2024-08-31 22:17:34 -07:00
Jean Viscogliosi-Pate 8609f47c0c Made dark theme darker, fixes #8 2024-08-31 21:57:24 -07:00
Jean Viscogliosi-Pate 9eced82e93 Fixed missing table of contents 2024-08-31 21:52:37 -07:00
Jean Viscogliosi-Pate 9ea42fa3aa Fixing drop shadow covering caption, fixes #9 2024-08-31 21:47:54 -07:00
Jean Viscogliosi-Pate ee6b9ab688 Added desc tags to post pages 2024-08-31 21:32:57 -07:00
Jean Viscogliosi-Pate 05e7316870 Adding publication date and support for hiding with internal tags, fixes #13 2024-08-31 19:39:33 -07:00
Jean Viscogliosi-Pate 3c4bcc3070 Adding table of contents compatiblility to full-width images, fixes #7 2024-08-31 17:59:31 -07:00
Jean Viscogliosi-Pate 7893803c8a Updating table of contents CSS, fixes #12 2024-08-31 17:44:08 -07:00
Jean Viscogliosi-Pate c727794550 Updating gitignore to hush nix 2024-08-31 17:43:10 -07:00
13 changed files with 225 additions and 108 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
node_modules node_modules
package-lock.json package-lock.json
dist/ dist/
flake.lock
yarn.lock yarn.lock
assets/built/ assets/built/

View File

@ -1,3 +1,4 @@
Copyright (c) 2013-2023 Ghost Foundation
Copyright (c) 2024 Jean Viscogliosi-Pate Copyright (c) 2024 Jean Viscogliosi-Pate
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person

View File

@ -2,13 +2,56 @@
Bifocal is is a minimal theme for [Ghost](https://github.com/TryGhost/Ghost) based on Solo. It features a two-column layout when screen width allows and displays internal tags to the visitor. Bifocal is is a minimal theme for [Ghost](https://github.com/TryGhost/Ghost) based on Solo. It features a two-column layout when screen width allows and displays internal tags to the visitor.
Additional features include adaptive light/dark theme, a table of contents, a cat, and email obfuscation. Please note that the theme includes a robots.txt file that tells most web scrapers to ignore your site, although not all of them listen. Additional features include adaptive light/dark theme, a table of contents, and email obfuscation. Please note that the theme comes with a robots.txt file that tells most web scrapers to ignore your site, although not all of them listen.
# Instructions # Instructions
1. Download this theme 1. [Download this theme](https://git.viscogliosi-pate.com/jean/Bifocal/releases)
2. Log into Ghost, and go to the `Design` settings area to upload the zip file 2. Log into Ghost, and go to the `Design` settings area to upload the zip file
# Usage
## Feature images
The maximum width that an image will be rendered at is 1200px. 1200px wide by 225px tall are the ideal dimensions for feature images. Be aware that the featured image for a post is not used within that post.
## Using internal tags
Internal tags can be added from the Tags page in Ghost's admin interface. All internal tags are prefixed with a hash. Tag behavior in this theme is dependent on whether it has an associated image.
### How to add text after a post's title
Do not add an image to your internal tag. Only the **Description** field is used.
### How to add icons above a post's title
- The **Tag image** field is the icon file. This is assumed to be an SVG with an `id` matching the tag's **Meta description**. The SVG must be structured this way to support `fill=currentColor`, which enables the icon to be themed with the website.
- The **Meta title** field is used for the image title and alt text.
- The **Description** field is the text that accompanies the icon, if present.
### How to hide publication date and/or table of contents
1. Any post with an internal tag named `#hide date` will have the publication date hidden.
2. Any post with an internal tag named `#hide toc` will have the table of contents hidden.
## Theme settings
### Accent color
This option is only used for link color.
### Email obfuscation
This feature requires JavaScript to be enabled for site visitors, but will have no impact on their experience of using the website. Please enter your email [encrypted with ROT13](https://rot13.com/) in the **Email address** field of the `Site-wide` settings. This feature is implemented to prevent bot scraping of your email address and should prevent spam.
### Socials
Include the full URL to your profile instead of your handle alone. Empty socials will not be accessible to visitors.
### Oneko
This setting toggles the cat that chases the visitor's mouse. It's a very cute and fun addition! Text-heavy sites may want to disable this feature because it can disrupt reading.
# Development # Development
Edition styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node](https://nodejs.org/), [Yarn](https://yarnpkg.com/) and [Gulp](https://gulpjs.com) installed globally. As an alternative, install [Nix](https://nixos.org/) and type `nix develop` with the experimental flakes feature enabled. After that, from the theme's root directory: Edition styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node](https://nodejs.org/), [Yarn](https://yarnpkg.com/) and [Gulp](https://gulpjs.com) installed globally. As an alternative, install [Nix](https://nixos.org/) and type `nix develop` with the experimental flakes feature enabled. After that, from the theme's root directory:
@ -23,7 +66,7 @@ yarn dev
Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically. 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/solo.zip`, which you can then upload to your site. The `zip` Gulp task packages the theme files into `dist/bifocal.zip`, which you can then upload to your site.
```bash ```bash
yarn zip yarn zip
@ -31,15 +74,11 @@ yarn zip
## Credits ## Credits
Original [Solo](https://github.com/TryGhost/Solo) theme relased under the MIT license by Ghost Foundation. - Original [Solo](https://github.com/TryGhost/Solo) theme relased under the MIT license by Ghost Foundation.
- Font is [Wanted Sans](https://github.com/wanteddev/wanted-sans), released under the SIL Open Font License 1.1 by Wanted Lab, Inc.
Font is [Wanted Sans](https://github.com/wanteddev/wanted-sans), released under the SIL Open Font License 1.1 by Wanted Lab, Inc. - Email and RSS icons are from [Tabler Icons](https://github.com/tabler/tabler-icons), released under the MIT license by Paweł Kuna.
- The cat that follows your cursor is [oneko.js](https://github.com/adryd325/oneko.js), released under the MIT license by adryd.
Email and RSS icons are from [Tabler Icons](https://github.com/tabler/tabler-icons), released under the MIT license by Paweł Kuna. - The JavaScript for generating a table of contents is [Tocbot](https://github.com/tscanlin/tocbot), released under the MIT license by Tim Scanlin.
The cat that follows your cursor is [oneko.js](https://github.com/adryd325/oneko.js), released under the MIT license by adryd.
The JavaScript for generating a table of contents is [Tocbot](https://github.com/tscanlin/tocbot), released under the MIT license by Tim Scanlin.
## Copyright & License ## Copyright & License

View File

@ -1,6 +1,5 @@
@import "@tryghost/shared-theme-assets/assets/css/v1/screen.css"; @import "@tryghost/shared-theme-assets/assets/css/v1/screen.css";
@import "fonts.css"; @import "fonts.css";
@import "tocbot.css";
:root { :root {
--font-sans: Wanted Sans, Century Gothic, Frutiger, Futura, Montserrat, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; --font-sans: Wanted Sans, Century Gothic, Frutiger, Futura, Montserrat, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
@ -12,6 +11,7 @@
--gap: clamp(24px, 1.7032rem + 1.9355vw, 48px); --gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);
--head-nav-gap: 32px; --head-nav-gap: 32px;
--container-width: 1440px; --container-width: 1440px;
--big-title-font-size: clamp(4rem, 2.86vw + 2.63rem, 7.2rem);
--title-font-size: clamp(3.2rem, 2.7rem + 1.5625vw, 5.2rem); --title-font-size: clamp(3.2rem, 2.7rem + 1.5625vw, 5.2rem);
--content-font-size: clamp(1.7rem, 0.38vw + 1.4rem, 2rem); --content-font-size: clamp(1.7rem, 0.38vw + 1.4rem, 2rem);
--header-spacing: clamp(4.8rem, 4rem + 2.5vw, 8rem); --header-spacing: clamp(4.8rem, 4rem + 2.5vw, 8rem);
@ -29,7 +29,7 @@
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--color-primary-text: var(--color-lighter-gray); --color-primary-text: var(--color-lighter-gray);
--background-color: #1e1e1e; --background-color: #141414;
--color-border: rgba(255, 255, 255, 0.08); --color-border: rgba(255, 255, 255, 0.08);
--color-secondary-text: var(--color-secondary-text-light); --color-secondary-text: var(--color-secondary-text-light);
} }
@ -175,6 +175,11 @@ hr {
color: inherit; color: inherit;
} }
.gh-burger:before,
.gh-burger:after {
background-color: var(--color-primary-text);
}
@media (max-width: 991px) { @media (max-width: 991px) {
.is-head-open:not(.is-head-brand):not(.is-head-dark):not(.is-head-transparent) :is(#gh-head, #gh-head .gh-head-actions) { .is-head-open:not(.is-head-brand):not(.is-head-dark):not(.is-head-transparent) :is(#gh-head, #gh-head .gh-head-actions) {
background-color: var(--background-color); background-color: var(--background-color);
@ -310,13 +315,14 @@ hr {
line-height: 32px; line-height: 32px;
} }
.tag-date {
font-size: 1.8rem;
}
.tag-desc { .tag-desc {
color: var(--color-secondary-text); color: var(--color-secondary-text);
font-weight: 600; font-weight: 600;
font-size: calc(var(--title-font-size) * 0.7); display: inline;
display: inline-block;
vertical-align: middle;
block-size: var(--title-font-size);
} }
/* Feed /* Feed
@ -379,11 +385,20 @@ hr {
row-gap: calc(var(--gap) * 2); row-gap: calc(var(--gap) * 2);
} }
.kg-gallery-container { .kg-width-full {
box-shadow: 0px 0px 30px 50px var(--background-color); box-shadow: 0px 0px 30px 50px var(--background-color);
background-color: var(--background-color); background-color: var(--background-color);
} }
.kg-gallery-card {
box-shadow: 0px 0px 30px 50px var(--background-color);
background-color: var(--background-color);
}
.kg-gallery-container {
background-color: var(--background-color);
}
@media (max-width: 991px) { @media (max-width: 991px) {
.gh-feed { .gh-feed {
display: grid; display: grid;
@ -444,8 +459,8 @@ hr {
} }
.gh-article-title { .gh-article-title {
grid-column: 1 / span 9; grid-column: 1 / span 12;
font-size: clamp(4rem, 2.86vw + 2.63rem, 7.2rem); font-size: var(--big-title-font-size);
font-weight: 800; font-weight: 800;
line-height: 1; line-height: 1;
letter-spacing: -0.03em; letter-spacing: -0.03em;
@ -484,6 +499,30 @@ hr {
line-height: 1.7; line-height: 1.7;
} }
.gh-content table:not(.gist table) {
display: table;
width: 100%;
white-space: wrap;
table-layout: fixed;
}
.gh-content table:not(.gist table) td, .gh-content table:not(.gist table) th {
border: 0;
border-left: 1px solid var(--color-light-gray);
}
.gh-content table:not(.gist table) td:first-child {
border: 0;
border-right: 1px solid var(--color-light-gray);
padding-right: 20px;
background: 0;
}
.gh-content table:not(.gist table) td:last-child {
padding-left: 20px;
background: 0;
}
:is(.post-template, .page-template) .no-image .gh-content { :is(.post-template, .page-template) .no-image .gh-content {
margin-top: clamp(4rem, 2.14vw + 2.97rem, 6.4rem); margin-top: clamp(4rem, 2.14vw + 2.97rem, 6.4rem);
} }
@ -598,3 +637,17 @@ hr {
width: 32px; width: 32px;
} }
/* Error page
/* ---------------------------------------------------------- */*
.error-message {
text-align: center;
}
.error-code {
font-size: var(--title-font-size);
}
.error-description {
font-size: var(--big-title-font-size);
}

View File

@ -1,65 +1,30 @@
/* Style from Tocbot */ /* Style from Tocbot */
.toc { .toc {
overflow-y: auto overflow-y: auto;
}
.toc>.toc-list {
overflow: hidden;
position: relative
}
.toc>.toc-list li {
list-style: none
}
.toc-list {
margin: 0;
padding-left: 10px
} }
a.toc-link { a.toc-link {
color: currentColor; color: currentColor;
height: 100% height: 100%;
} }
.is-collapsible { .is-collapsible {
max-height: 1000px; max-height: 1000px;
overflow: hidden; overflow: hidden;
transition: all 300ms ease-in-out transition: all 300ms ease-in-out;
} }
.is-collapsed { .is-collapsed {
max-height: 0 max-height: 0;
} }
.is-position-fixed { .is-position-fixed {
position: fixed !important; position: fixed !important;
top: 0 top: 0;
} }
.is-active-link { .is-active-li {
font-weight: 700 list-style: disc;
}
.toc-link::before {
background-color: #EEE;
content: ' ';
display: inline-block;
height: inherit;
left: 0;
margin-top: -1px;
position: absolute;
width: 2px
}
@media (prefers-color-scheme: dark) {
.toc-link::before {
background-color: #EEE;
}
}
.is-active-link::before {
background-color: #54BC4B
} }
/* Style from Ghost Foundation */ /* Style from Ghost Foundation */
@ -69,6 +34,7 @@ a.toc-link {
.gh-toc > .toc-list { .gh-toc > .toc-list {
position: relative; position: relative;
padding-left: 15.3667px;
} }
.toc-list { .toc-list {
@ -96,10 +62,15 @@ a.toc-link {
a.toc-link { a.toc-link {
text-decoration: none; text-decoration: none;
color: var(--color-secondary-text);
display: inline-block;
vertical-align: middle;
margin: 0;
font-weight: 700;
} }
.gh-toc .is-active-link::before { a.is-active-link {
background-color: var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */ color: var(--color-primary-text);
} }
/* Additional style information from Jean interspersed */ /* Additional style information from Jean interspersed */

View File

@ -67,21 +67,6 @@
<script src="{{asset "built/main.min.js"}}"></script> <script src="{{asset "built/main.min.js"}}"></script>
{{! Tocbot is used for the table of contents }}
<script src="{{asset "built/tocbot.min.js"}}"></script>
<script>
tocbot.init({
// Where to render the table of contents.
tocSelector: '.gh-toc',
// Where to grab the headings to build the table of contents.
contentSelector: '.gh-content',
// Which headings to grab inside of the contentSelector element.
headingSelector: 'h1, h2',
// Ensure correct positioning
hasInnerContainers: true,
});
</script>
{{#if @custom.oneko}} {{#if @custom.oneko}}
<script src="{{asset "js/oneko.js"}}"></script> <script src="{{asset "js/oneko.js"}}"></script>
{{/if}} {{/if}}

10
error.hbs Normal file
View File

@ -0,0 +1,10 @@
{{!< default}}
<main class="gh-main gh-outer">
<div class="gh-inner">
<section class="error-message">
<p class="error-code">{{statusCode}}</p>
<h1 class="error-description">{{message}}</h1>
</section>
</div>
</main>

39
flake.lock Normal file
View File

@ -0,0 +1,39 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 0,
"narHash": "sha256-Grh5PF0+gootJfOJFenTTxDTYPidA3V28dqJ/WV7iis=",
"path": "/nix/store/d9gbq853jvbccrz5g3y0irbwgc57w137-source",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"systems": "systems"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@ -1,7 +1,7 @@
{ {
"name": "bifocal", "name": "bifocal",
"description": "A Ghost theme, based on Solo", "description": "A Ghost theme, based on Solo",
"version": "1.0.0", "version": "1.0.3",
"private": true, "private": true,
"engines": { "engines": {
"ghost": ">=5.0.0" "ghost": ">=5.0.0"
@ -43,7 +43,11 @@
"custom": { "custom": {
"navigation_layout": { "navigation_layout": {
"type": "select", "type": "select",
"options": ["Logo on the left", "Logo in the middle", "Stacked"], "options": [
"Logo on the left",
"Logo in the middle",
"Stacked"
],
"default": "Logo on the left" "default": "Logo on the left"
}, },
"primary_header": { "primary_header": {
@ -99,5 +103,6 @@
"postcss": "8.4.38", "postcss": "8.4.38",
"postcss-easy-import": "4.0.0", "postcss-easy-import": "4.0.0",
"pump": "3.0.0" "pump": "3.0.0"
} },
"dependencies": {}
} }

View File

@ -1,18 +0,0 @@
{{#if feature_image}}
<figure class="gh-article-image{{#if feature_image_caption}} has-caption{{/if}}">
<img
srcset="{{img_url feature_image size="s"}} 300w,
{{img_url feature_image size="m"}} 720w,
{{img_url feature_image size="l"}} 960w,
{{img_url feature_image size="xl"}} 1200w,
{{img_url feature_image size="xxl"}} 2000w,
{{img_url feature_image}}"
sizes="(max-width: 1200px) 100vw, 1200px"
src="{{img_url feature_image size="xl"}}"
alt="{{title}}"
>
{{#if feature_image_caption}}
<figcaption>{{feature_image_caption}}</figcaption>
{{/if}}
</figure>
{{/if}}

View File

@ -1,9 +1,11 @@
{{!-- Outputs the descriptions of ONLY internal tags with NO icon --}} {{!-- Used for de-emphasized text after post title --}}
{{#if tags}} {{#if tags}}
{{#foreach tags visibility="internal"}} {{#foreach tags visibility="internal"}}
{{^if feature_image}} {{^if feature_image}}
{{description}} {{#if description}}
{{description}}
{{/if}}
{{/if}} {{/if}}
{{/foreach}} {{/foreach}}
{{/if}} {{/if}}

View File

@ -1,4 +1,4 @@
{{!-- Outputs a bullet list of icons and descriptions for ONLY internal tags with an icon --}} {{!-- Generates list of post information --}}
{{#if tags}} {{#if tags}}
<ul class="tag-list"> <ul class="tag-list">
@ -9,11 +9,20 @@
<use href="{{img_url feature_image}}#{{meta_description}}"> <use href="{{img_url feature_image}}#{{meta_description}}">
</svg> </svg>
<div class=tag-text> <div class="tag-text">
<p>{{description}}</p> <p>{{description}}</p>
</div> </div>
</li> </li>
{{/if}} {{/if}}
{{/foreach}} {{/foreach}}
{{!-- Adds publication date unless instructed not to --}}
{{^has tag="#hide date"}}
<li>
<div class="tag-text tag-date">
<p>{{date value format="MMM D YYYY"}}</p>
</div>
</li>
{{/has}}
</ul> </ul>
{{/if}} {{/if}}

View File

@ -10,7 +10,12 @@
{{#if feature_image}} {{#if feature_image}}
<header class="gh-article-header gh-canvas"> <header class="gh-article-header gh-canvas">
<h1 class="gh-article-title">{{title}}</h1> <h1 class="gh-article-title">
{{title}}
<div class="tag-desc">
{{> "get-desc-tags"}}
</div>
</h1>
{{#if custom_excerpt}} {{#if custom_excerpt}}
<p class="gh-article-excerpt">{{custom_excerpt}}</p> <p class="gh-article-excerpt">{{custom_excerpt}}</p>
{{/if}} {{/if}}
@ -18,8 +23,12 @@
{{/if}} {{/if}}
<section class="gh-content gh-canvas"> <section class="gh-content gh-canvas">
<aside class="gh-sidebar"><div class="gh-toc"></div></aside> {{! Table of contents }} <aside class="gh-sidebar">
<div class="gh-toc"></div>
</aside>
{{content}} {{content}}
{{#unless feature_image}} {{#unless feature_image}}
<header class="gh-article-header"> <header class="gh-article-header">
<h1 class="gh-article-title">{{title}}</h1> <h1 class="gh-article-title">{{title}}</h1>
@ -30,6 +39,19 @@
{{/unless}} {{/unless}}
</section> </section>
</article> </article>
{{!-- Adds table of contents unless instructed not to --}}
{{^has tag="#hide toc"}}
<script src="{{asset "js/lib/tocbot.min.js"}}"></script>
<script>
tocbot.init({
tocSelector: '.gh-toc',
contentSelector: '.gh-content',
headingSelector: 'h2',
hasInnerContainers: true,
});
</script>
{{/has}}
{{/post}} {{/post}}
</div> </div>
</main> </main>