feat: refactored the overview
This commit is contained in:
parent
523402d3ad
commit
ee26af8b35
@ -1,41 +0,0 @@
|
|||||||
<!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">
|
|
||||||
|
|
||||||
<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>
|
|
211
stsg/build.py
211
stsg/build.py
@ -1,9 +1,10 @@
|
|||||||
|
from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import markdown
|
import markdown
|
||||||
from typing import Optional
|
from typing import Optional, Union, Dict, Generator
|
||||||
|
|
||||||
from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION
|
from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION
|
||||||
|
|
||||||
@ -11,87 +12,112 @@ from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION
|
|||||||
logger = logging.getLogger("stsg.build")
|
logger = logging.getLogger("stsg.build")
|
||||||
|
|
||||||
|
|
||||||
def copy_static(src, dst):
|
class CustomPath:
|
||||||
if not os.path.exists(src):
|
def __init__(self, path: Path):
|
||||||
logger.warn("The static folder '%s' wasn't defined.", src)
|
self.path = path
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return str(self.path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_path(self) -> Path:
|
||||||
|
return Path(SOURCE_DIRECTORY, self.path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dist_path(self) -> Path:
|
||||||
|
return Path(DIST_DIRECTORY, self.path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return Path(self.path).name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self) -> CustomPath:
|
||||||
|
return CustomPath(Path(self.path).parent)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stem(self) -> str:
|
||||||
|
return Path(self.path).stem
|
||||||
|
|
||||||
|
def iterdir(self) -> Generator[CustomPath, None, None]:
|
||||||
|
for p in self.source_path.iterdir():
|
||||||
|
yield CustomPath(Path(self.path, p.name))
|
||||||
|
|
||||||
|
def get_child(self, name: str, force_directory: bool = False, force_file: bool = False) -> Optional[CustomPath]:
|
||||||
|
child = Path(self.source_path, name)
|
||||||
|
|
||||||
|
if not child.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
if force_directory and not child.is_dir():
|
||||||
|
return None
|
||||||
|
|
||||||
|
if force_file and not child.is_file():
|
||||||
|
return None
|
||||||
|
|
||||||
|
return CustomPath(Path(self.path, name))
|
||||||
|
|
||||||
|
def read_text(self) -> str:
|
||||||
|
return self.source_path.read_text()
|
||||||
|
|
||||||
|
def copy_static(path: CustomPath):
|
||||||
|
src = path.source_path
|
||||||
|
dst = path.dist_path
|
||||||
|
|
||||||
|
if not src.exists():
|
||||||
|
logger.warning("The static folder '%s' wasn't defined.", src)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info("copying static files from '%s' to '%r'", src, dst)
|
logger.info("Copying static files from '%s' to '%s'", src, dst)
|
||||||
|
|
||||||
os.makedirs(dst, exist_ok=True)
|
dst.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
for root, dirs, files in os.walk(src):
|
for root, dirs, files in os.walk(src):
|
||||||
if any(p.startswith(".") for p in Path(root).parts):
|
root_path = Path(root)
|
||||||
|
|
||||||
|
if any(part.startswith(".") for part in root_path.parts):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Compute relative path from the source root
|
rel_path = root_path.relative_to(src)
|
||||||
rel_path = os.path.relpath(root, src)
|
dest_dir = dst / rel_path
|
||||||
dest_dir = os.path.join(dst, rel_path)
|
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
os.makedirs(dest_dir, exist_ok=True)
|
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.startswith("."):
|
if file.startswith("."):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
src_file = os.path.join(root, file)
|
src_file = root_path / file
|
||||||
dest_file = os.path.join(dest_dir, file)
|
dest_file = dest_dir / file
|
||||||
shutil.copy2(src_file, dest_file)
|
shutil.copy2(src_file, dest_file)
|
||||||
|
|
||||||
|
|
||||||
class Context:
|
|
||||||
def __init__(self, root: str = SOURCE_DIRECTORY):
|
|
||||||
self.file = None
|
|
||||||
|
|
||||||
current_root = Path(root)
|
class Article(CustomPath):
|
||||||
while current_root.parts and self.file is None:
|
def __init__(self, path: CustomPath):
|
||||||
current_file = Path(current_root, "index.html")
|
super().__init__(path.path)
|
||||||
if current_file.exists() and current_file.is_file:
|
|
||||||
self.file = current_file
|
|
||||||
|
|
||||||
current_root = current_root.parent
|
def get_content(self) -> str:
|
||||||
|
if self.name.endswith(".md"):
|
||||||
|
return markdown.markdown(self.read_text())
|
||||||
|
|
||||||
if self.file is None:
|
return self.read_text()
|
||||||
logger.error("couldn't find context for %s", root)
|
|
||||||
exit(1)
|
|
||||||
logger.info("%s found context %r", root, str(self.file))
|
|
||||||
|
|
||||||
def get_text(self, **placeholder_values: dict):
|
@property
|
||||||
text = self.file.read_text()
|
def article_directory(self) -> Path:
|
||||||
|
return self.dist_path.parent / self.stem
|
||||||
for key, value in placeholder_values.items():
|
|
||||||
text = text.replace(f"<{key}/>", value)
|
|
||||||
text = text.replace(f"<{key} />", value)
|
|
||||||
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def convert_md(src: Path, dst: Path, context: Optional[Context] = None):
|
|
||||||
logger.info("converting %s", src)
|
|
||||||
|
|
||||||
html_content = markdown.markdown(src.read_text())
|
|
||||||
context = context or Context(str(src.parent))
|
|
||||||
full_page = context.get_text(content=html_content)
|
|
||||||
|
|
||||||
folder_dst = dst.parent / dst.name.replace(".md", "")
|
|
||||||
folder_dst.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
with Path(folder_dst, "index.html").open("w") as f:
|
|
||||||
f.write(full_page)
|
|
||||||
|
|
||||||
|
|
||||||
class CustomLanguageCode:
|
class CustomLanguageCode:
|
||||||
def __init__(self, file: Path):
|
def __init__(self, file: CustomPath):
|
||||||
self.file: Path = file
|
self.file = file
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def language_code(self) -> str:
|
def language_code(self) -> str:
|
||||||
return self.file.name.replace(".md", "")
|
return self.file.stem
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def relative_url(self) -> str:
|
def relative_url(self) -> str:
|
||||||
return "/" + str(Path(self.file.parent, self.language_code))
|
return "/" + str(self)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"{self.language_code}"
|
return f"{self.language_code}"
|
||||||
@ -120,40 +146,67 @@ class CustomLanguageCode:
|
|||||||
return f'<ul><a href="{self.relative_url}"><bold>{self.flag} {self.native_name}</bold></a></ul>'
|
return f'<ul><a href="{self.relative_url}"><bold>{self.flag} {self.native_name}</bold></a></ul>'
|
||||||
|
|
||||||
|
|
||||||
def walk_directory(root):
|
class Template:
|
||||||
src_path = Path(SOURCE_DIRECTORY, root)
|
def __init__(self, root: CustomPath):
|
||||||
dst_path = Path(DIST_DIRECTORY, root)
|
self.root = root
|
||||||
|
|
||||||
context = Context(src_path)
|
self.articles = []
|
||||||
language_codes_found = []
|
|
||||||
|
|
||||||
for current_full_path in src_path.iterdir():
|
def copy(self):
|
||||||
current_name = Path(current_full_path).name
|
return Template(root=self.root)
|
||||||
current_dst = Path(dst_path, current_name)
|
|
||||||
current_src = Path(src_path, current_name)
|
|
||||||
|
|
||||||
if current_name == "static":
|
def _replace_keywords(self, text: str, **placeholder_values: str) -> str:
|
||||||
copy_static(current_src, current_dst)
|
for key, value in placeholder_values.items():
|
||||||
|
text = text.replace(f"<{key}/>", value)
|
||||||
|
text = text.replace(f"<{key} />", value)
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def article_template(self) -> str:
|
||||||
|
article = self.root.get_child("article.html", force_file=True)
|
||||||
|
return article.source_path.read_text() if article else "<content/>"
|
||||||
|
|
||||||
|
def convert_article(self, path: Article):
|
||||||
|
logger.info("converting %s", path)
|
||||||
|
|
||||||
|
article_text = self._replace_keywords(
|
||||||
|
self.article_template,
|
||||||
|
content = path.get_content(),
|
||||||
|
)
|
||||||
|
|
||||||
|
path.article_directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
with Path(path.article_directory, "index.html").open("w") as f:
|
||||||
|
f.write(article_text)
|
||||||
|
|
||||||
|
|
||||||
|
def walk_directory(root: CustomPath, template: Optional[Template] = None):
|
||||||
|
template_dir = root.get_child("_templates", force_directory=True)
|
||||||
|
if template_dir is not None:
|
||||||
|
template = Template(template_dir)
|
||||||
|
|
||||||
|
if template is None:
|
||||||
|
logger.error("Didn't find template for %d", root)
|
||||||
|
return
|
||||||
|
|
||||||
|
for current_path in root.iterdir():
|
||||||
|
if current_path.name.startswith("_") or current_path.name == "static":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_name.endswith(".md"):
|
if current_path.source_path.is_file():
|
||||||
convert_md(current_src, current_dst, context=context)
|
template.convert_article(Article(current_path))
|
||||||
|
|
||||||
language_codes_found.append(CustomLanguageCode(Path(root, current_name)))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_src.is_dir():
|
if current_path.source_path.is_dir():
|
||||||
walk_directory(Path(root, current_full_path.name))
|
walk_directory(current_path, template=template.copy())
|
||||||
|
|
||||||
content = f"""
|
|
||||||
<li>
|
|
||||||
{''.join(l.html_code for l in language_codes_found)}
|
static_dir = root.get_child("static", force_directory=True)
|
||||||
</li>
|
if static_dir:
|
||||||
"""
|
copy_static(static_dir)
|
||||||
with Path(dst_path, "index.html").open("w") as f:
|
|
||||||
f.write(context.get_text(content=content))
|
|
||||||
|
|
||||||
|
|
||||||
def build():
|
def build():
|
||||||
logger.info("building static page")
|
logger.info("building static page")
|
||||||
walk_directory("")
|
walk_directory(CustomPath(Path()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user