Compare commits

..

1 commit

Author SHA1 Message Date
f621ec944f wip: generate RSS feed 2025-07-15 15:14:11 -04:00
15 changed files with 105 additions and 236 deletions

View file

@ -7,9 +7,6 @@ jobs:
runs-on: based-alpine runs-on: based-alpine
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: setup cache
id: uv-cache
uses: https://git.ficd.sh/ficd/uv-cache@v1
- name: build - name: build
run: | run: |
uv sync uv sync

View file

@ -1,18 +0,0 @@
# 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

4
.kakrc
View file

@ -15,10 +15,6 @@ define-command readme %{
root-edit README.md root-edit README.md
} }
define-command kakrc %{
root-edit .kakrc
}
# change working directory to the package # change working directory to the package
hook global -once BufCreate .* %{ hook global -once BufCreate .* %{
change-directory %exp{%opt{project_root}/src/zona} change-directory %exp{%opt{project_root}/src/zona}

View file

@ -1,14 +1,3 @@
# 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 # 1.1.0
- Major improvements to default stylesheet. - Major improvements to default stylesheet.

View file

@ -101,6 +101,10 @@ 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 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. `--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 ### Live Preview
To make the writing process as frictionless as possible, zona ships with a live To make the writing process as frictionless as possible, zona ships with a live
@ -117,10 +121,9 @@ By default, the build outputs to a temporary directory. Use `-o/--output` to
override this. override this.
**Note**: if the live preview isn't working as expected, try restarting the **Note**: if the live preview isn't working as expected, try restarting the
server. If you change the configuration, the server must also be restarted. The server. If you change the configuration or any templates, the server must also
live preview uses the same function as `zona build` internally; this means that be restarted. The live preview uses the same function as `zona build`
the output is also written to disk --- a temporary directory by default, unless internally; this means that the output is also written to disk.
overridden with `-o/--output`.
#### Live Reload #### Live Reload
@ -193,17 +196,13 @@ the packaged defaults. To apply a certain template to a page, set the `template`
option in its [frontmatter](#frontmatter). The following public variables are option in its [frontmatter](#frontmatter). The following public variables are
made available to the template engine: made available to the template engine:
| Name | Description | | Name | Description |
| ----------- | -------------------------------------------------------- | | ---------- | ------------------------------------------------------ |
| `content` | The content of this page. | | `content` | The content of this page. |
| `url` | The resolved URL of this page. | | `url` | The resolved URL of this page. |
| `metadata` | The frontmatter of this page (_merged with defaults_). | | `metadata` | The frontmatter of this page (_merged with defaults_). |
| `header` | The sitemap header in HTML form. Can be `False`. | | `header` | The sitemap header in HTML form. Can be `False`. |
| `footer` | The footer 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 #### Markdown Footer

View file

@ -1,6 +1,6 @@
[project] [project]
name = "zona" name = "zona"
version = "1.2.1" version = "1.1.0"
description = "Opinionated static site generator." description = "Opinionated static site generator."
license = "BSD-3-Clause " license = "BSD-3-Clause "
license-files = ["LICENSE"] license-files = ["LICENSE"]

View file

@ -123,8 +123,6 @@ class ZonaBuilder:
def _get_post_list(self) -> list[Item]: def _get_post_list(self) -> list[Item]:
assert self.items assert self.items
# sort according to date
# descending order
post_list: list[Item] = sorted( post_list: list[Item] = sorted(
[item for item in self.items if item.post], [item for item in self.items if item.post],
key=lambda item: item.metadata.date key=lambda item: item.metadata.date
@ -132,17 +130,17 @@ class ZonaBuilder:
else date.min, else date.min,
reverse=True, reverse=True,
) )
# number of posts
# generate RSS here # generate RSS here
posts = len(post_list) posts = len(post_list)
# link post chronology
for i, item in enumerate(post_list): for i, item in enumerate(post_list):
# prev: older post prev = post_list[i - 1] if i > 0 else None
older = post_list[i + 1] if i + 1 < posts else None next = post_list[i + 1] if i < posts - 2 else None
# next: newer post item.previous = prev
newer = post_list[i - 1] if i > 0 else None item.next = next
item.older = older return post_list
item.newer = newer
def _build(self):
post_list = self._get_post_list()
templater = Templater( templater = Templater(
config=self.config, config=self.config,

View file

@ -1,4 +1,3 @@
from importlib.metadata import version as __version__
from pathlib import Path from pathlib import Path
from typing import Annotated from typing import Annotated
@ -135,23 +134,8 @@ def serve(
) )
def version_callback(value: bool):
if value:
print(f"Zona version: {__version__('zona')}")
raise typer.Exit()
@app.callback() @app.callback()
def main_entry( 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[ verbosity: Annotated[
str, str,
typer.Option( typer.Option(

View file

@ -1,5 +1,4 @@
:root { :root {
--main-placeholder-color: #b14242;
--main-text-color: #b4b4b4; --main-text-color: #b4b4b4;
--main-text-opaque-color: rgba(180, 180, 180, 0.8); --main-text-opaque-color: rgba(180, 180, 180, 0.8);
--main-bg-color: #121212; --main-bg-color: #121212;
@ -34,101 +33,27 @@ header {
.post-nav { .post-nav {
font-family: monospace; 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 { .post-nav .symbol {
color: var(--main-bullet-color); color: var(--main-bullet-color);
margin: 0;
padding: 0;
display: inline;
} }
.site-logo.hover-symbol::before { .post-nav a {
content: "~/"; margin: 0 2px;
} }
.title.hover-symbol::before { .site-logo {
content: "$";
}
.hover-symbol {
color: inherit; color: inherit;
position: relative;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
transition: color 0.15s ease; /* font-size: 1.75rem;*/
}
.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 { .toclink {
position: relative; position: relative;
text-decoration: none; text-decoration: none;
color: inherit; 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 { .toclink::before {
@ -139,16 +64,7 @@ header {
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
opacity: 0; opacity: 0;
transition: opacity 0.15s ease, color 0.15s ease; transition: opacity 0.2s ease;
color: var(--main-link-color);
}
.toclink:hover::before {
opacity: 1;
color: var(--main-placeholder-color);
}
.toclink:hover {
background-color: transparent;
} }
h1 .toclink::before { h1 .toclink::before {
@ -167,6 +83,13 @@ h4 .toclink::before {
content: "###"; content: "###";
} }
.toclink:hover::before {
opacity: 1;
}
.toclink:hover {
background-color: transparent;
}
/* h1, */ /* h1, */
h2, h2,
h3, h3,
@ -188,11 +111,6 @@ h1 {
font-family: monospace; font-family: monospace;
} }
.title a {
color: inherit;
text-decoration: none;
}
article h1:first-of-type { article h1:first-of-type {
margin-block-start: 1.67rem; margin-block-start: 1.67rem;
} }
@ -236,55 +154,40 @@ h6 {
font-weight: bold; font-weight: bold;
} }
/*ul {*/
/* list-style-type: disc;*/
/*}*/
ul { ul {
list-style-type: " "; list-style-type: disc;
} /* or any other list style */
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 { li::marker {
color: var(--main-bullet-color); color: var(--main-bullet-color);
/* Change this to your desired color */
} }
a { a {
color: var(--main-link-color); color: var(--main-link-color);
text-decoration: underline; text-decoration: none;
text-decoration-color: rgba(0, 0, 0, 0); position: relative;
text-underline-offset: 2px;
} }
a { a::after {
transition: color 0.15s ease, text-decoration-color 0.15s ease; 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:hover { a:hover::after {
text-decoration-color: var(--main-placeholder-color); transform: scaleX(1);
color: var(--main-bullet-color); }
a:has(> code)::after {
display: none;
} }
max-width: 100%; max-width: 100%;
@ -521,3 +424,23 @@ caption {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--main-small-text-color); 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;
}

View file

@ -1,18 +1,20 @@
{% extends "base.html" %} {% block content %} {% if metadata.show_title %} {% {% extends "base.html" %} {% block content %}
include "title.html" %} {% endif %}
{% if metadata.show_title %}
{% include "title.html" %}
{% endif %}
<article>{{ content | safe }}</article> <article>{{ content | safe }}</article>
{% if post_list %} {% if post_list %}
<div class="post-list"> <ul>
<ul> {% for item in post_list %}
{% for item in post_list %} <li>
<li> <time class="post-list-date" datetime="{{ item.metadata.date | safe }}"
<time class="post-list-date" datetime="{{ item.metadata.date | safe }}" >{{ item.metadata.date | safe}}</time>: <a href="/{{ item.url }}"
>{{ item.metadata.date | safe}}</time>: <a href="/{{ item.url }}" >{{ item.metadata.title }}</a>
>{{ item.metadata.title }}</a> </li>
</li> {% endfor %}
{% endfor %} </ul>
</ul>
</div>
{% endif %} {% endblock %} {% endif %} {% endblock %}

View file

@ -1,11 +1,9 @@
<div class="post-nav"> <div class="post-nav">
<center> <center>
<span class="symbol">&lt;</span>{% if newer %}<a href="{{ newer }}">newr</a>{% <span class="symbol">&lt;</span>{% if previous %}<a
else %}<span class="placeholder">null</span>{% endif %}<span href="{{ previous }}"
class="symbol" >prev</a>{% endif %}{% if previous and next %}<span class="symbol"
><span class="bar"></span></span>{% if older %}<a href="{{ older }}" >|</span>{% endif %}{% if next %}<a href="{{ next }}">next</a>{% endif
>oldr</a>{% else %}<span class="placeholder">null</span>{% endif %}<span %}<span class="symbol">&gt;</span>
class="symbol"
>&gt;</span>
</center> </center>
</div> </div>

View file

@ -1,2 +1,2 @@
<center><h1 class="title hover-symbol"><a id="" href="#">{{ metadata.title }}</a></h1></center> <center><h1 class="title">{{ metadata.title }}</h1></center>

View file

@ -23,8 +23,8 @@ class Item:
type: ItemType | None = None type: ItemType | None = None
copy: bool = True copy: bool = True
post: bool = False post: bool = False
newer: Item | None = None next: Item | None = None
older: Item | None = None previous: Item | None = None
# @dataclass # @dataclass

View file

@ -27,6 +27,7 @@ def get_footer(template_dir: Path) -> str | None:
return html_footer.read_text() return html_footer.read_text()
# TODO: add next/prev post button logic to posts
# TODO: add a recent posts element that can be included elsewhere? # TODO: add a recent posts element that can be included elsewhere?
class Templater: class Templater:
def __init__( def __init__(
@ -78,11 +79,11 @@ class Templater:
header=header, header=header,
footer=footer, footer=footer,
is_post=item.post, is_post=item.post,
newer=util.normalize_url(item.newer.url) next=util.normalize_url(item.next.url)
if item.newer if item.next
else None, else None,
older=util.normalize_url(item.older.url) previous=util.normalize_url(item.previous.url)
if item.older if item.previous
else None, else None,
post_list=self.post_list, post_list=self.post_list,
) )

2
uv.lock generated
View file

@ -509,7 +509,7 @@ wheels = [
[[package]] [[package]]
name = "zona" name = "zona"
version = "1.2.1" version = "1.1.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "dacite" }, { name = "dacite" },