Add head configuration
This snippet allows users to configure their head in markata.toml
.
{{ config.get('head', {}).pop('text') if 'text' in config.get('head',{}).keys() }} {% for tag, meta in config.get('head', {}).items() %} {% for _meta in meta %} <{{ tag }} {% for attr, value in _meta.items() %}{{ attr }}="{{ value }}"{% endfor %} /> {% endfor %} {% endfor %}
Users can specify any sort of tag in their markata.toml
[[markata.head.meta]] name = "og:type" content = "article" [[markata.head.meta]] name = "og:author" content = "Waylon Walker"
The above configuration becomes this once rendered.
<meta name='og:type' content='article' /> <meta name='og:Author' content='Waylon Walker' />
!! Note
Article variables can be used for dynamic entries like canonical_url
``` toml
[markata]
url = "markata.dev"
[[markata.head.meta]]
href="{{ config.url }}/{{ slug }}/"
rel="canonical"
```
Optionally users can also specify plain text to be appended to the head of their documents. This works well for things that involve full blocks.
[[markata.head.text]] value = ''' <script> console.log('hello world') </script> ''' [[markata.head.text]] value=''' html { font-family: "Space Mono", monospace; background: var(--color-bg); color: var(--color-text); } '''
!! class
SilentUndefined class
"SilentUndefined source"
class SilentUndefined(Undefined): def _fail_with_undefined_error(self, *args, **kwargs): return ""
!! function
optional function
"optional source"
def optional(*fields): def dec(_cls): for field in fields: _cls.__fields__[field].default = None return _cls if ( fields and inspect.isclass(fields[0]) and issubclass(fields[0], pydantic.BaseModel) ): cls = fields[0] fields = cls.__fields__ return dec(cls) return dec
!! class
Style class
"Style source"
class Style(pydantic.BaseModel): color_bg: str = "#1f2022" color_bg_code: str = "#1f2022" color_text: str = "#eefbfe" color_link: str = "#fb30c4" color_accent: str = "#e1bd00c9" overlay_brightness: str = ".85" body_width: str = "800px" color_bg_light: str = "#eefbfe" color_bg_code_light: str = "#eefbfe" color_text_light: str = "#1f2022" color_link_light: str = "#fb30c4" color_accent_light: str = "#ffeb00" overlay_brightness_light: str = ".95"
!! class
StyleOverrides class
"StyleOverrides source"
class StyleOverrides(Style): ...
!! class
Meta class
"Meta source"
class Meta(pydantic.BaseModel): name: str content: str
!! class
Text class
"Text source"
class Text(pydantic.BaseModel): value: str
!! class
Link class
"Link source"
class Link(pydantic.BaseModel): rel: str = "canonical" href: str
!! class
HeadConfig class
"HeadConfig source"
class HeadConfig(pydantic.BaseModel): meta: List[Meta] = [] link: List[Link] = [] text: Union[List[Text], str] = "" @pydantic.validator("text", pre=True) def text_to_list(cls, v): if isinstance(v, list): return "\n".join([text["value"] for text in v]) return v @property def html(self): html = self.text html += "\n" for meta in self.meta: html += f'<meta name="{meta.name}" content="{meta.content}" />\n' for link in self.link: html += f'<link rel="{link.rel}" href="{link.href}" />\n' return html
!! class
Config class
"Config source"
class Config(pydantic.BaseModel): head: HeadConfig = HeadConfig() style: Style = Style() post_template: str = None @pydantic.validator("post_template", pre=True, always=True) def default_post_template(cls, v): if v is None: return ( Path(__file__).parent / "default_post_template.html.jinja" ).read_text() if isinstance(v, Path): return v.read_text() if isinstance(v, str) and Path(v).exists(): return Path(v).read_text() return v
!! class
PostOverrides class
"PostOverrides source"
class PostOverrides(pydantic.BaseModel): head: HeadConfig = HeadConfig() style: Style = StyleOverrides()
!! class
Post class
"Post source"
class Post(pydantic.BaseModel): config_overrides: PostOverrides = PostOverrides()
!! function
config_model function
"config_model source"
def config_model(markata: "Markata") -> None: markata.config_models.append(Config)
!! function
post_model function
"post_model source"
def post_model(markata: "Markata") -> None: markata.post_models.append(Post)
!! function
configure function
Massages the configuration limitations of toml to allow a little bit easier experience to the end user making configurations while allowing an simpler jinja template. This enablees the use of themarkata.head.text
list in
configuration.
"configure source"
def configure(markata: "Markata") -> None: """ Massages the configuration limitations of toml to allow a little bit easier experience to the end user making configurations while allowing an simpler jinja template. This enablees the use of the `markata.head.text` list in configuration. """
!! function
pre_render function
FOR EACH POST: Massages the configuration limitations of toml/yaml to allow a little bit easier experience to the end user making configurations while allowing an simpler jinja template. This enablees the use of themarkata.head.text
list in configuration.
"pre_render source"
def pre_render(markata: "Markata") -> None: """ FOR EACH POST: Massages the configuration limitations of toml/yaml to allow a little bit easier experience to the end user making configurations while allowing an simpler jinja template. This enablees the use of the `markata.head.text` list in configuration. """ for article in [a for a in markata.articles if "config_overrides" in a]: raw_text = article.get("config_overrides", {}).get("head", {}).get("text", "") if isinstance(raw_text, list): article["config_overrides"]["head"]["text"] = "\n".join( flatten([t.values() for t in raw_text]), )
!! function
render function
"render source"
def render(markata: "Markata") -> None: template = Template(markata.config.post_template, undefined=SilentUndefined) if "{{" in str(markata.config.get("head", {})): Template( str(markata.config.get("head", {})), undefined=SilentUndefined, ) else: pass merged_config = markata.config for article in [a for a in markata.articles if hasattr(a, "html")]: # TODO do we need to handle merge?? # if head_template: # head = eval( # head_template.render( # __version__=__version__, # config=_full_config, # **article, # ) # ) # merged_config = { # **_full_config, # **{"head": head}, # } # merged_config = always_merger.merge( # merged_config, # copy.deepcopy( # article.get( # "config_overrides", # {}, # ) # ), # ) article.html = template.render( __version__=__version__, body=article.html, toc=markata.md.toc, # type: ignore config=merged_config, post=article, **article.metadata, )
!! method
_fail_with_undefined_error method
"_fail_with_undefined_error source"
def _fail_with_undefined_error(self, *args, **kwargs): return ""
!! function
dec function
"dec source"
def dec(_cls): for field in fields: _cls.__fields__[field].default = None return _cls
!! method
text_to_list method
"text_to_list source"
def text_to_list(cls, v): if isinstance(v, list): return "\n".join([text["value"] for text in v]) return v
!! method
html method
"html source"
def html(self): html = self.text html += "\n" for meta in self.meta: html += f'<meta name="{meta.name}" content="{meta.content}" />\n' for link in self.link: html += f'<link rel="{link.rel}" href="{link.href}" />\n' return html
!! method
default_post_template method
"default_post_template source"
def default_post_template(cls, v): if v is None: return ( Path(__file__).parent / "default_post_template.html.jinja" ).read_text() if isinstance(v, Path): return v.read_text() if isinstance(v, str) and Path(v).exists(): return Path(v).read_text() return v