Skip to content

Commit

Permalink
Merge branch 'main' into item-models
Browse files Browse the repository at this point in the history
  • Loading branch information
object-Object committed Oct 7, 2024
2 parents f25e014 + 6cc3354 commit cff18a8
Show file tree
Hide file tree
Showing 46 changed files with 964 additions and 113 deletions.
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Pydantic's HISTORY.md](https://github.com/pydantic/pydantic/blob/main/HISTORY.md), and this project *mostly* adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## `1!0.1.0a20`

### Added

* New Jinja template filter: `hexdoc_smart_var`
* Can be used to allow runtime variable lookups based on values in `props.template.args`. This is currently used by the [custom navbar links](https://hexdoc.hexxy.media/docs/guides/template/#navbar) feature.

### Changed

* A GitHub link is now added to the navbar by default (fixes [#26](https://github.com/hexdoc-dev/hexdoc/issues/26)). See the [docs](https://hexdoc.hexxy.media/docs/guides/template/#navbar) for more info.

### Fixed

* Fix the root-level redirect not being generated in cases where there are no versioned books and no book exists for the default branch.
* Fix crash on startup by adding a dependency exclusion for Pydantic v2.9.0 (see [pydantic/pydantic#10345](https://github.com/pydantic/pydantic/issues/10345)).

## `1!0.1.0a19`

### Added

* Allow adding custom links to the web book navbar ([docs](https://hexdoc.hexxy.media/docs/guides/template)).

## `1!0.1.0a18`

### Fixed

* Add missing handler for nested list styles (`$(li2)`, `$(li3)`, etc).
* Fix book links to other extension books on 1.19 and below (also fixes [#75](https://github.com/hexdoc-dev/hexdoc/issues/75))

## `1!0.1.0a17`

### Fixed
Expand Down
15 changes: 14 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def dummy_setup(session: nox.Session):
"categories/foo.json": {
"name": "Dummy Category",
"icon": "minecraft:amethyst_shard",
"description": "Foo bar baz qux quux corge grault garply waldo fred plugh xyzzy thud",
"description": "Foo bar baz qux$(br)$(li)quux$(br)$(li2)corge$(br)$(li3)grault$(br)$(li4)garply$(li)waldo$(br)fred plugh xyzzy thud",
"sortnum": 0,
},
"entries/bar.json": {
Expand Down Expand Up @@ -510,6 +510,19 @@ def dummy_setup(session: nox.Session):
mod_name = "Dummy"
author = "author"
show_landing_text = true
[template.args.navbar]
left = [
{ text="<strong>Left</strong>", href="https://google.ca" },
]
center = [
{ text="Center 1", href="https://google.ca", external=false },
{ text="Center 2", href="https://google.ca", external=false, icon="box-arrow-down-right" },
]
right = [
{ text="Right", href="https://google.ca", icon="box-arrow-up-left" },
{ text="GitHub", href.variable="source_url" },
]
"""
),
"nodemon.json": {
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ dependencies = [
"packaging~=23.2",
"pluggy~=1.3",
"pydantic_settings~=2.0",
"pydantic>=2.7.1,<3",
"pydantic>=2.7.1,<3,!=2.9.0",
"pygithub~=2.1",
"pyjson5~=1.6",
"requests~=2.31",
Expand All @@ -75,6 +75,7 @@ test = [
"pyright==1.1.361",
"pytest~=7.4",
"pytest-dependency~=0.5",
"pytest-describe~=2.2",
"syrupy~=4.6",
"copier_template_tester",
"pyyaml-include<2", # https://github.com/copier-org/copier/issues/1568
Expand Down
6 changes: 3 additions & 3 deletions src/hexdoc/_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def default_rendered_templates_v2(
templates: DefaultRenderedTemplates = {}

for category in book.categories.values():
templates[redirect_path(category.raw_link)] = (
templates[redirect_path(category.redirect_path)] = (
"redirects/category.html.jinja",
{
"category": category,
Expand All @@ -106,7 +106,7 @@ def default_rendered_templates_v2(
)

for entry in category.entries.values():
templates[redirect_path(entry.raw_link)] = (
templates[redirect_path(entry.redirect_path)] = (
"redirects/entry.html.jinja",
{
"category": category,
Expand All @@ -116,7 +116,7 @@ def default_rendered_templates_v2(
)

for page in entry.pages:
page_path = page.raw_link_path(entry.raw_link)
page_path = page.redirect_path(entry.redirect_path)
if page_path is not None:
templates[redirect_path(page_path)] = (
"redirects/page.html.jinja",
Expand Down
18 changes: 16 additions & 2 deletions src/hexdoc/_templates/components/navbar.html.jinja
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{% import "macros/formatting.html.jinja" as fmt with context -%}

<nav class="navbar navbar-default navbar-static-top">
<div class="container">
<!-- toggle and name -->
<div class="navbar-header">
<button
type="button"
Expand All @@ -17,9 +18,19 @@
<a class="navbar-brand" href="{{ relative_site_url }}">{{ _("hexdoc."~props.modid~".title") }}</a>
</div>

<!-- content -->
<div class="collapse navbar-collapse" id="navbar-collapse">
{% set navbar = navbar|default({}) %}
{% if navbar.left|default(false) %}
<ul class="nav navbar-nav navbar-left">
{% for item in navbar.left %}
{{ fmt.navbar_link(item) }}
{% endfor %}
</ul>
{% endif %}
<ul class="nav navbar-nav navbar-right">
{% for item in navbar.center|default([]) %}
{{ fmt.navbar_link(item) }}
{% endfor %}
<li class="dropdown">
<a
href=""
Expand All @@ -42,6 +53,9 @@
>{{ lang_name }} <span class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-left" id="lang-dropdown"></ul>
</li>
{% for item in navbar.right|default([]) %}
{{ fmt.navbar_link(item) }}
{% endfor %}
</ul>
</div>
</div>
Expand Down
12 changes: 12 additions & 0 deletions src/hexdoc/_templates/index.css.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,17 @@ p {

p.fake-li {
margin: 0;
--level: 1;
}

p.fake-li::before {
content: "\2022";
margin: 1ex;
margin-left: calc(1ex + (var(--level) - 1) * 2ex);
}

p.fake-li-alt::before {
content: "\25E6";
}

.linkout::before {
Expand Down Expand Up @@ -375,6 +381,12 @@ p.todo-note {
border-radius: 6px 0 6px 6px;
}

.external-link-icon {
position: relative;
bottom: 2px;
margin-left: 2px;
}

.nobr {
white-space: nowrap;
}
Expand Down
17 changes: 17 additions & 0 deletions src/hexdoc/_templates/macros/formatting.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,20 @@
<span class="collapse-recipe-hide">{{ _(base_key~".hide") }}</span>
</summary>
{%- endmacro %}

{% defaultmacro navbar_link(data) -%}
{% set external = data.external|default(true)|hexdoc_smart_var %}
{% set icon = data.icon|default("box-arrow-up-right" if external else false)|hexdoc_smart_var %}
<li>
<a
href="{{ data.href|hexdoc_smart_var }}"
{% if external %}
target="_blank"
{% endif %}
class="navbar-link"
role="button"
aria-haspopup="true"
aria-expanded="false"
>{{ data.text|hexdoc_smart_var|safe }}{% if icon %} <i class="bi bi-{{ icon }} external-link-icon"></i>{% endif %}</a>
</li>
{%- enddefaultmacro %}
2 changes: 1 addition & 1 deletion src/hexdoc/_templates/macros/styles.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@
{%- endmacro %}

{% macro paragraph_list_item(style) -%}
<p class="fake-li">{{ caller() }}</p>
<p class="fake-li {{ 'fake-li-alt' if style.level % 2 == 0 }}" style="--level: {{ style.level }};">{{ caller() }}</p>
{%- endmacro %}
2 changes: 1 addition & 1 deletion src/hexdoc/_templates/macros/styles.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@
{%- endmacro %}

{% macro paragraph_list_item(style) -%}
* {{ caller() }}\n
{{ " " * style.level }}* {{ caller() }}\n
{%- endmacro %}
9 changes: 9 additions & 0 deletions src/hexdoc/cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,17 @@ def merge(

if root_redirect is None:
# TODO: use plugin to build this path
# TODO: refactor
if item := sitemap.get(f"latest/{props.default_branch}"):
root_redirect = item.default_marker.redirect_contents
elif sitemap:
key = sorted(sitemap.keys())[0]
root_redirect = sitemap[key].default_marker.redirect_contents
logger.warning(
f"No book exists for the default branch `{props.default_branch}`, generating root redirect to `{key}` (check the value of `default_branch` in hexdoc.toml)"
)
else:
logger.error("No books found, skipping root redirect")

if root_redirect is not None:
redirects[Path()] = root_redirect
Expand Down
12 changes: 10 additions & 2 deletions src/hexdoc/core/properties/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,16 @@ def asset_url(self) -> URL:

return (
URL("https://raw.githubusercontent.com")
/ self.repo_owner
/ self.repo_name
/ self.github_repository
/ self.github_sha
)

@property
def source_url(self) -> URL:
return (
URL("https://github.com")
/ self.github_repository
/ "tree"
/ self.github_sha
)

Expand Down
9 changes: 8 additions & 1 deletion src/hexdoc/data/sitemap.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import shutil
import textwrap
from collections import defaultdict
from pathlib import Path

Expand Down Expand Up @@ -98,7 +99,13 @@ def delete_updated_books(*, src: Path, dst: Path, release: bool):
if dst_dir.exists():
if release:
raise ValueError(
f"Tried to overwrite book directory in release mode: {dst_dir}"
textwrap.dedent(
f"""
Release mode is enabled, refusing to overwrite existing directory: {dst_dir}
Note: this combination of mod and book version has already been released.
Try incrementing the book version number (usually in __version__.py).
"""
).strip()
)
shutil.rmtree(dst_dir)

Expand Down
2 changes: 2 additions & 0 deletions src/hexdoc/jinja/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"IncludeRawExtension",
"hexdoc_item_image",
"hexdoc_localize",
"hexdoc_smart_var",
"hexdoc_texture_image",
"hexdoc_wrap",
]
Expand All @@ -10,6 +11,7 @@
from .filters import (
hexdoc_item_image,
hexdoc_localize,
hexdoc_smart_var,
hexdoc_texture_image,
hexdoc_wrap,
)
22 changes: 21 additions & 1 deletion src/hexdoc/jinja/filters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import functools
from typing import Callable, ParamSpec, TypeVar
from typing import Any, Callable, ParamSpec, TypeVar

from jinja2 import pass_context
from jinja2.runtime import Context
Expand Down Expand Up @@ -97,3 +97,23 @@ def hexdoc_texture_image(context: Context, id: str | ResourceLocation):
@make_jinja_exceptions_suck_a_bit_less
def hexdoc_item_image(context: Context, id: str | ResourceLocation | ItemStack):
return validate_image(ItemImage, id, context)


@pass_context
@make_jinja_exceptions_suck_a_bit_less
def hexdoc_smart_var(context: Context, value: Any):
"""Smart template argument filter.
If `value` is of the form `{"variable": str(ref)}`, returns the value of the
template variable called `ref`.
Otherwise, returns `value` unchanged.
"""

match value:
case {**items} if len(items) != 1:
return value
case {"variable": str(ref)}:
return context.resolve(ref)
case _:
return value
8 changes: 8 additions & 0 deletions src/hexdoc/jinja/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from .filters import (
hexdoc_item_image,
hexdoc_localize,
hexdoc_smart_var,
hexdoc_texture_image,
hexdoc_wrap,
)
Expand Down Expand Up @@ -107,6 +108,7 @@ def create_jinja_env_with_loader(loader: BaseLoader):
"hexdoc_localize": hexdoc_localize,
"hexdoc_texture_image": hexdoc_texture_image,
"hexdoc_item_image": hexdoc_item_image,
"hexdoc_smart_var": hexdoc_smart_var,
}

return env
Expand Down Expand Up @@ -193,6 +195,7 @@ def render_book(
"site_url": str(props.env.github_pages_url),
"relative_site_url": relative_site_url,
"page_url": str(page_url),
"source_url": str(props.env.source_url),
"version": version,
"lang": lang,
"lang_name": lang_name,
Expand All @@ -204,6 +207,11 @@ def render_book(
"safari_pinned_tab_color": "#332233",
"minecraft_version": minecraft_version or "???",
"full_version": plugin.full_version,
"navbar": { # default navbar links (ignored if set in props)
"center": [
{"text": "GitHub", "href": {"variable": "source_url"}},
],
},
"_": lambda key: hexdoc_localize( # i18n helper
key,
do_format=False,
Expand Down
10 changes: 5 additions & 5 deletions src/hexdoc/patchouli/book.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def _load_categories(self, context: ContextSource, book_ctx: BookContext):
self._categories[id] = category

link_base = book_ctx.get_link_base(category.resource_dir)
book_ctx.book_links[category.raw_link] = link_base.with_fragment(
book_ctx.book_links[category.book_link_key] = link_base.with_fragment(
category.fragment
)

Expand Down Expand Up @@ -122,15 +122,15 @@ def _load_entries(
internal_entries[entry.category_id][entry.id] = entry

link_base = book_ctx.get_link_base(resource_dir)
book_ctx.book_links[entry.raw_link] = link_base.with_fragment(
book_ctx.book_links[entry.book_link_key] = link_base.with_fragment(
entry.fragment
)

for page in entry.pages:
page_raw_link = page.raw_link(entry.raw_link)
page_key = page.book_link_key(entry.book_link_key)
page_fragment = page.fragment(entry.fragment)
if page_raw_link is not None and page_fragment is not None:
book_ctx.book_links[page_raw_link] = link_base.with_fragment(
if page_key is not None and page_fragment is not None:
book_ctx.book_links[page_key] = link_base.with_fragment(
page_fragment
)

Expand Down
Loading

0 comments on commit cff18a8

Please sign in to comment.