diff --git a/.forgejo/workflows/publish.yml b/.forgejo/workflows/publish.yml
index 53dd92f..fde3206 100644
--- a/.forgejo/workflows/publish.yml
+++ b/.forgejo/workflows/publish.yml
@@ -7,6 +7,9 @@ jobs:
runs-on: based-alpine
steps:
- uses: actions/checkout@v4
+ - name: setup cache
+ id: uv-cache
+ uses: https://git.ficd.sh/ficd/uv-cache@v1
- name: build
run: |
uv sync
diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml
new file mode 100644
index 0000000..2a05ee6
--- /dev/null
+++ b/.forgejo/workflows/test.yml
@@ -0,0 +1,18 @@
+# this workflow checks if the project can be built successfully.
+# it also serves to test whether based-alpine and uv-cache are working properly.
+# Unit tests will be added here eventually
+on: [push]
+jobs:
+ test-build:
+ runs-on: based-alpine
+ steps:
+ - name: checkout source
+ uses: actions/checkout@v4
+ - name: setup cache
+ id: uv-cache
+ uses: https://git.ficd.sh/ficd/uv-cache@v1
+ - name: sync and build
+ run: |
+ uv sync
+ uv build
+ uv run zona --version
diff --git a/.kakrc b/.kakrc
index 7a60b1f..688bcbe 100644
--- a/.kakrc
+++ b/.kakrc
@@ -15,6 +15,10 @@ define-command readme %{
root-edit README.md
}
+define-command kakrc %{
+ root-edit .kakrc
+}
+
# change working directory to the package
hook global -once BufCreate .* %{
change-directory %exp{%opt{project_root}/src/zona}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e65c79..104815a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+# 1.2.1
+
+- Added `--version` flag to CLI.
+
+# 1.2.0
+
+- Improved the appearance and semantics of post navigation buttons.
+ - Navigation now follows "newer/older" logic.
+- Added hover symbols to page titles.
+- Improved the styling of hover symbols and links.
+
# 1.1.0
- Major improvements to default stylesheet.
diff --git a/README.md b/README.md
index bd7eb9b..c3facfb 100644
--- a/README.md
+++ b/README.md
@@ -101,10 +101,6 @@ If you don't want discovery, you can specify the project root as the first
argument to `zona build`. You may specify a path for the output using the
`--output/-o` flag. The `--draft/-d` flag includes draft posts in the output.
-_Note: the previous build is _not_ cleaned before the new site is built. If
-you've deleted some pages, you may need to remove the output directory before
-rebuilding._
-
### Live Preview
To make the writing process as frictionless as possible, zona ships with a live
@@ -121,9 +117,10 @@ By default, the build outputs to a temporary directory. Use `-o/--output` to
override this.
**Note**: if the live preview isn't working as expected, try restarting the
-server. If you change the configuration or any templates, the server must also
-be restarted. The live preview uses the same function as `zona build`
-internally; this means that the output is also written to disk.
+server. If you change the configuration, the server must also be restarted. The
+live preview uses the same function as `zona build` internally; this means that
+the output is also written to disk --- a temporary directory by default, unless
+overridden with `-o/--output`.
#### Live Reload
@@ -196,13 +193,17 @@ the packaged defaults. To apply a certain template to a page, set the `template`
option in its [frontmatter](#frontmatter). The following public variables are
made available to the template engine:
-| Name | Description |
-| ---------- | ------------------------------------------------------ |
-| `content` | The content of this page. |
-| `url` | The resolved URL of this page. |
-| `metadata` | The frontmatter of this page (_merged with defaults_). |
-| `header` | The sitemap header in HTML form. Can be `False`. |
-| `footer` | The footer in HTML form. Can be `False`. |
+| Name | Description |
+| ----------- | -------------------------------------------------------- |
+| `content` | The content of this page. |
+| `url` | The resolved URL of this page. |
+| `metadata` | The frontmatter of this page (_merged with defaults_). |
+| `header` | The sitemap header in HTML form. Can be `False`. |
+| `footer` | The footer in HTML form. Can be `False`. |
+| `is_post` | Whether this page is a post. |
+| `newer` | URL of the newer post in the post list. |
+| `older` | URL of the older post in the post list. |
+| `post_list` | A sorted list of `Item` objects. Meant for internal use. |
#### Markdown Footer
diff --git a/pyproject.toml b/pyproject.toml
index a66fa54..f0c6b14 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "zona"
-version = "1.1.0"
+version = "1.2.1"
description = "Opinionated static site generator."
license = "BSD-3-Clause "
license-files = ["LICENSE"]
diff --git a/src/zona/builder.py b/src/zona/builder.py
index 27ff2ca..bd2812b 100644
--- a/src/zona/builder.py
+++ b/src/zona/builder.py
@@ -123,6 +123,8 @@ class ZonaBuilder:
def _get_post_list(self) -> list[Item]:
assert self.items
+ # sort according to date
+ # descending order
post_list: list[Item] = sorted(
[item for item in self.items if item.post],
key=lambda item: item.metadata.date
@@ -130,17 +132,17 @@ class ZonaBuilder:
else date.min,
reverse=True,
)
+ # number of posts
# generate RSS here
posts = len(post_list)
+ # link post chronology
for i, item in enumerate(post_list):
- prev = post_list[i - 1] if i > 0 else None
- next = post_list[i + 1] if i < posts - 2 else None
- item.previous = prev
- item.next = next
- return post_list
-
- def _build(self):
- post_list = self._get_post_list()
+ # prev: older post
+ older = post_list[i + 1] if i + 1 < posts else None
+ # next: newer post
+ newer = post_list[i - 1] if i > 0 else None
+ item.older = older
+ item.newer = newer
templater = Templater(
config=self.config,
diff --git a/src/zona/cli.py b/src/zona/cli.py
index 4b48d3a..da15a22 100644
--- a/src/zona/cli.py
+++ b/src/zona/cli.py
@@ -1,3 +1,4 @@
+from importlib.metadata import version as __version__
from pathlib import Path
from typing import Annotated
@@ -134,8 +135,23 @@ def serve(
)
+def version_callback(value: bool):
+ if value:
+ print(f"Zona version: {__version__('zona')}")
+ raise typer.Exit()
+
+
@app.callback()
def main_entry(
+ version: Annotated[ # pyright: ignore[reportUnusedParameter]
+ bool | None,
+ typer.Option(
+ "--version",
+ callback=version_callback,
+ is_eager=True,
+ help="Print version info and exit.",
+ ),
+ ] = None,
verbosity: Annotated[
str,
typer.Option(
diff --git a/src/zona/data/content/static/style.css b/src/zona/data/content/static/style.css
index f02717e..caa0eef 100644
--- a/src/zona/data/content/static/style.css
+++ b/src/zona/data/content/static/style.css
@@ -1,4 +1,5 @@
:root {
+ --main-placeholder-color: #b14242;
--main-text-color: #b4b4b4;
--main-text-opaque-color: rgba(180, 180, 180, 0.8);
--main-bg-color: #121212;
@@ -33,27 +34,101 @@ header {
.post-nav {
font-family: monospace;
+ font-size: 0.95em;
+ white-space: nowrap;
+}
+
+.post-nav .bar {
+ position: relative;
+ bottom: 0.05em;
+ display: inline-block;
+ width: 1px;
+ height: 0.8em;
+ background-color: currentColor;
+ vertical-align: middle;
+ margin: 0 0.3em;
+}
+
+.post-nav .placeholder {
+ color: var(--main-placeholder-color);
}
.post-nav .symbol {
color: var(--main-bullet-color);
+ margin: 0;
+ padding: 0;
+ display: inline;
}
-.post-nav a {
- margin: 0 2px;
+.site-logo.hover-symbol::before {
+ content: "~/";
}
-.site-logo {
+.title.hover-symbol::before {
+ content: "$";
+}
+
+.hover-symbol {
color: inherit;
+ position: relative;
font-weight: bold;
text-decoration: none;
- /* font-size: 1.75rem;*/
+ transition: color 0.15s ease;
+}
+
+.hover-symbol::before {
+ font-family: monospace;
+ content: "#";
+ position: absolute;
+ right: 100%;
+ margin-right: 0.25em;
+ top: 50%;
+ transform: translateY(-50%);
+ opacity: 0;
+ transition: opacity 0.15s ease, color 0.15s ease;
+ color: var(--main-text-color);
+}
+
+.hover-symbol:hover::before {
+ opacity: 1;
+ color: var(--main-placeholder-color);
+}
+.hover-symbol:hover {
+ background-color: transparent;
+}
+
+.toc ul {
+ font-family: monospace;
+ text-transform: lowercase;
+ margin: auto;
+ width: 50%;
+}
+
+.toc ul ul {
+ padding-left: 1em;
+ margin-left: 1em;
+ /* list-style-type: "–– ";*/
+}
+.toc ul ul ul {
+ padding-left: 1em;
+ margin-left: 1em;
+ /* list-style-type: "-- ";*/
}
.toclink {
position: relative;
text-decoration: none;
color: inherit;
+ transition: color 0.15s ease;
+ text-transform: lowercase;
+ font-family: monospace;
+}
+.post-list a {
+ position: relative;
+ text-decoration: none;
+ transition: color 0.15s ease;
+ text-transform: lowercase;
+ font-family: monospace;
}
.toclink::before {
@@ -64,7 +139,16 @@ header {
top: 50%;
transform: translateY(-50%);
opacity: 0;
- transition: opacity 0.2s ease;
+ transition: opacity 0.15s ease, color 0.15s ease;
+ color: var(--main-link-color);
+}
+
+.toclink:hover::before {
+ opacity: 1;
+ color: var(--main-placeholder-color);
+}
+.toclink:hover {
+ background-color: transparent;
}
h1 .toclink::before {
@@ -83,13 +167,6 @@ h4 .toclink::before {
content: "###";
}
-.toclink:hover::before {
- opacity: 1;
-}
-.toclink:hover {
- background-color: transparent;
-}
-
/* h1, */
h2,
h3,
@@ -111,6 +188,11 @@ h1 {
font-family: monospace;
}
+.title a {
+ color: inherit;
+ text-decoration: none;
+}
+
article h1:first-of-type {
margin-block-start: 1.67rem;
}
@@ -154,40 +236,55 @@ h6 {
font-weight: bold;
}
+/*ul {*/
+/* list-style-type: disc;*/
+/*}*/
+
ul {
- list-style-type: disc;
- /* or any other list style */
+ list-style-type: "– ";
+}
+ul ul {
+ padding-left: 1em;
+ margin-left: 1em;
+ list-style-type: "+ ";
+}
+ul ul ul {
+ list-style-type: "~ ";
+}
+ul ul ul ul {
+ list-style-type: "• ";
+}
+ul ul ul ul ul {
+ list-style-type: "– ";
+}
+ul ul ul ul ul ul {
+ list-style-type: "+ ";
+}
+ul ul ul ul ul ul ul {
+ list-style-type: "~ ";
+}
+ul ul ul ul ul ul ul ul {
+ list-style-type: "• ";
}
li::marker {
color: var(--main-bullet-color);
- /* Change this to your desired color */
}
a {
color: var(--main-link-color);
- text-decoration: none;
- position: relative;
+ text-decoration: underline;
+ text-decoration-color: rgba(0, 0, 0, 0);
+ text-underline-offset: 2px;
}
-a::after {
- content: "";
- position: absolute;
- left: 0;
- bottom: -2px;
- width: 100%;
- height: 1px;
- background-color: currentColor;
- transform: scaleX(0);
- transform-origin: center;
- transition: transform 0.1s ease;
+a {
+ transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
-a:hover::after {
- transform: scaleX(1);
-}
-a:has(> code)::after {
- display: none;
+a:hover {
+ text-decoration-color: var(--main-placeholder-color);
+ color: var(--main-bullet-color);
}
max-width: 100%;
@@ -424,23 +521,3 @@ caption {
font-size: 0.8rem;
color: var(--main-small-text-color);
}
-
-a > code {
- text-decoration: none;
- color: var(--main-link-color);
- position: relative;
-}
-
-a:has(> code) {
- text-decoration: none;
- background: none;
- /* position: static;*/
-}
-
-a:hover > code {
- text-decoration: underline;
-}
-
-a:hover:has(> code) {
- background: none;
-}
diff --git a/src/zona/data/templates/post_list.html b/src/zona/data/templates/post_list.html
index 85e0be8..6b0bdca 100644
--- a/src/zona/data/templates/post_list.html
+++ b/src/zona/data/templates/post_list.html
@@ -1,20 +1,18 @@
-{% extends "base.html" %} {% block content %}
-
-{% if metadata.show_title %}
-{% include "title.html" %}
-{% endif %}
+{% extends "base.html" %} {% block content %} {% if metadata.show_title %} {%
+include "title.html" %} {% endif %}