diff --git a/README.md b/README.md index a084e50..faf5e82 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,24 @@ -# ᕦʕ •ᴥ•ʔᕤ Bear Cub +# ʕ •ᴥ•ʔつ🗳️ Voting Bear Cub -[![github pages](https://github.com/clente/hugo-bearcub/actions/workflows/gh-pages.yml/badge.svg)](https://github.com/clente/hugo-bearcub/actions/workflows/gh-pages.yml) -[![MIT license](https://img.shields.io/github/license/clente/hugo-bearcub)](https://github.com/clente/hugo-bearcub/blob/main/LICENSE) +[![MIT license](https://img.shields.io/badge/license-MIT-blue)](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: diff --git a/assets/auto-theme.css b/assets/auto-theme.css index dce83e8..276e937 100644 --- a/assets/auto-theme.css +++ b/assets/auto-theme.css @@ -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, diff --git a/assets/herman.css b/assets/herman.css index f2573c3..e2dfc11 100644 --- a/assets/herman.css +++ b/assets/herman.css @@ -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; diff --git a/exampleSite/hugo.toml b/exampleSite/hugo.toml index 04690c0..939c13d 100644 --- a/exampleSite/hugo.toml +++ b/exampleSite/hugo.toml @@ -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] diff --git a/go.mod b/go.mod deleted file mode 100644 index 1008b40..0000000 --- a/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module hugo-bearcub - -go 1.26.2 diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 0c85516..5f5d4db 100644 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -27,4 +27,14 @@

{{ end }} {{ end }} +{{ if and .Site.Params.upvotes (not .Params.hideUpvotes) }} +
+ +
+ + +{{ end }} {{ end }} diff --git a/static/upvote.js b/static/upvote.js new file mode 100644 index 0000000..131da67 --- /dev/null +++ b/static/upvote.js @@ -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"); + } + }); +})(); diff --git a/theme.toml b/theme.toml index 602a351..7f6b154 100644 --- a/theme.toml +++ b/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"