added packaged template resources
This commit is contained in:
parent
c4505502e8
commit
ca58a0758c
13 changed files with 135 additions and 54 deletions
|
@ -1,5 +1,6 @@
|
|||
from rich import print
|
||||
from zona.models import Item, ItemType
|
||||
from zona.metadata import parse_metadata
|
||||
from zona import markdown as zmd
|
||||
from zona.templates import Templater
|
||||
from zona.layout import Layout, discover_layout
|
||||
|
@ -38,7 +39,7 @@ class ZonaBuilder:
|
|||
if path.name.endswith(".md") and not path.is_relative_to(
|
||||
layout.root / "content" / "static"
|
||||
):
|
||||
item.metadata, item.content = util.parse_metadata(path)
|
||||
item.metadata, item.content = parse_metadata(path)
|
||||
item.type = ItemType.MARKDOWN
|
||||
item.copy = False
|
||||
name = destination.stem
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ metadata.title }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
href="{{ metadata.style }}"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
media="all"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
{% if header %}
|
||||
<header id="header">
|
||||
<center>
|
||||
{{ header | safe }}
|
||||
</center>
|
||||
<hr>
|
||||
</header>
|
||||
{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
{% if footer %}
|
||||
<footer id="footer">
|
||||
<hr>
|
||||
{{ footer | safe }}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
1
src/zona/data/templates/footer.md
Normal file
1
src/zona/data/templates/footer.md
Normal file
|
@ -0,0 +1 @@
|
|||
The footer content.
|
2
src/zona/data/templates/header.md
Normal file
2
src/zona/data/templates/header.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
- One
|
||||
- Two
|
6
src/zona/data/templates/page.html
Normal file
6
src/zona/data/templates/page.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<article>{{ content | safe }}</article>
|
||||
{% endblock %}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
from pathlib import Path
|
||||
from dataclasses import dataclass, asdict
|
||||
from zona.config import ZonaConfig, find_config
|
||||
from zona import util
|
||||
import yaml
|
||||
|
||||
|
||||
|
@ -54,9 +55,19 @@ def initialize_site(root: Path | None = None):
|
|||
raise FileExistsError(f"Config file already exists at {config}")
|
||||
# create requires layout
|
||||
layout = Layout.from_input(root=root, validate=False)
|
||||
for dir in [layout.root, layout.content, layout.templates]:
|
||||
# load template resources
|
||||
templates = util.get_resources("templates")
|
||||
for dir, resources in [
|
||||
(layout.root, None),
|
||||
(layout.content, None),
|
||||
(layout.templates, templates),
|
||||
]:
|
||||
if not dir.is_dir():
|
||||
dir.mkdir()
|
||||
if resources is not None:
|
||||
for r in resources:
|
||||
Path(r.name).write_text(r.contents)
|
||||
|
||||
config_path = layout.root / "config.yml"
|
||||
config = ZonaConfig()
|
||||
with open(config_path, "w") as f:
|
||||
|
|
|
@ -14,8 +14,6 @@ from pygments.formatters import HtmlFormatter
|
|||
from zona import util
|
||||
from zona.models import Item
|
||||
|
||||
# TODO: create Ashen pygments style (separate package probably)
|
||||
|
||||
|
||||
class ZonaRenderer(HTMLRenderer):
|
||||
def __init__(
|
||||
|
|
51
src/zona/metadata.py
Normal file
51
src/zona/metadata.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
|
||||
from dacite.config import Config
|
||||
from dacite.core import from_dict
|
||||
from dacite.exceptions import DaciteError
|
||||
from yaml import YAMLError
|
||||
import zona.util
|
||||
import frontmatter
|
||||
|
||||
|
||||
@dataclass
|
||||
class Metadata:
|
||||
title: str
|
||||
date: date
|
||||
description: str | None
|
||||
style: str | None = "/static/style.css"
|
||||
header: bool = True
|
||||
footer: bool = True
|
||||
template: str = "page.html"
|
||||
|
||||
|
||||
def parse_metadata(path: Path) -> tuple[Metadata, str]:
|
||||
"""
|
||||
Parses a file and returns parsed Metadata and its content. Defaults
|
||||
are applied for missing fields. If there is no metadata, a Metadata
|
||||
with default values is returned.
|
||||
|
||||
Raises:
|
||||
ValueError: If the metadata block is malformed in any way.
|
||||
"""
|
||||
try:
|
||||
post = frontmatter.load(str(path))
|
||||
except YAMLError as e:
|
||||
raise ValueError(f"YAML frontmatter error in {path}: {e}")
|
||||
raw_meta = post.metadata or {}
|
||||
defaults = {
|
||||
"title": zona.util.filename_to_title(path),
|
||||
"date": date.fromtimestamp(path.stat().st_mtime),
|
||||
}
|
||||
meta = {**defaults, **raw_meta}
|
||||
try:
|
||||
metadata = from_dict(
|
||||
data_class=Metadata,
|
||||
data=meta,
|
||||
config=Config(check_types=True, strict=True),
|
||||
)
|
||||
except DaciteError as e:
|
||||
raise ValueError(f"Malformed metadata in {path}: {e}")
|
||||
return metadata, post.content
|
|
@ -1,20 +1,8 @@
|
|||
from pathlib import Path
|
||||
from enum import Enum
|
||||
from datetime import date
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
|
||||
from zona.layout import Layout
|
||||
|
||||
|
||||
@dataclass
|
||||
class Metadata:
|
||||
title: str
|
||||
date: date
|
||||
description: str | None
|
||||
style: str | None = "/static/style.css"
|
||||
header: bool = True
|
||||
footer: bool = True
|
||||
template: str = "page.html"
|
||||
from zona.metadata import Metadata
|
||||
|
||||
|
||||
class ItemType(Enum):
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
from datetime import date
|
||||
from typing import NamedTuple
|
||||
from rich import print
|
||||
from importlib import resources
|
||||
import fnmatch
|
||||
from pathlib import Path
|
||||
from shutil import copy2
|
||||
import string
|
||||
|
||||
from dacite import Config, DaciteError, from_dict
|
||||
import frontmatter
|
||||
from yaml import YAMLError
|
||||
|
||||
from zona.models import Metadata
|
||||
class ZonaResource(NamedTuple):
|
||||
name: str
|
||||
contents: str
|
||||
|
||||
|
||||
def get_resources(subdir: str) -> list[ZonaResource]:
|
||||
"""Load the packaged resources in data/subdir"""
|
||||
out: list[ZonaResource] = []
|
||||
for resource in (
|
||||
resources.files("zona").joinpath(f"data/{subdir}").iterdir()
|
||||
):
|
||||
out.append(
|
||||
ZonaResource(f"{subdir}/{resource.name}", resource.read_text())
|
||||
)
|
||||
print(out)
|
||||
return out
|
||||
|
||||
|
||||
def ensure_parents(target: Path):
|
||||
|
@ -37,33 +51,3 @@ def normalize_url(url: str) -> str:
|
|||
def should_ignore(path: Path, patterns: list[str], base: Path) -> bool:
|
||||
rel_path = path.relative_to(base)
|
||||
return any(fnmatch.fnmatch(str(rel_path), pattern) for pattern in patterns)
|
||||
|
||||
|
||||
def parse_metadata(path: Path) -> tuple[Metadata, str]:
|
||||
"""
|
||||
Parses a file and returns parsed Metadata and its content. Defaults
|
||||
are applied for missing fields. If there is no metadata, a Metadata
|
||||
with default values is returned.
|
||||
|
||||
Raises:
|
||||
ValueError: If the metadata block is malformed in any way.
|
||||
"""
|
||||
try:
|
||||
post = frontmatter.load(str(path))
|
||||
except YAMLError as e:
|
||||
raise ValueError(f"YAML frontmatter error in {path}: {e}")
|
||||
raw_meta = post.metadata or {}
|
||||
defaults = {
|
||||
"title": filename_to_title(path),
|
||||
"date": date.fromtimestamp(path.stat().st_mtime),
|
||||
}
|
||||
meta = {**defaults, **raw_meta}
|
||||
try:
|
||||
metadata = from_dict(
|
||||
data_class=Metadata,
|
||||
data=meta,
|
||||
config=Config(check_types=True, strict=True),
|
||||
)
|
||||
except DaciteError as e:
|
||||
raise ValueError(f"Malformed metadata in {path}: {e}")
|
||||
return metadata, post.content
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
from datetime import date
|
||||
from zona.models import Metadata
|
||||
from zona.metadata import Metadata
|
||||
from zona.builder import split_metadata, discover, build
|
||||
from pathlib import Path
|
||||
|
||||
|
|
|
@ -7,3 +7,8 @@ def test_title(tmp_path: Path):
|
|||
b = tmp_path / "Writing_emails_Post.md"
|
||||
assert util.filename_to_title(a) == "My First Post"
|
||||
assert util.filename_to_title(b) == "Writing Emails Post"
|
||||
|
||||
|
||||
def test_get_resourcees():
|
||||
util.get_resources("templates")
|
||||
assert True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue