edited templates

This commit is contained in:
Hazel Noack 2025-05-22 15:47:46 +02:00
parent f2a3d7ada4
commit 2690f0af87
6 changed files with 134 additions and 81 deletions

View File

@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/static/icon.ico">
<title>{{slug}}</title>
<title>{{name}}</title>
<link rel="stylesheet" href="/static/bulma.min.css" />
<link rel="stylesheet" href="/static/style.css" />
</head>
@ -16,7 +16,7 @@
>
<div class="navbar-brand">
<a class="navbar-item" href="#">
<strong>Static Translated Site Generator</strong>
<strong>{{name}}</strong>
</a>
</div>
</nav>
@ -33,7 +33,7 @@
<div class="card mb-4" lang="{{t.language.code}}" style="height: 100%;">
<a href="{{t.url}}" hreflang="{{t.language.code}}" class="card mb-4" style="color: inherit; text-decoration: none;">
<div class="card-content">
<p class="title">{{t.language.flag}} {{t.title}}</p>
<p class="title">{{t.language.flag}} {{t.name}}</p>
<hr />
<p class="content">
{{t.preview}}
@ -41,7 +41,7 @@
</div>
<div class="card-footer">
<time class="card-footer-item" datetime="{{iso_date}}">{{date}}</time>
<time class="card-footer-item" datetime="{{t.iso_date}}">{{t.date}}</time>
</div>
</a>
</div>
@ -62,15 +62,15 @@
<div class="card mb-4" >
<a href="{{c.url}}" class="card mb-4" style="color: inherit; text-decoration: none;">
<div class="card-content">
<p class="title">{{c.slug}} </p>
<p class="title">{{c.name}} </p>
<hr />
<p class="content is-flex is-flex-direction-column" style="gap: 10px;">
{% for ct in c.translations %}
<a href="{{ct.url}}" hreflang="{{ct.language.code}}">{{ct.language.flag}}: {{ct.title}}</a>
<a href="{{ct.url}}" hreflang="{{ct.language.code}}">{{ct.language.flag}}: {{ct.name}}</a>
{% endfor %}
</p>
<hr />
<time datetime="{{iso_date}}">{{date}}</time>
<time datetime="{{c.iso_date}}">{{c.date}}</time>
</div>
</a>
</div>
@ -83,7 +83,7 @@
<!-- Footer -->
<footer class="footer">
<div class="content has-text-centered">
<p><strong>STSG</strong> by Hazel. &copy; 2025</p>
<p><strong>{{name}}</strong> by {{author}}. &copy; 2025</p>
</div>
</footer>
</body>

View File

@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/static/icon.ico">
<title>{{title}}</title>
<title>{{name}}</title>
<link rel="stylesheet" href="/static/bulma.min.css" />
<link rel="stylesheet" href="/static/style.css" />
</head>
@ -18,7 +18,7 @@
<div class="navbar-brand">
<a class="navbar-item" href="{{article_url}}">
<strong>{{language.flag}} {{title}}</strong>
<time datetime="{{meta.iso_date}}">{{meta.date}}</time>
<time datetime="{{iso_date}}">{{date}}</time>
</a>
</div>
</nav>
@ -39,7 +39,7 @@
<div class="card mb-4" >
<a href="{{c.url}}" hreflang="{{c.language.code}}" class="card mb-4" style="color: inherit; text-decoration: none;">
<div class="card-content">
<p class="title">{{c.title}}</p>
<p class="title">{{c.name}}</p>
<hr />
<p class="content">
{{c.preview}}
@ -47,7 +47,7 @@
</div>
<div class="card-footer">
<time class="card-footer-item" datetime="{{c.meta.iso_date}}">{{c.meta.date}}</time>
<time class="card-footer-item" datetime="{{c.iso_date}}">{{c.date}}</time>
</div>
</a>
</div>
@ -61,7 +61,7 @@
<!-- Footer -->
<footer class="footer">
<div class="content has-text-centered">
<p><strong>STSG</strong> by Hazel. &copy; 2025</p>
<p><strong>{{name}}</strong> by {{author}}. &copy; 2025</p>
</div>
</footer>
</body>

View File

@ -1,3 +1,5 @@
fall_back_to_overview_in_translation = false
[setup]
source_directory = "src"
dist_directory = "dist"

View File

@ -1,5 +1,6 @@
class config:
default_author = "anonymous"
fall_back_to_overview_in_translation = True
class setup:
source_directory = "src"

View File

@ -6,7 +6,7 @@ import os
from markdown2 import markdown
from typing import Optional, Union, Dict, Generator, List, DefaultDict, Any, TypedDict, Set
from bs4 import BeautifulSoup
from collections import defaultdict
from collections import defaultdict, UserList
import toml
from datetime import datetime
import jinja2
@ -17,16 +17,6 @@ from .definitions import *
from . import config
def get_first_header_content(content, fallback: str = ""):
soup = BeautifulSoup(content, 'html.parser')
for level in range(1, 7):
header = soup.find(f'h{level}')
if header:
return header.get_text(strip=True)
return fallback
def shorten_text_and_clean(html_string, max_length=config.formatting.preview_length):
soup = BeautifulSoup(html_string, 'html.parser')
@ -128,10 +118,62 @@ def add_html_link(c):
c["link"] = f'<a href="{url}">{name}</a>'
def get_translated_articles(articles: List[Article], language_code: str = None) -> List[Union[ArticleTranslation, Article]]:
result = {}
for a in articles:
if a.slug in result:
continue
if language_code is None:
result[a.slug] = a
continue
if not config.fall_back_to_overview_in_translation and language_code not in a.article_translations_map:
continue
result[a.slug] = a.article_translations_map.get(language_code, a)
class ArticleList(UserList):
def __init__(self, iterable):
super().__init__(item for item in iterable)
self.used_slugs = set()
def append(self, a: Union[Article, str]):
if isinstance(a, str):
a = ARTICLE_LAKE[a]
if a.slug in self.used_slugs:
return
self.used_slugs.add(a.slug)
self.data.append(a)
def extend(self, other):
for a in other:
self.append(a)
def get_translated(self, language_code: str) -> ArticleList[Union[ArticleTranslation, Article]]:
res = ArticleList([])
for a in self:
if not config.fall_back_to_overview_in_translation and language_code not in a.article_translations_map:
continue
res.append(a.article_translations_map.get(language_code, a))
return res
@property
def context(self) -> List[Union[ArticleContext, ArticleTranslationContext]]:
return [a.context for a in self]
class ArticleTranslation:
article: Article
slug: str = property(fget=lambda self: self.article.slug)
file: Path
@cached_property
@ -178,31 +220,32 @@ class ArticleTranslation:
self.article = article
self.file = file
self.context = {}
self.cross_article_context = TRANSLATED_CROSS_ARTICLE_CONTEXT[self.language_code][self.article.slug] = {}
self.context = TRANSLATED_CROSS_ARTICLE_CONTEXT[self.language_code][self.article.slug] = {}
@cached_property
def name(self) -> str:
soup = BeautifulSoup(self.html_content, 'html.parser')
for level in range(1, 7):
header = soup.find(f'h{level}')
if header:
return header.get_text(strip=True)
return self.article.name
def __init_context__(self):
self.context["meta"] = self.article.context_shared
self.context["slug"] = self.article.slug
self.context["name"] = self.name
self.context["url"] = self.url
add_html_link(self.context)
self.context["date"] = self.article.modified_at.strftime(config.formatting.datetime_format)
self.context["iso_date"] = self.article.modified_at.isoformat()
self.context["author"] = self.article.author
self.context["language"] = LANGUAGES[self.language_code]
self.context["article_url"] = self.article.url
self.context["title"] = get_first_header_content(self.html_content, fallback=LANGUAGES[self.language_code]["native_name"])
self.cross_article_context.update(self.article.context_shared)
self.cross_article_context["title"] = self.context["title"]
self.cross_article_context["article_url"] = self.article.url
self.cross_article_context["url"] = self.url
add_html_link(self.cross_article_context)
# get children
self.context["children"] = [
c.article_translations_map[self.language_code].context for c in self.article.child_articles
if self.language_code in c.article_translations_map
]
self.linked_context = self.context["linked"] = []
self.related_context = self.context["related"] = []
self.context["children"] = self.article.child_articles.get_translated(self.language_code).context
def __init_content_context__(self):
template = jinja2.Template(self.html_content)
@ -216,17 +259,16 @@ class ArticleTranslation:
template.environment.context_class = jinja2.runtime.Context
accessed_keys = template.environment.accessed_keys
for key in accessed_keys:
a = ARTICLE_LAKE[key]
if self.language_code in a.article_translations_map:
self.linked_context.append(a.article_translations_map[self.language_code].context)
self.related_context.extend(self.linked_context)
self.related_context.extend(self.context["children"])
for key in accessed_keys:
self.article.linked_articles.append(key)
self.context["content"] = self.html_content
self.context["preview"] = get_preview_text(html_string=self.html_content)
self.context["linked"] = self.article.linked_articles.get_translated(self.language_code).context
self.context["related"] = self.article.related_articles.get_translated(self.language_code).context
def build(self):
self.dist_path.mkdir(parents=True, exist_ok=True)
@ -272,25 +314,17 @@ class Article:
context_shared: Dict[str, Any]
cross_article_context: Dict[str, Any]
child_articles: List[Article]
article_translations_list: List[ArticleTranslation]
child_articles: ArticleList[Article]
article_translations_list: ArticleList[ArticleTranslation]
article_translations_map: Dict[str, ArticleTranslation]
linked_articles: List[Article]
linked_articles: ArticleList[Article]
@cached_property
def related_articles(self) -> List[Article]:
used_slugs = set()
related = []
for a in [*self.child_articles, *self.linked_articles]:
if a.slug in used_slugs:
continue
used_slugs.add(a.slug)
related.append(a)
return related
def related_articles(self) -> ArticleList[Article]:
res = ArticleList(self.child_articles)
res.extend(self.linked_articles)
return res
def __init__(self, directory: Path, article_path: Optional[List[str]] = None, is_root: bool = False, parent: Optional[Article] = None):
self.directory = directory
@ -298,17 +332,15 @@ class Article:
self.article_path: List[Article] = article_path or []
self.article_path.append(self)
self.context: ArticleContext = {}
self.context_shared = {}
self.cross_article_context = CROSS_ARTICLE_CONTEXT[self.slug] = {}
self.context = CROSS_ARTICLE_CONTEXT[self.slug] = {}
ARTICLE_LAKE[self.slug] = self
self.linked_articles = []
self.linked_articles = ArticleList([])
# build the tree
self.child_articles = []
self.article_translations_list = []
self.child_articles = ArticleList([])
self.article_translations_list = ArticleList([])
self.article_translations_map = {}
for c in self.directory.iterdir():
@ -356,25 +388,24 @@ class Article:
self.context["author"] = self.author
# recursive context structures
self.context["translations"] = [t.context for t in self.self.article_translations_list]
self.context["children"] = [c.context for c in self.child_articles]
self.context["translations"] = self.article_translations_list.context
self.context["children"] = self.child_articles.context
for lang, article in self.article_translations_map.items():
self.context[lang] = article.context
for at in self.article_translations_list:
at.__init_context__()
# the __init_context__ functions of the translations needs to be called first
# because the linked articles will be set there
self.context["linked"] = [l.context for l in self.linked_articles]
self.context["related"] = [r.context for r in self.related_articles]
for a in self.child_articles:
a.__init_context__()
def __init_content_context__(self):
for at in self.article_translations_list:
at.__init_content_context__()
self.context["linked"] = self.linked_articles.context
self.context["related"] = self.related_articles.context
for a in self.child_articles:
a.__init_content_context__()
@ -400,9 +431,9 @@ class ContextDict(jinja2.runtime.Context):
# GLOBALS
logger = logging.getLogger("stsg.build")
ARTICLE_LAKE: Dict[str, Article] = {}
CROSS_ARTICLE_CONTEXT: Dict[str, Dict[str, Any]] = {}
TRANSLATED_CROSS_ARTICLE_CONTEXT: Dict[str, Dict[str, Dict[str, Any]]] = defaultdict(dict)
ARTICLE_LAKE: Dict[str, Article] = {}
ARTICLE_REFERENCE_VALUES: DefaultDict[str, Dict[str, str]] = defaultdict(dict)

View File

@ -1,5 +1,5 @@
from __future__ import annotations
from typing import TypedDict, List
from typing import TypedDict, List, Union
class ArticleConfig(TypedDict):
@ -24,6 +24,14 @@ class ArticleContext(TypedDict):
related: List[ArticleContext]
class TypedLanguage(TypedDict):
flag: str
name: str
native_name: str
priority: int
code: str
class ArticleTranslationContext(TypedDict):
slug: str
name: str
@ -33,7 +41,18 @@ class ArticleTranslationContext(TypedDict):
iso_date: str
author: str
translations: List[ArticleTranslationContext]
children: List[ArticleTranslationContext]
linked: List[ArticleTranslationContext]
related: List[ArticleTranslationContext]
language: TypedLanguage
article_url: str
"""
The type Union[ArticleTranslationContext, ArticleContext] exist,
because if the article it is linked to doesn't exist in the same languages it uses the overview instead.
If you dislike this behavior set:
config.fall_back_to_overview_in_translation = False
"""
children: List[Union[ArticleTranslationContext, ArticleContext]]
# you can't use these within the markdown text itself
content: str
preview: str
linked: List[Union[ArticleTranslationContext, ArticleContext]]
related: List[Union[ArticleTranslationContext, ArticleContext]]