Compare commits
9 commits
2a390f1224
...
17c78a6bcd
| Author | SHA1 | Date | |
|---|---|---|---|
| 17c78a6bcd | |||
| 556c1725ab | |||
| ecceb7afa9 | |||
| 665da9bec6 | |||
| 41c217030c | |||
| 460fe6a820 | |||
| d8834d83b7 | |||
| e896111497 | |||
| 87bc37e124 |
8 changed files with 153 additions and 33 deletions
28
README.md
28
README.md
|
|
@ -1,13 +1,24 @@
|
|||
# ᕦʕ •ᴥ•ʔᕤ Bear Cub
|
||||
# ʕ •ᴥ•ʔつ🗳️ Voting Bear Cub
|
||||
|
||||
[](https://github.com/clente/hugo-bearcub/actions/workflows/gh-pages.yml)
|
||||
[](https://github.com/clente/hugo-bearcub/blob/main/LICENSE)
|
||||
[](https://forge.alexselimov.com/aselimov/hugo-bearcub/src/branch/main/LICENSE)
|
||||
|
||||
## Overview
|
||||
|
||||
🐻 A lightweight [Hugo](https://gohugo.io/) theme based on [Bear
|
||||
Blog](https://bearblog.dev) and [Hugo Bear
|
||||
Blog](https://github.com/janraasch/hugo-bearblog).
|
||||
This is a fork of [Bear Cub](https://github.com/clente/hugo-bearcub) with the
|
||||
following additions:
|
||||
|
||||
- **Anonymous post upvoting**: each post can display an upvote button backed by
|
||||
a configurable API endpoint. Votes are tracked anonymously via cookies so
|
||||
readers can toggle their vote without creating an account. Enable with
|
||||
`upvotes = true` and set `upvoteApi` to your API base URL.
|
||||
- **Redesigned header**: the site header now uses a mesh SVG background for a
|
||||
more distinctive look.
|
||||
- **GitHub light/dark color scheme**: the syntax highlighting palette has been
|
||||
replaced with colors matching the GitHub light and dark themes.
|
||||
- **Herman CSS upvote styles**: upvote button styles are bundled into the Herman
|
||||
CSS variant so the button integrates cleanly with the existing theme.
|
||||
- **Configurable index post count**: use `postsToShowOnIndex` in `[params]` to
|
||||
control how many posts appear on the home page (defaults to 3).
|
||||
|
||||
**Bear Cub** takes care of speed and optimization, so you can focus on writing
|
||||
good content. It is free, multilingual, optimized for search engines,
|
||||
|
|
@ -29,6 +40,11 @@ To finish off, append a line to the site configuration file:
|
|||
echo 'theme = "hugo-bearcub"' >> hugo.toml
|
||||
```
|
||||
|
||||
### Anonymous voting
|
||||
|
||||
To easily setup the anonymous voting you need to run an [upvoters](https://forge.alexselimov.com/aselimov/upvoters) server.
|
||||
You should be able to ship your own solution as well.
|
||||
|
||||
## Features
|
||||
|
||||
Like [Bear Blog](https://bearblog.dev), this theme:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ footer {
|
|||
}
|
||||
|
||||
.mesh-image {
|
||||
color: #61ABDA;
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
.footer-copy {
|
||||
|
|
@ -104,13 +104,17 @@ li {
|
|||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
#upvote-btn[voted] {
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
color: #1f2328;
|
||||
background-color: #fffdf8;
|
||||
color: #201e1b;
|
||||
}
|
||||
|
||||
.mesh-image {
|
||||
color: #61ABDA;
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
h1,
|
||||
|
|
@ -125,12 +129,12 @@ li {
|
|||
}
|
||||
|
||||
a {
|
||||
color: #61ABDA;
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
a:visited,
|
||||
ul.blog-posts li a:visited {
|
||||
color: #61ABDA;
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
header a,
|
||||
|
|
@ -178,7 +182,7 @@ li {
|
|||
a,
|
||||
a:visited,
|
||||
ul.blog-posts li a:visited {
|
||||
color: #61ABDA;
|
||||
color: #EF9F27;
|
||||
}
|
||||
|
||||
header a,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
:root {
|
||||
font-size: 62.5%; /* 10px */
|
||||
--color-dark: #181a20;
|
||||
--color-light: #fafafa;
|
||||
--color-primary: #1a8fe3;
|
||||
--color-dark: #1a1a1a;
|
||||
--color-light: #faf8f4;
|
||||
--color-primary: #EF9F27;
|
||||
--size: 1rem;
|
||||
--spacing: calc(var(--size) * 2.4);
|
||||
}
|
||||
|
|
@ -190,6 +190,51 @@ td {
|
|||
transform: translateY(0%);
|
||||
}
|
||||
|
||||
.upvote {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
gap: 0.2rem;
|
||||
margin-block: var(--spacing);
|
||||
}
|
||||
|
||||
#upvote-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: currentColor;
|
||||
font-size: calc(var(--size) * 4);
|
||||
line-height: 0.8;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
#upvote-btn:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
#upvote-btn[voted] {
|
||||
color: var(--color-primary);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#upvote-chevron {
|
||||
display: block;
|
||||
line-height: 1;
|
||||
margin-bottom: -0.3em;
|
||||
}
|
||||
|
||||
#upvote-count {
|
||||
font-size: calc(var(--size) * 1.6);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin-inline-start: 0em;
|
||||
margin-inline-end: 0em;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,17 @@ enableRobotsTXT = true
|
|||
# information see layouts/partials/social_card.html
|
||||
generateSocialCard = true
|
||||
|
||||
# The number of posts to show on the index page. Defaults to 3 if not set.
|
||||
postsToShowOnIndex = 3
|
||||
|
||||
# Enable upvoting on posts. When set to true, each post will display an upvote
|
||||
# button that calls the API endpoint specified by `upvoteApi`.
|
||||
upvotes = false
|
||||
|
||||
# The base URL of the upvote API. Only used when `upvotes = true`.
|
||||
# The API is expected to handle GET and POST requests at {upvoteApi}/{post-path}.
|
||||
upvoteApi = "https://example.com/api"
|
||||
|
||||
# Social media. Delete any item you aren't using to make sure it won't show up
|
||||
# in your website's metadata.
|
||||
[params.social]
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -1,3 +0,0 @@
|
|||
module hugo-bearcub
|
||||
|
||||
go 1.26.2
|
||||
|
|
@ -27,4 +27,14 @@
|
|||
</p>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if and .Site.Params.upvotes (not .Params.hideUpvotes) }}
|
||||
<div class="upvote">
|
||||
<button id="upvote-btn" aria-label="Upvote">
|
||||
<span id="upvote-chevron">⌃</span>
|
||||
<span id="upvote-count">—</span>
|
||||
</button>
|
||||
</div>
|
||||
<script>window.UPVOTE_API = "{{ .Site.Params.upvoteApi }}";</script>
|
||||
<script src="/upvote.js"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
|
|
|||
37
static/upvote.js
Normal file
37
static/upvote.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
(async function () {
|
||||
// Define the slug
|
||||
const slug = location.pathname.replace(/^\/|\/$/g, "").replaceAll("/", "-");
|
||||
const API = window.UPVOTE_API;
|
||||
|
||||
const btn = document.getElementById("upvote-btn");
|
||||
const count = document.getElementById("upvote-count");
|
||||
|
||||
// On load fetch curent vote count and whether the button should be clicked on or off
|
||||
const res = await fetch(`${API}/posts/${slug}/votes`, {
|
||||
credentials: "include",
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
count.textContent = data.vote_count;
|
||||
if (data.voted) btn.setAttribute("voted", true);
|
||||
|
||||
btn.addEventListener("click", async () => {
|
||||
const alreadyVoted = btn.hasAttribute("voted");
|
||||
|
||||
const method = alreadyVoted ? "DELETE" : "POST";
|
||||
const r = await fetch(`${API}/posts/${slug}/vote`, {
|
||||
method,
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (r.ok) {
|
||||
const updated = await fetch(`${API}/posts/${slug}/votes`, {
|
||||
credentials: "include",
|
||||
});
|
||||
const d = await updated.json();
|
||||
count.textContent = d.vote_count;
|
||||
if (d.voted) btn.setAttribute("voted", false);
|
||||
else btn.removeAttribute("voted");
|
||||
}
|
||||
});
|
||||
})();
|
||||
28
theme.toml
28
theme.toml
|
|
@ -1,29 +1,29 @@
|
|||
name = "Bear Cub"
|
||||
name = "Voting Bear Cub"
|
||||
license = "MIT"
|
||||
licenselink = "https://github.com/clente/hugo-bearcub/blob/master/LICENSE"
|
||||
description = "A lightweight Hugo theme based on Bear Blog and Hugo Bear Blog. It is free, multilingual, optimized for search engines, no-nonsense, responsive, light, and fast. Really fast."
|
||||
description = """A lightweight Hugo theme based on Bear Blog and Hugo Bear Blog. It is free,
|
||||
multilingual, optimized for search engines, no-nonsense, responsive, light, and fast. Really fast.
|
||||
This version adds an upvote button that connects to an
|
||||
https://forge.alexselimov.com/aselimov/upvoters server to handle anonymous upvotes.
|
||||
"""
|
||||
|
||||
# The home page of the theme, where the source can be found.
|
||||
homepage = "https://github.com/clente/hugo-bearcub"
|
||||
|
||||
# If you have a running demo of the theme.
|
||||
demosite = "https://clente.github.io/hugo-bearcub"
|
||||
homepage = "https://forge.alexselimov.com/aselimov/hugo-bearcub"
|
||||
|
||||
tags = ["blog", "responsive", "minimal", "personal", "dark", "multilingual"]
|
||||
features = ["favicon", "seo", "no javascript", "rss", "social cards"]
|
||||
|
||||
# If the theme has a single author
|
||||
[author]
|
||||
name = "Caio Lente"
|
||||
homepage = "https://lente.dev"
|
||||
name = "Alex Selimov"
|
||||
homepage = "https://alexselimov.com"
|
||||
|
||||
# If porting an existing theme
|
||||
[original]
|
||||
author = "Jan Raasch"
|
||||
homepage = "https://www.janraasch.com"
|
||||
repo = "https://github.com/janraasch/hugo-bearblog"
|
||||
name = "Caio Lente"
|
||||
homepage = "https://lente.dev"
|
||||
repo = "https://github.com/clente/hugo-bearcub"
|
||||
|
||||
# Hugo versions the theme supports
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
min = "0.90"
|
||||
[module.hugoVersion]
|
||||
min = "0.90"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue