Custom styles
While Flower includes several built-in styles, you can also create custom styles for your particular use case. A custom style consists of Jinja templates and configuration files that define the structure of the documentation generated from a datapackage.json. When you run the build command, Flower uses these files to generate the documentation in your custom style.
Custom styles only work with build, not view. Since view can be run from anywhere on your computer, there is no reliable way for it to find a custom style. If you would like your style to be available to view, consider contributing it as a built-in style.
In this guide, you will create a custom style that generates one Quarto Markdown file for the metadata describing the Data Package as a whole and separate Markdown files for each data resource. The guide uses a Data Package about a (fake) study on flowers and their growing conditions. To work through the steps yourself, copy the datapackage.json content below into a local directory.
In this guide, the directory is called flora/. Once you’ve completed the guide, your file structure will look like the below with the custom-style/ folder containing the files for your custom style, and the docs/ folder containing the generated documentation files:
flora/
├── datapackage.json
├── .flower.toml
├── custom-style/
│ ├── sections.toml
│ ├── package.qmd.jinja
│ ├── contributors.qmd.jinja
│ └── resource.qmd.jinja
└── docs/
├── index.qmd
└── resources/
├── species_catalog.qmd
└── growth_records.qmdCreating the templates
The first step is to set up the files within the custom-style/ folder. With Flower, you define a custom layout for your metadata (or part of your metadata) using one or more Jinja2 templates. In these templates, you write out the structure of the desired output in your target language (e.g., HTML, markdown, or YAML), using placeholder values for the metadata elements that will come from your datapackage.json.
In this guide, you will create template files containing the Data Package’s general metadata, the contributor metadata, and metadata for each resource contained in the Data Package. The general metadata and contributor metadata templates will be combined into a single index.qmd file, while the resource metadata template will split resources into separate files.
First, create a new directory for the templates in the root of your project. You can store your templates wherever it makes sense for your project, but for this guide, call the folder custom-style/:
flora/
├── datapackage.json
└── custom-style/Inside the template folder, create three files, one for each type of metadata listed above.
package.qmd.jinjafor the general metadata.contributors.qmd.jinjafor the contributor metadata.resource.qmd.jinjafor each resource’s metadata.
The .qmd.jinja extension indicates that the file is a Jinja template that will create a qmd file. If you wanted to create an html file instead, the extension would be .html.jinja.
Next, you will set the layout for the generated documentation in each template. Since Flower uses Jinja2 as its templating engine, you need to use Jinja syntax when accessing values from the Data Package metadata.
package.qmd.jinja
Start with the package.qmd.jinja template that will include metadata about the Data Package as a whole. Since the output will be a Quarto Markdown file, you should use Markdown syntax to structure the content. First, add a YAML header to the template to set the title, subtitle, and date of the generated document, using Jinja syntax to access the relevant metadata properties.
custom-style/package.qmd.jinja
---
title: "{{ package.title or package.name }}"
subtitle: "Version: {{ package.version }}"
date: "{{ package.created }}"
---Jinja syntax uses the double curly brackets {{...}} to output the value of a variable or expression. In the above, {{ package.title or package.name }} sets the title of the generated document to the title property of the package metadata, or to the name property if title is not available. You can use any name for the metadata object passed to the template (e.g., root or data_package instead of package); this variable name will be defined in the sections.toml configuration file described in the sections.toml section below.
Jinja provides built-in filters and functions for processing values, as well as control flow statements such as conditionals and loops. Below, you extend package.qmd.jinja to include the package description and a list of keywords that describe the Data Package:
custom-style/package.qmd.jinja
- 1
-
{{ package.description }}outputs the value of thedescriptionproperty of the package metadata. - 2
-
The
ifstatement checks if thekeywordsproperty exists in the package metadata. If it does, it will output a line with the keywords joined by commas using the built-in Jinjajoinfilter. You can learn more about Jinja features in the Jinja documentation.
contributors.qmd.jinja
In the contributors.qmd.jinja template, you will define the layout for the contributors (using the variable name contributors). You could include the contributors in the package.qmd.jinja template, but, to show how to split content across templates, you will create a separate template. The content of these templates will be combined via the sections.toml configuration file described in the sections.toml section below.
As with the previous template, you will use Jinja syntax to access the relevant metadata properties and to include control flow statements. In this case, you will use a for loop to iterate over the list of contributors and output their metadata. You will also include a conditional to check if the organization and email properties exist for each contributor:
custom-style/contributors.qmd.jinja
## Contributors
{%- if contributors %}
{% for contributor in contributors %}
### {{ contributor.title }}
{%- if contributor.organization %}
**Organization:** {{ contributor.organization }}
{% endif %}
{% if contributor.email -%}
**Email:** <{{ contributor.email }}>
{%- endif %}
{% endfor %}
{% else %}
No contributors listed.
{% endif %}Notice that the template includes a conditional to check if there are any contributors listed in the metadata. If there are no contributors, it will output “No contributors listed.” instead of leaving an empty section.
resource.qmd.jinja
A Data Package can contain multiple data resources and you may want to display each resource’s metadata in a separate file with the same layout. To do this, you can create a template that defines the layout for a single resource and then use the sections.toml configuration file to indicate that this template should be applied to each resource in the Data Package. In the template, the variable name resource is used to refer to the metadata of any single resource that will be rendered with the template:
custom-style/resource.qmd.jinja
---
title: "{{ resource.title or resource.name }}"
---
{{ resource.description }}
## Overview
- **Name:** `{ resource.name }`
{% if resource.path %}
- **Path:** `{ resource.path }`
{% endif %}
{%- if resource.schema and resource.schema.fields %}
- **Number of fields:** {{ resource.schema.fields | length }}
{% else %}
- **Number of fields:** 0
{% endif %}Creating the configuration files
Main configuration file
When you define a custom style, you must set the template and output folder in the main configuration file. Flower can read the main configuration from the .flower.toml or the pyproject.toml file in the root of your Data Package. In this guide, you will use .flower.toml.
Create a .flower.toml file in the root of your Data Package and add the following settings:
.flower.toml
template-dir = "custom-style/"This line points Flower to the folder containing your templates. The output-dir is not set here, so the generated documentation will be written to the default docs/ directory.
If you want to save the generated documentation files to a different folder than docs/, you can set the output-dir in the main configuration file as well.
If you have a pyproject.toml file in the root of your Data Package, you can include the same settings there instead of in a separate .flower.toml file. The only difference is that the settings in pyproject.toml need to be nested under a header like so:
pyproject.toml
[tool.seedcase-flower]
template-dir = "custom-style/"The main configuration also includes a style field. This specifies a built-in style and should not be used when creating a custom style. If you want to use a built-in style, leave template-dir unset and set style to the name of your chosen built-in style.
For examples of built-in styles, see the examples page.
sections.toml configuration file
The sections.toml file defines how many output files will be created and which metadata will be displayed in each file. Flower splits documentation into two section types: one and many.
oneis for one output file (e.g., an index file).manyis for a group of similar output files (a file for each resource or a file for each resource field).
The sections.toml file must be stored in the same folder as the Jinja templates.
Adding [[one]] section(s)
Create a sections.toml file in the custom-style/ folder. Inside, add a [[one]] section for each output file you want to create. For this guide, add just one [[one]] section to save an index.qmd file:
custom-style/sections.toml
[[one]]
output-path = "index.qmd"This will generate an index.qmd file in the output directory (docs/ in this example, since this is the default output directory).
Each [[one]] section contains one or more content items, each linking a specific part of the metadata to a template. Content items in the same section are combined into one output file in the order they are defined.
The section below outputs index.qmd, the “landing page” for the Data Package documentation, with content items for the general package properties (like title and description) and the contributors.
Each content item requires the following fields:
jsonpath: A JSON path pointing to the metadata property or properties to send to the template.template-path: The path to the Jinja template file, relative to the template folder.jinja-variable: The variable name used in the template to reference the metadata selected by thejsonpath.
Update the sections.toml file to include the content items for the [[one]] section:
custom-style/sections.toml
- 1
-
Select the entire metadata object from
datapackage.json. - 2
- Render the selected metadata with this template.
- 3
- Reference the selected metadata with this variable name.
- 4
-
Append this section to the previous section’s output in
docs/index.qmd.
You can add more [[one]] sections if you want to create more output files that contain different metadata. Or you can keep adding content items to the same [[one]] section. Each [[one.contents]] item belongs to the [[one]] section defined above it in the file.
Adding [[many]] section(s)
The [[many]] section type creates a group of similar output files, for example, one file per resource. It works similarly to [[one]], but instead of jsonpath, it uses a content type (either "resources" or "fields"), with the other Content attributes defined directly in the [[many]] section.
The content field in a [[many]] section is restricted to "resources" or "fields" because these are the only Data Package metadata properties structured as lists, making them the only ones that benefit from generating one file per item.
To create one file for each resource in a resources/ folder using the resource.qmd.jinja template, add the following [[many]] section to the sections.toml file:
custom-style/sections.toml
[[many]]
output-path = "resources/"
content = "resources"
template-path = "resource.qmd.jinja"
jinja-variable = "resource"The created files will be placed in the resources/ folder inside the output directory defined in the main configuration (docs/ in this example). Each created file will be named using the resource’s name property (in this case species_catalog.qmd and growth_records.qmd).
You can either set a folder or a file in the output-path of [[many]]. If you use a file path, you need to include the {} placeholder for the file name. In the case above, it would be resources/{resource-name}.qmd.
See more about the [[one]] and [[many]] section Python classes in the design documentation.
Build the custom style documentation
To generate your custom style documentation, run the build command in the terminal from the root of your Data Package:
Terminal
seedcase-flower buildFlower then reads the configuration files (.flower.toml and sections.toml), populates the templates (in the custom-style/ folder) with metadata from datapackage.json, and outputs the generated documentation files to the specified output directory.
Your file structure should now look like:
flora/
├── datapackage.json
├── .flower.toml
├── custom-style/
│ ├── sections.toml
│ ├── package.qmd.jinja
│ ├── contributors.qmd.jinja
│ └── resource.qmd.jinja
└── docs/
├── index.qmd
└── resources/
├── species_catalog.qmd
└── growth_records.qmdYou can now use your custom documentation files in the docs/ folder as you would with any other Quarto Markdown files, such as generating a website or PDF.