1import os
2
3import frontmatter
4
5from plain.templates import Template
6from plain.utils.functional import cached_property
7
8from .markdown import render_markdown
9
10
11class Page:
12 def __init__(self, url_path, relative_path, absolute_path):
13 self.url_path = url_path
14 self.relative_path = relative_path
15 self.absolute_path = absolute_path
16
17 @cached_property
18 def _frontmatter(self):
19 with open(self.absolute_path) as f:
20 return frontmatter.load(f)
21
22 @cached_property
23 def vars(self):
24 return self._frontmatter.metadata
25
26 @cached_property
27 def title(self):
28 default_title = os.path.splitext(os.path.basename(self.relative_path))[0]
29 return self.vars.get("title", default_title)
30
31 @cached_property
32 def content(self):
33 # Strip the frontmatter
34 content = self._frontmatter.content
35
36 if not self.vars.get("render_plain", False):
37 template = Template(os.path.join("pages", self.relative_path))
38 content = template.render({})
39 # Strip the frontmatter again, since it was in the template file itself
40 _, content = frontmatter.parse(content)
41
42 if self.content_type == "markdown":
43 content = render_markdown(content)
44
45 return content
46
47 @property
48 def content_type(self):
49 extension = os.path.splitext(self.absolute_path)[1]
50
51 # Explicitly define the known content types that we intend to handle
52 # (others will still pass through)
53 if extension == ".md":
54 return "markdown"
55
56 if extension == ".html":
57 return "html"
58
59 if extension == ".redirect":
60 return "redirect"
61
62 return extension.lstrip(".")
63
64 def get_template_name(self):
65 if template_name := self.vars.get("template_name"):
66 return template_name
67
68 return f"{self.content_type}.html"