feat: added a nice overview card site
This commit is contained in:
parent
ee26af8b35
commit
432f16ba08
40
src/_templates/article.html
Normal file
40
src/_templates/article.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>STSG</title>
|
||||||
|
<link rel="stylesheet" href="/static/bulma.min.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header (Navbar) -->
|
||||||
|
<nav
|
||||||
|
class="navbar is-primary"
|
||||||
|
role="navigation"
|
||||||
|
aria-label="main navigation"
|
||||||
|
>
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="#">
|
||||||
|
<strong>Static Translated Site Generator</strong>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="content">
|
||||||
|
<a href="../">Go Back</a>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
{article_content}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="content has-text-centered">
|
||||||
|
<p><strong>STSG</strong> by Hazel. © 2025</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
38
src/_templates/overview.html
Normal file
38
src/_templates/overview.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>STSG</title>
|
||||||
|
<link rel="stylesheet" href="/static/bulma.min.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Header (Navbar) -->
|
||||||
|
<nav
|
||||||
|
class="navbar is-primary"
|
||||||
|
role="navigation"
|
||||||
|
aria-label="main navigation"
|
||||||
|
>
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="#">
|
||||||
|
<strong>Static Translated Site Generator</strong>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="column is-half is-offset-one-quarter">
|
||||||
|
{overview_cards}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="content has-text-centered">
|
||||||
|
<p><strong>STSG</strong> by Hazel. © 2025</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
src/_templates/overview_card.html
Normal file
8
src/_templates/overview_card.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<div class="card mb-4">
|
||||||
|
<a href="{article_href}" class="card mb-4" style="color: inherit; text-decoration: none;">
|
||||||
|
<div class="card-content" href="{article_href}">
|
||||||
|
<p class="title">{article_language_flag} {article_language_name}</p>
|
||||||
|
<p class="content">{article_preview}</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
113
stsg/build.py
113
stsg/build.py
@ -4,9 +4,9 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import markdown
|
import markdown
|
||||||
from typing import Optional, Union, Dict, Generator
|
from typing import Optional, Union, Dict, Generator, List
|
||||||
|
|
||||||
from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION
|
from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION, ARTICLE_PREVIEW_LENGTH
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("stsg.build")
|
logger = logging.getLogger("stsg.build")
|
||||||
@ -92,32 +92,9 @@ def copy_static(path: CustomPath):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Article(CustomPath):
|
|
||||||
def __init__(self, path: CustomPath):
|
|
||||||
super().__init__(path.path)
|
|
||||||
|
|
||||||
def get_content(self) -> str:
|
|
||||||
if self.name.endswith(".md"):
|
|
||||||
return markdown.markdown(self.read_text())
|
|
||||||
|
|
||||||
return self.read_text()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def article_directory(self) -> Path:
|
|
||||||
return self.dist_path.parent / self.stem
|
|
||||||
|
|
||||||
|
|
||||||
class CustomLanguageCode:
|
class CustomLanguageCode:
|
||||||
def __init__(self, file: CustomPath):
|
def __init__(self, language_code: str):
|
||||||
self.file = file
|
self.language_code = language_code
|
||||||
|
|
||||||
@property
|
|
||||||
def language_code(self) -> str:
|
|
||||||
return self.file.stem
|
|
||||||
|
|
||||||
@property
|
|
||||||
def relative_url(self) -> str:
|
|
||||||
return "/" + str(self)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"{self.language_code}"
|
return f"{self.language_code}"
|
||||||
@ -141,44 +118,98 @@ class CustomLanguageCode:
|
|||||||
def native_name(self) -> str:
|
def native_name(self) -> str:
|
||||||
return self._get_additional_data()["native_name"]
|
return self._get_additional_data()["native_name"]
|
||||||
|
|
||||||
@property
|
|
||||||
def html_code(self) -> str:
|
|
||||||
return f'<ul><a href="{self.relative_url}"><bold>{self.flag} {self.native_name}</bold></a></ul>'
|
|
||||||
|
|
||||||
|
class Article(CustomPath):
|
||||||
|
def __init__(self, path: CustomPath):
|
||||||
|
super().__init__(path.path)
|
||||||
|
|
||||||
|
def get_content(self) -> str:
|
||||||
|
if self.name.endswith(".md"):
|
||||||
|
return markdown.markdown(self.read_text())
|
||||||
|
|
||||||
|
return self.read_text()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def article_directory(self) -> Path:
|
||||||
|
return self.dist_path.parent / self.stem
|
||||||
|
|
||||||
|
@property
|
||||||
|
def language_code(self) -> CustomLanguageCode:
|
||||||
|
return CustomLanguageCode(self.stem)
|
||||||
|
|
||||||
|
def get_article_keys(self) -> Dict[str, str]:
|
||||||
|
article_content = self.get_content()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"article_content": article_content,
|
||||||
|
"article_preview": article_content[:ARTICLE_PREVIEW_LENGTH],
|
||||||
|
"article_href": "/" + str(self.path.parent / self.stem),
|
||||||
|
"article_language_name": self.language_code.native_name,
|
||||||
|
"article_language_code": self.language_code.language_code,
|
||||||
|
"article_language_flag": self.language_code.flag,
|
||||||
|
}
|
||||||
|
|
||||||
class Template:
|
class Template:
|
||||||
def __init__(self, root: CustomPath):
|
def __init__(self, root: CustomPath):
|
||||||
self.root = root
|
self.root = root
|
||||||
|
|
||||||
self.articles = []
|
self.articles: List[Article] = []
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Template(root=self.root)
|
return Template(root=self.root)
|
||||||
|
|
||||||
def _replace_keywords(self, text: str, **placeholder_values: str) -> str:
|
def _replace_keywords(self, text: str, **placeholder_values: str) -> str:
|
||||||
for key, value in placeholder_values.items():
|
for key, value in placeholder_values.items():
|
||||||
text = text.replace(f"<{key}/>", value)
|
text = text.replace("{" + key + "}", value)
|
||||||
text = text.replace(f"<{key} />", value)
|
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
@property
|
def get_article_template(self) -> str:
|
||||||
def article_template(self) -> str:
|
|
||||||
article = self.root.get_child("article.html", force_file=True)
|
article = self.root.get_child("article.html", force_file=True)
|
||||||
return article.source_path.read_text() if article else "<content/>"
|
return article.source_path.read_text() if article else "{article_content}"
|
||||||
|
|
||||||
def convert_article(self, path: Article):
|
def build_article(self, path: Article):
|
||||||
logger.info("converting %s", path)
|
logger.info("converting %s", path)
|
||||||
|
|
||||||
article_text = self._replace_keywords(
|
article_text = self._replace_keywords(
|
||||||
self.article_template,
|
self.get_article_template(),
|
||||||
content = path.get_content(),
|
**path.get_article_keys(),
|
||||||
)
|
)
|
||||||
|
|
||||||
path.article_directory.mkdir(parents=True, exist_ok=True)
|
path.article_directory.mkdir(parents=True, exist_ok=True)
|
||||||
with Path(path.article_directory, "index.html").open("w") as f:
|
with Path(path.article_directory, "index.html").open("w") as f:
|
||||||
f.write(article_text)
|
f.write(article_text)
|
||||||
|
|
||||||
|
self.articles.append(path)
|
||||||
|
|
||||||
|
def get_overview_card_template(self) -> str:
|
||||||
|
overview_card = self.root.get_child("overview_card.html", force_file=True)
|
||||||
|
return overview_card.source_path.read_text() if overview_card else "<a href=\"{article_href}\"> {article_language_flag} {article_language_name} </a>"
|
||||||
|
|
||||||
|
def get_overview_template(self) -> str:
|
||||||
|
overview = self.root.get_child("overview.html", force_file=True)
|
||||||
|
return overview.source_path.read_text() if overview else "{overview_cards}"
|
||||||
|
|
||||||
|
def build_overview(self, root: CustomPath):
|
||||||
|
if not len(self.articles):
|
||||||
|
return
|
||||||
|
|
||||||
|
overview_card_template = self.get_overview_card_template()
|
||||||
|
|
||||||
|
overview_cards = "\n".join(self._replace_keywords(
|
||||||
|
overview_card_template,
|
||||||
|
**a.get_article_keys(),
|
||||||
|
) for a in self.articles)
|
||||||
|
|
||||||
|
overview_text = self._replace_keywords(
|
||||||
|
self.get_overview_template(),
|
||||||
|
overview_cards = overview_cards,
|
||||||
|
)
|
||||||
|
|
||||||
|
with Path(root.dist_path, "index.html").open("w") as f:
|
||||||
|
f.write(overview_text)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def walk_directory(root: CustomPath, template: Optional[Template] = None):
|
def walk_directory(root: CustomPath, template: Optional[Template] = None):
|
||||||
template_dir = root.get_child("_templates", force_directory=True)
|
template_dir = root.get_child("_templates", force_directory=True)
|
||||||
@ -194,13 +225,13 @@ def walk_directory(root: CustomPath, template: Optional[Template] = None):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if current_path.source_path.is_file():
|
if current_path.source_path.is_file():
|
||||||
template.convert_article(Article(current_path))
|
template.build_article(Article(current_path))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_path.source_path.is_dir():
|
if current_path.source_path.is_dir():
|
||||||
walk_directory(current_path, template=template.copy())
|
walk_directory(current_path, template=template.copy())
|
||||||
|
|
||||||
|
template.build_overview(root=root)
|
||||||
|
|
||||||
static_dir = root.get_child("static", force_directory=True)
|
static_dir = root.get_child("static", force_directory=True)
|
||||||
if static_dir:
|
if static_dir:
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
SOURCE_DIRECTORY = "src"
|
SOURCE_DIRECTORY = "src"
|
||||||
DIST_DIRECTORY = "dist"
|
DIST_DIRECTORY = "dist"
|
||||||
|
|
||||||
# relative to SOURCE_DIRECTORY / DIST_DIRECTORY
|
# config template stuff
|
||||||
STATIC_DIRECTORY = "static"
|
ARTICLE_PREVIEW_LENGTH = 200
|
||||||
|
|
||||||
# FOR DEVELOPMENT
|
# FOR DEVELOPMENT
|
||||||
|
|
||||||
CODE_DIRECTORY = "stsg"
|
CODE_DIRECTORY = "stsg"
|
||||||
|
|
||||||
# LANGUAGE INFORMATION
|
# LANGUAGE INFORMATION
|
||||||
|
Loading…
x
Reference in New Issue
Block a user