cuddly/README.md
2024-02-17 17:18:38 +01:00

159 lines
3.3 KiB
Markdown

# Cuddly
Generate HTML and PDF from KDL structed data.
## Installation
```
git clone https://git.bksp.space/hannaeko/cuddly
cd cuddly
python -m venv env
env/bin/pip install .
```
## Usage
### Example
Generating a PDF:
```
env/bin/cuddly --template samples/cv/cv.template.html --input samples/cv.kdl --output samples/cv.pdf
```
Generating a HTML file
```
env/bin/cuddly --template samples/cv/cv.template.html --input samples/cv.kdl --output samples/cv.html
```
### Template usage
The template language used is [Jinja](https://jinja.palletsprojects.com/en/3.0.x/), source template need to be a single HTML template file.
#### Base URL
When generating the PDF the base URL is set to the source template directory. All relative links to other resources (for example CSS and images) must be relative to that directory.
#### Accessing nodes values and attributes
Nodes are available as global variables in the template. The rendered value of a node is the first value that has been assigned to the node. This value can also be accessed using the `value` property. The list of values can be accessed using the `values` property.
```kdl
my_node "something" "other thing"
```
```jinja
{{ my_node }}
{{ my_node.value }}
{{ my_node.values | join(', ')}}
```
renders to
```
something
something
something, other thing
```
Accessing children nodes can be done using properties of the children names.
```kdl
my_node {
other_node "test"
}
```
```jinja
{{ my_node.other_node.value }}
```
renders to
```
test
```
If a node has multiple children of a same node type, then directly accessing the children properties will fail, a loop will be needed. Note that, on the other hand, looping on the children always work, even if there is only one child of the given type.
```kdl
my_node {
other_node "first"
other_node "second"
}
```
```jinja
{% for node in my_node.other_node %}
{{ node.value }}
{% endofr %}
```
renders to
```
first
second
```
Attributes of a node can be accessed through the `attributes` property:
```kdl
my_node version=42 "something"
```
```jinja
{{ my_node.attributes.version }}
```
renders to
```
42
```
#### Templating nodes
Node specific templates can be defined in the `components` element in the HTML template file. Nodes can then be rendered using those micro-templates using the `render` filter.
The context of the micro-template is the node being rendered. As such, children and properties of that node are in the global scope.
```kdl
menu "Midnight meal" price="10 €" {
dish name="Tomato soup" "Fancy tomato soup with a slice of bread"
dish name="Banana bread" "Amazing banana bread with a scoop of icecream"
}
```
```html
<!DOCTYPE html>
<html lang="{{ lang }}">
<head>
<meta charset="UTF-8">
</head>
<components>
<menu>
<h1>{{ value }}</h1>
<dl>
<dt>Price</dt>
<dd>{{ attributes.prices }}</dd>
</dl>
<dl>
{% for dish in dish %}
{{ dish | render }}
{% endfor %}
</dl>
</menu>
<dish>
<div>
<dt>{{ attribute.name }}</dt>
<dd>{{ value }}</dd>
</div>
</dish>
</components>
<body>
{{ menu | render }}
</body>
```
## Samples
* `samples/cv/cv.template.html`: Template to generate a CV, see `samples/cv.kdl` for the input data.