Remove minification, format html, break the tests

This commit is contained in:
object-Object 2023-07-23 02:34:07 -04:00
parent 5c0e410b76
commit d78e057aa6
21 changed files with 360 additions and 286 deletions

View file

@ -6,6 +6,9 @@
},
"editor.rulers": [88],
},
"[html][jinja-html]": {
"editor.rulers": [120],
},
"python.formatting.provider": "black",
"python.analysis.typeCheckingMode": "strict", // god save us
"python.analysis.diagnosticSeverityOverrides": {

View file

@ -23,7 +23,7 @@ blacklist = []
[template_args]
title = "Hex Book"
mod_name = "Hexcasting"
mod_name = "Hex Casting"
author = "petrak@, Alwinfy"
description = "The Hex Book, all in one place."
icon_href = "icon.png"

View file

@ -1,4 +1,3 @@
from html import escape
from typing import Any
from jinja2 import nodes
@ -27,21 +26,12 @@ class IncludeRawExtension(Extension):
return Markup(source[0])
def hexdoc_minify(value: str) -> str:
return "".join(line.strip() for line in value.splitlines())
# TODO: remove this when we do the jinja breaking changes
def hexdoc_escape(value: Any) -> str:
return Markup(escape(str(value)))
def hexdoc_block(value: Any) -> str:
match value:
case LocalizedStr() | str():
# use Markup to tell Jinja not to escape this string for us
lines = str(value).splitlines()
return Markup("<br />".join(hexdoc_escape(line) for line in lines))
return Markup("<br />".join(Markup.escape(line) for line in lines))
case FormatTree():
with HTMLStream() as out:
with value.style.element(out):
@ -60,4 +50,4 @@ def hexdoc_wrap(value: str, *args: str):
attributes = " " + " ".join(attributes)
else:
attributes = ""
return Markup(f"<{tag}{attributes}>{hexdoc_escape(value)}</{tag}>")
return Markup(f"<{tag}{attributes}>{Markup.escape(value)}</{tag}>")

View file

@ -9,19 +9,18 @@ from jinja2 import Environment, FileSystemLoader, StrictUndefined
# from jinja2.sandbox import SandboxedEnvironment
from tap import Tap
from common.jinja_extensions import (
IncludeRawExtension,
hexdoc_block,
hexdoc_escape,
hexdoc_minify,
hexdoc_wrap,
)
from common.jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
from common.properties import Properties
from hexcasting.hex_book import HexBook
if sys.version_info < (3, 11):
raise RuntimeError("Minimum Python version: 3.11")
def strip_empty_lines(text: str) -> str:
return "\n".join(s for s in text.splitlines() if s.strip())
# CLI arguments
class Args(Tap):
"""example: main.py properties.toml -o out.html"""
@ -51,20 +50,18 @@ def main(args: Args) -> None:
extensions=[IncludeRawExtension],
)
env.filters |= dict( # for some reason, pylance doesn't like the {} here
hexdoc_minify=hexdoc_minify,
hexdoc_block=hexdoc_block,
hexdoc_wrap=hexdoc_wrap,
hexdoc_escape=hexdoc_escape,
)
# load and render template
template = env.get_template(props.template)
docs = template.render(
props.template_args
| {
"book": book,
"props": props,
}
docs = strip_empty_lines(
template.render(
**props.template_args,
book=book,
props=props,
)
)
# if there's an output file specified, write to it

View file

@ -1,21 +1,21 @@
<div class='container'>
<div class="container">
{# big landing text box - this is optional so addons can disable it if they want #}
{% if show_landing_text %}
<header class='jumbotron'>
<h1 class='book-title'>{{ book.name }}</h1>
<header class="jumbotron">
<h1 class="book-title">{{ book.name }}</h1>
{{ book.landing_text|hexdoc_block }}
</header>
{% endif %}
{# table of contents #}
<nav>
{% include "tableofcontents.html.jinja" %}
{% include "table_of_contents.html.jinja" %}
</nav>
{# actual book content (ie. all the categories) #}
<main class='book-body'>
{% for category in book.categories.values() %}
<main class="book-body">
{% for category in book.categories.values() +%}
{% include "category.html.jinja" %}
{% endfor -%}
{% endfor +%}
</main>
</div>

View file

@ -1,11 +1,12 @@
{% import "macros.html.jinja" as macros -%}
{% import "macros.html.jinja" as macros %}
<section id='{{ category.id.path }}'>
<section id="{{ category.id.path }}">
{% call macros.maybe_spoilered(category) %}
{{ macros.section_header(category, "h2", "category-title") }}
{{- macros.section_header(category, "h2", "category-title") }}
{{ category.description|hexdoc_block }}
{% endcall %}
{% for entry in category.entries if entry.id not in props.blacklist %}
{% for entry in category.entries if entry.id not in props.blacklist +%}
{% include "entry.html.jinja" %}
{% endfor %}
{% endfor +%}
</section>

View file

@ -1,10 +1,11 @@
{% import "macros.html.jinja" as macros -%}
<div id='{{ entry.id.path }}'>
<div id="{{ entry.id.path }}">
{% call macros.maybe_spoilered(entry) %}
{{ macros.section_header(entry, "h3", "entry-title") }}
{% for page in entry.pages %}
{%- include page.template -%}
{{- macros.section_header(entry, "h3", "entry-title") }}
{% for page in entry.pages +%}
{% include page.template %}
{% endfor %}
{% endcall %}
</div>

View file

@ -1,37 +1,37 @@
{# jump to top icon in section headers #}
{% macro jump_to_top() -%}
<a href='#table-of-contents' class='permalink small' title='Jump to top'>
<i class='bi bi-box-arrow-up'></i>
</a>
<a
href="#table-of-contents"
class="permalink small"
title="Jump to top"
><i class="bi bi-box-arrow-up"></i></a>
{%- endmacro %}
{# link icon in section headers to get a permalink to that section #}
{% macro permalink(href) -%}
<a href='#{{ href }}' class='permalink small' title='Permalink'>
<i class='bi bi-link-45deg'></i>
</a>
<a
href="#{{ href }}"
class="permalink small"
title="Permalink"
><i class="bi bi-link-45deg"></i></a>
{%- endmacro %}
{# header for categories and entries #}
{% macro section_header(value, header_tag, class_name) -%}
<{{ header_tag }} class='{{ class_name }} page-header'>
{{ value.name|hexdoc_escape }}
{{ jump_to_top() }}
{{ permalink(value.id.path) }}
<{{ header_tag }} class="{{ class_name }} page-header">
{{- value.name ~ jump_to_top() ~ permalink(value.id.path) -}}
</{{ header_tag }}>
{%- endmacro %}
{# link to value.id, with spoiler blur if value is a spoiler #}
{% macro maybe_spoilered_link(value) -%}
<a href='#{{ value.id.path }}' class='{{ "spoilered" if value.is_spoiler else "" }}'>
{{- value.name|hexdoc_escape -}}
</a>
<a href="#{{ value.id.path }}"{{ ' class="spoilered"'|safe if value.is_spoiler }}>{{ value.name }}</a>
{%- endmacro %}
{# macro block which spoiler blurs its content if value is a spoiler #}
{% macro maybe_spoilered(value) -%}
{% if value.is_spoiler %}
<div class='spoilered'>
<div class="spoilered">
{{ caller() }}
</div>
{% else %}
@ -41,11 +41,11 @@
{# shows the names of all the recipe results in a list of recipes #}
{% macro recipe_block(recipes, result_attribute, description, separator) -%}
<blockquote class='crafting-info'>
<blockquote class="crafting-info">
Depicted in the book: {{ description }} {{
recipes
|map(attribute='result.' ~ result_attribute)
|map('hexdoc_wrap', 'code')
|map(attribute="result." ~ result_attribute)
|map("hexdoc_wrap", "code")
|join(separator)
}}.
</blockquote>

117
doc/templates/main.css.jinja vendored Normal file
View file

@ -0,0 +1,117 @@
summary {
display: list-item;
}
details.spell-collapsible {
display: inline-block;
border: 1px solid #aaa;
border-radius: 4px;
padding: 0.5em 0.5em 0;
margin-bottom: 0.5em;
}
summary.collapse-spell {
font-weight: bold;
margin: -0.5em -0.5em 0;
padding: 0.5em;
}
details.spell-collapsible[open] {
padding: 0.5em;
}
details[open] summary.collapse-spell {
border-bottom: 1px solid #aaa;
margin-bottom: 0.5em;
}
details .collapse-spell::before {
content: "Click to show spell";
}
details[open] .collapse-spell::before {
content: "Click to hide spell";
}
blockquote.crafting-info {
font-size: inherit;
}
a.permalink {
margin-left: 0.5em;
}
a.permalink:hover {
color: lightgray;
}
p {
margin: 0.5ex 0;
}
p.fake-li {
margin: 0;
}
p.fake-li::before {
content: "\2022";
margin: 1ex;
}
.linkout::before {
content: "Link: ";
}
p.todo-note {
font-style: italic;
color: lightgray;
}
.obfuscated {
filter: blur(1em);
}
.spoilered {
filter: blur(1ex);
-moz-transition: filter 0.04s linear;
}
.spoilered:hover {
filter: blur(0.5ex);
}
.spoilered.unspoilered {
filter: blur(0);
}
canvas.spell-viz {
--dot-color: #777f;
--dot-color: #777f;
--start-dot-color: #f009;
--moving-dot-color: #0fa9;
--path-color: darkgray;
--visited-path-color: #0c8;
--dot-scale: 0.0625;
--moving-dot-scale: 0.125;
--line-scale: 0.08333;
--pausetext-scale: 0.5;
--dark-mode: 0;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #201a20;
color: #ddd;
}
.jumbotron {
background-color: #323;
}
canvas.spell-viz {
/* hack */
--dark-mode: 1;
}
}

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{{ description }}">
@ -9,148 +10,33 @@
<title>{{ title }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
<style>
summary { display: list-item; }
details.spell-collapsible {
display: inline-block;
border: 1px solid #aaa;
border-radius: 4px;
padding: .5em .5em 0;
margin-bottom: .5em;
}
summary.collapse-spell {
font-weight: bold;
margin: -.5em -.5em 0;
padding: .5em;
}
details.spell-collapsible[open] {
padding: .5em;
}
details[open] summary.collapse-spell {
border-bottom: 1px solid #aaa;
margin-bottom: .5em;
}
details .collapse-spell::before {
content: "Click to show spell";
}
details[open] .collapse-spell::before {
content: "Click to hide spell";
}
blockquote.crafting-info {
font-size: inherit;
}
a.permalink {
margin-left: 0.5em;
}
a.permalink:hover {
color: lightgray;
}
p {
margin: 0.5ex 0;
}
p.fake-li {
margin: 0;
}
p.fake-li::before {
content: "\2022";
margin: 1ex;
}
.linkout::before {
content: "Link: ";
}
p.todo-note {
font-style: italic;
color: lightgray;
}
.obfuscated {
filter: blur(1em);
}
.spoilered {
filter: blur(1ex);
-moz-transition: filter 0.04s linear;
}
.spoilered:hover {
filter: blur(0.5ex);
}
.spoilered.unspoilered {
filter: blur(0);
}
canvas.spell-viz {
--dot-color: #777f;
--dot-color: #777f;
--start-dot-color: #f009;
--moving-dot-color: #0fa9;
--path-color: darkgray;
--visited-path-color: #0c8;
--dot-scale: 0.0625;
--moving-dot-scale: 0.125;
--line-scale: 0.08333;
--pausetext-scale: 0.5;
--dark-mode: 0;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #201a20;
color: #ddd;
}
.jumbotron {
background-color: #323;
}
canvas.spell-viz {
/* hack */
--dark-mode: 1;
}
}
{% filter indent(6) %}
{%+ include "main.css.jinja" %}
{% endfilter %}
</style>
<noscript>
<style>
<style>
/* for accessibility */
.spoilered {
filter: none !important;
}
</style>
</style>
</noscript>
<script>
{# TODO: kinda hacky #}
{% filter indent(6) %}
{%+ include_raw "main.js" %}
{% endfilter +%}
{% endfilter %}
</script>
</head>
</head>
<body>
<div class="container" style="margin-top: 3em;">
<blockquote>
<h1>This is the online version of the {{ mod_name }} documentation.</h1>
<p>Embedded images and patterns are included, but not crafting recipes or items. There's an in-game book for
those.</p>
{% if is_bleeding_edge %}
<p>Additionally, this is built from the latest code on GitHub. It may describe <b>newer</b> features that you
may not necessarily have, even on the latest CurseForge version!</p>
{% endif %}
<p><b>Entries which are blurred are spoilers</b>. Click to reveal them, but be aware that they may spoil endgame
progression. Alternatively, click <a href="?nospoiler">here</a> to get a version with all spoilers showing.
</p>
</blockquote>
</div>
{% filter hexdoc_minify %}
{% include "book.html.jinja" %}
{% endfilter +%}
</body>
<body>
{% include "welcome.html.jinja" +%}
{% include "book.html.jinja" +%}
</body>
</html>

147
doc/templates/main.js vendored
View file

@ -1,8 +1,10 @@
"use strict";
const speeds = [0, 0.25, 0.5, 1, 2, 4];
const scrollThreshold = 100;
const rfaQueue = [];
const colorCache = new Map();
function getColorRGB(ctx, str) {
if (!colorCache.has(str)) {
ctx.fillStyle = str;
@ -13,28 +15,45 @@ function getColorRGB(ctx, str) {
}
return colorCache.get(str);
}
function startAngle(str) {
switch (str) {
case "east": return 0;
case "north_east": return 1;
case "north_west": return 2;
case "west": return 3;
case "south_west": return 4;
case "south_east": return 5;
default: return 0;
case "east":
return 0;
case "north_east":
return 1;
case "north_west":
return 2;
case "west":
return 3;
case "south_west":
return 4;
case "south_east":
return 5;
default:
return 0;
}
}
function offsetAngle(str) {
switch (str) {
case "w": return 0;
case "q": return 1;
case "a": return 2;
case "s": return 3;
case "d": return 4;
case "e": return 5;
default: return -1;
case "w":
return 0;
case "q":
return 1;
case "a":
return 2;
case "s":
return 3;
case "d":
return 4;
case "e":
return 5;
default:
return -1;
}
}
function initializeElem(canvas) {
const str = canvas.dataset.string;
let angle = startAngle(canvas.dataset.start);
@ -43,12 +62,13 @@ function initializeElem(canvas) {
// build geometry
const points = [[0, 0]];
let lastPoint = points[0];
let minPoint = lastPoint, maxPoint = lastPoint;
let minPoint = lastPoint,
maxPoint = lastPoint;
for (const ch of "w" + str) {
const addAngle = offsetAngle(ch);
if (addAngle < 0) continue;
angle = (angle + addAngle) % 6;
const trueAngle = Math.PI / 3 * angle;
const trueAngle = (Math.PI / 3) * angle;
const [lx, ly] = lastPoint;
const newPoint = [lx + Math.cos(trueAngle), ly - Math.sin(trueAngle)];
@ -62,13 +82,24 @@ function initializeElem(canvas) {
maxPoint = [Math.max(max, newPoint[0]), Math.max(may, newPoint[1])];
}
const size = Math.min(canvas.width, canvas.height) * 0.8;
const scale = size / Math.max(3, Math.max(maxPoint[1] - minPoint[1], maxPoint[0] - minPoint[0]));
const center = [(minPoint[0] + maxPoint[0]) * 0.5, (minPoint[1] + maxPoint[1]) * 0.5];
const truePoints = points.map(p => [canvas.width * 0.5 + scale * (p[0] - center[0]), canvas.height * 0.5 + scale * (p[1] - center[1])]);
const scale =
size /
Math.max(3, Math.max(maxPoint[1] - minPoint[1], maxPoint[0] - minPoint[0]));
const center = [
(minPoint[0] + maxPoint[0]) * 0.5,
(minPoint[1] + maxPoint[1]) * 0.5,
];
const truePoints = points.map((p) => [
canvas.width * 0.5 + scale * (p[0] - center[0]),
canvas.height * 0.5 + scale * (p[1] - center[1]),
]);
let uniqPoints = [];
l1: for (const point of truePoints) {
for (const pt of uniqPoints) {
if (Math.abs(point[0] - pt[0]) < 0.00001 && Math.abs(point[1] - pt[1]) < 0.00001) {
if (
Math.abs(point[0] - pt[0]) < 0.00001 &&
Math.abs(point[1] - pt[1]) < 0.00001
) {
continue l1;
}
}
@ -83,14 +114,15 @@ function initializeElem(canvas) {
let scrollTimeout = 1e309;
let speedLevel = 3;
let speedIncrement = 0;
function speedScale() {
return speeds[speedLevel];
}
const style = getComputedStyle(canvas);
const getProp = n => style.getPropertyValue(n);
const getProp = (n) => style.getPropertyValue(n);
const tick = dt => {
const tick = (dt) => {
scrollTimeout += dt;
if (canvas.offsetParent === null) return;
@ -107,18 +139,24 @@ function initializeElem(canvas) {
const pauseScale = scale * +getProp("--pausetext-scale");
const bodyBg = scale * +getProp("--pausetext-scale");
const darkMode = +getProp("--dark-mode");
const bgColors = getColorRGB(context, getComputedStyle(document.body).backgroundColor);
const bgColors = getColorRGB(
context,
getComputedStyle(document.body).backgroundColor
);
if (!perWorld) {
progress += speed * dt * (progress > 0 ? speedScale() : Math.sqrt(speedScale()));
progress +=
speed * dt * (progress > 0 ? speedScale() : Math.sqrt(speedScale()));
}
if (progress >= truePoints.length - 1) {
progress = negaProgress;
}
let ix = Math.floor(progress), frac = progress - ix, core = null, fadeColor = 0;
let ix = Math.floor(progress),
frac = progress - ix,
core = null,
fadeColor = 0;
if (ix < 0) {
const rawFade = 2 * progress / negaProgress - 1;
const rawFade = (2 * progress) / negaProgress - 1;
fadeColor = 1 - Math.abs(rawFade);
context.strokeStyle = rawFade > 0 ? strokeVisitedStyle : strokeStyle;
ix = rawFade > 0 ? truePoints.length - 2 : 0;
@ -131,7 +169,6 @@ function initializeElem(canvas) {
const [rx, ry] = truePoints[ix + 1];
core = [lx + (rx - lx) * frac, ly + (ry - ly) * frac];
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.lineWidth = strokeWidth;
@ -151,8 +188,8 @@ function initializeElem(canvas) {
for (let i = 0; i < uniqPoints.length; i++) {
context.beginPath();
context.fillStyle = (i == 0 && !perWorld) ? startDotStyle : dotStyle;
const radius = (i == 0 && !perWorld) ? movDotRadius : dotRadius;
context.fillStyle = i == 0 && !perWorld ? startDotStyle : dotStyle;
const radius = i == 0 && !perWorld ? movDotRadius : dotRadius;
context.arc(uniqPoints[i][0], uniqPoints[i][1], radius, 0, 2 * Math.PI);
context.fill();
}
@ -168,16 +205,22 @@ function initializeElem(canvas) {
context.fillRect(0, 0, canvas.width, canvas.height);
}
if (scrollTimeout <= 2000) {
context.fillStyle = `rgba(200, 200, 200, ${(2000 - scrollTimeout) / 1000})`;
context.fillStyle = `rgba(200, 200, 200, ${
(2000 - scrollTimeout) / 1000
})`;
context.font = `${pauseScale}px sans-serif`;
context.fillText(speedScale() ? speedScale() + "x" : "Paused", 0.2 * scale, canvas.height - 0.2 * scale);
context.fillText(
speedScale() ? speedScale() + "x" : "Paused",
0.2 * scale,
canvas.height - 0.2 * scale
);
}
};
rfaQueue.push(tick);
// scrolling input
if (!perWorld) {
canvas.addEventListener("wheel", ev => {
canvas.addEventListener("wheel", (ev) => {
speedIncrement += ev.deltaY;
const oldSpeedLevel = speedLevel;
if (speedIncrement >= scrollThreshold) {
@ -194,6 +237,7 @@ function initializeElem(canvas) {
});
}
}
function hookLoad(elem) {
let init = false;
const canvases = elem.querySelectorAll("canvas");
@ -204,22 +248,27 @@ function hookLoad(elem) {
}
});
}
function hookToggle(elem) {
const details = Array.from(document.querySelectorAll("details." + elem.dataset.target));
const details = Array.from(
document.querySelectorAll("details." + elem.dataset.target)
);
elem.addEventListener("click", () => {
if (details.some(x => x.open)) {
details.forEach(x => x.open = false);
if (details.some((x) => x.open)) {
details.forEach((x) => (x.open = false));
} else {
details.forEach(x => x.open = true);
details.forEach((x) => (x.open = true));
}
});
}
const params = new URLSearchParams(document.location.search);
function hookSpoiler(elem) {
if (params.get("nospoiler") !== null) {
elem.classList.add("unspoilered");
} else {
const thunk = ev => {
const thunk = (ev) => {
if (!elem.classList.contains("unspoilered")) {
ev.preventDefault();
ev.stopImmediatePropagation();
@ -232,21 +281,27 @@ function hookSpoiler(elem) {
if (elem instanceof HTMLAnchorElement) {
const href = elem.getAttribute("href");
if (href.startsWith("#")) {
elem.addEventListener("click", () => document.getElementById(href.substring(1)).querySelector(".spoilered").classList.add("unspoilered"));
elem.addEventListener("click", () =>
document
.getElementById(href.substring(1))
.querySelector(".spoilered")
.classList.add("unspoilered")
);
}
}
}
}
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('details.spell-collapsible').forEach(hookLoad);
document.querySelectorAll('a.toggle-link').forEach(hookToggle);
document.querySelectorAll('.spoilered').forEach(hookSpoiler);
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll("details.spell-collapsible").forEach(hookLoad);
document.querySelectorAll("a.toggle-link").forEach(hookToggle);
document.querySelectorAll(".spoilered").forEach(hookSpoiler);
function tick(prevTime, time) {
const dt = time - prevTime;
for (const q of rfaQueue) {
q(dt);
}
requestAnimationFrame(t => tick(time, t));
requestAnimationFrame((t) => tick(time, t));
}
requestAnimationFrame(t => tick(t, t));
});
requestAnimationFrame((t) => tick(t, t));
});

View file

@ -1,9 +1,9 @@
{% extends "pages/PageWithTitle.html.jinja" %}
{% block inner_body %}
<p class='img-wrapper'>
<p class="img-wrapper">
{% for image in page.images %}
<img src='{{ props.asset_url(image) }}'></img>
<img src="{{ props.asset_url(image) }}"></img>
{% endfor %}
</p>
{{ super() }}

View file

@ -1,8 +1,8 @@
{% extends "pages/PageWithTitle.html.jinja" %}
{% block inner_body %}
{{- super() }}
<h4 class='linkout'>
<a href='{{ page.url|hexdoc_escape }}'>{{ page.link_text }}</a>
{{ super() }}
<h4 class="linkout">
<a href="{{ page.url }}">{{ page.link_text }}</a>
</h4>
{% endblock inner_body %}

View file

@ -1,3 +1,3 @@
{% extends "pages/PageWithPattern.html.jinja" %}
{% block title_attrs %} class='pattern-title'{% endblock %}
{% block title_attrs %} class="pattern-title"{% endblock %}

View file

@ -1,12 +1,12 @@
{% if page.anchor %}
{# set variable to allow children to use this value too #}
{% set page_anchor_id = entry.id.path ~ "@" ~ page.anchor -%}
{% set page_anchor_id = entry.id.path ~ "@" ~ page.anchor %}
{# page content (not required because EmptyPage uses this template directly) -#}
<div id='{{ page_anchor_id }}'>
{% block body scoped %}{% endblock -%}
{#- page content (not required because EmptyPage uses this template directly) #}
<div id="{{ page_anchor_id }}">
{% block body scoped %}{% endblock %}
</div>
{% else %}
{{- self.body() }}
{{ self.body() }}
{% endif %}
<br />

View file

@ -1,13 +1,17 @@
{% extends "pages/PageWithTitle.html.jinja" %}
{% block inner_body %}
<details class='spell-collapsible'>
<summary class='collapse-spell'></summary>
<details class="spell-collapsible">
<summary class="collapse-spell"></summary>
{% for pattern in page.patterns %}
<canvas class='spell-viz' width='216' height='216' data-string='{{ pattern.signature }}' data-start='{{ pattern.startdir.name.lower() }}' data-per-world='{{ pattern.is_per_world }}'>
Your browser does not support visualizing patterns. Pattern code: {{ pattern.signature }}
</canvas>
<canvas
class="spell-viz"
width="216"
height="216"
data-string="{{ pattern.signature }}"
data-start="{{ pattern.startdir.name.lower() }}"
data-per-world="{{ pattern.is_per_world }}"
>Your browser does not support visualizing patterns. Pattern code: {{ pattern.signature }}</canvas>
{% endfor %}
</details>
{{ super() }}

View file

@ -5,15 +5,16 @@
{% if page.title is not none %}
{# need title_attrs for LookupPatternPage -#}
<h4{% block title_attrs %}{% endblock %}>
{{ page.title|hexdoc_escape }}
{% if page_anchor_id is defined %} {# conditionally defined in Page #}
{{ macros.permalink(page_anchor_id) }}
{% endif %}
{{- page.title -}}
{# conditionally defined in Page #}
{%- if page_anchor_id is defined %}
{{- macros.permalink(page_anchor_id) -}}
{% endif -%}
</h4>
{% endif %}
{# within a separate block so we can control if the text goes before or after page-specific content #}
{% block inner_body %}
{{- page.text|hexdoc_block }}
{{ page.text|hexdoc_block }}
{% endblock inner_body %}
{% endblock body %}

View file

@ -1,6 +1,6 @@
{% extends "pages/PageWithTitle.html.jinja" %}
{% block inner_body %}
<h4 class='spotlight-title page-header'>{{ page.item }}</h4>
<h4 class="spotlight-title page-header">{{ page.item }}</h4>
{{ super() }}
{% endblock inner_body %}

View file

@ -0,0 +1,24 @@
{% import "macros.html.jinja" as macros -%}
<h2 id="table-of-contents" class="page-header">
Table of Contents<a
href="javascript:void(0)"
class="permalink toggle-link small"
data-target="toc-category"
title="Toggle all"
><i class="bi bi-list-nested"></i></a>{{ macros.permalink("table-of-contents") }}
</h2>
{% for category in book.categories.values() %}
<details class="toc-category">
{# category #}
<summary>{{ macros.maybe_spoilered_link(category) }}</summary>
{# list of entries in the category #}
<ul>
{% for entry in category.entries %}
<li>{{ macros.maybe_spoilered_link(entry) }}</li>
{% endfor %}
</ul>
</details>
{% endfor %}

View file

@ -1,25 +0,0 @@
{% import "macros.html.jinja" as macros %}
{# section header #}
<h2 id='table-of-contents' class='page-header'>
Table of Contents
<a href='javascript:void(0)' class='permalink toggle-link small' data-target='toc-category' title='Toggle all'>
<i class='bi bi-list-nested'></i>
</a>
{{ macros.permalink("table-of-contents") }}
</h2>
{# table of contents #}
{% for category in book.categories.values() %}
<details class='toc-category'>
{# category #}
<summary>{{ macros.maybe_spoilered_link(category) }}</summary>
{# list of entries in the category #}
<ul>
{% for entry in category.entries %}
<li>{{ macros.maybe_spoilered_link(entry) }}</li>
{% endfor %}
</ul>
</details>
{% endfor %}

20
doc/templates/welcome.html.jinja vendored Normal file
View file

@ -0,0 +1,20 @@
<div class="container" style="margin-top: 3em;">
<blockquote>
<h1>This is the online version of the {{ mod_name }} documentation.</h1>
<p>
Embedded images and patterns are included, but not crafting recipes or items. There's an in-game book for those.
</p>
{% if is_bleeding_edge %}
<p>
Additionally, this is built from the latest code on GitHub.
It may describe <b>newer</b> features that you may not necessarily have, even on the latest CurseForge version!
</p>
{% endif %}
<p>
<b>Entries which are blurred are spoilers</b>. Click to reveal them, but be aware that they may spoil endgame
progression. Alternatively, click <a href="?nospoiler">here</a> to get a version with all spoilers showing.
</p>
</blockquote>
</div>