create-modulo
Version:
Starter projects for Modulo.html - Ready for all uses - Markdown-SSG / SSR / API-backed SPA
230 lines (186 loc) • 7.03 kB
HTML
<script src=../static/Modulo.html></script><script type=md>---
title: ContentList
---
# ContentList
> **Markdown?** Markdown is a useful format: It's easily edited by GUI editors,
> and popular in many different contexts for content management. It can also
> store meta data, such as date or product information like price or ISBN.
Use a _ContentList_ definition to mix in a list of files for a sidebar or data
collection. It's super powerful when combined with Markdown files, allowing for
meta information and content. It supports use as both a site-map or list of
links, a list type for managing CMS content, or as an easy way to collect many
files of _StaticData_. When used as a site-map, it can provide a management
command that builds all pages at once, for a complete SSG-style build.
##### Example 1: Simple list of pages
The most common usage is a single, global _ContentList_ used as a "site map",
that has links to all your pages in it. This can also be the list used for
building -- just adding a `build=build_all` will register a new command.
See below for an example:
```modulo
edit: demo=modulo_embed
<ContentList build=build_all>
start/getting-started.html, Getting Started
start/development.html, Development
core/artifact.html, Artifact
core/component.html, Component
</ContentList>
<Component name=App>
<Template>
<ol><h3>Site Map</h3>
{% for row in global.definitions.contentlist.data %}
<li><a href="{{ row|get:0 }}">{{ row|get:1 }}</a></li>
{% endfor %}
</ol>
</Template>
</Component>
```
Note that by default _ContentList_ is in `CSV` format (hence the comma
separated data), but that can be changed with `-data-type=JSON` etc.
> **Paths?** - ContentList expects paths to be relative to the root path (e.g.
> project root). The root path is expected to be relative to the `static/`
> directory, wherever that is set.
> **Manually setting static** - If ContentList can't find your files, try
> setting `modulo.rootPath = "../"` (or something equivalent), to indicate the
> path from the currently viewed file to the root of your project.
##### Example 2: Loading Content
_ContentList_ is also intended to _collect_ the files it has listed. That is,
it will loop through and load all those files as content files, processing them
with the given content type (e.g. `-load="json"`, `-load="md"`). Once collected,
it will expose them in a `.files` array, making it wasy to generate article
lists and other content-management tasks. See below:
```modulo
edit: demo=modulo_embed
<ContentList -load="md">
core/configuration.html
core/include.html
core/library.html
</ContentList>
<Component name=App>
<Template>
{% for file in global.definitions.contentlist.files %}
<article>
<p><strong>TITLE:</strong> {{ file.title }}
<p><strong>CONTENT:</strong> {{ file.body|truncate:80 }}
<p><a href="{{ file.Source }}">{{ file.Source }}</a>
</article>
{% endfor %}
</Template>
<Style>
article {
padding: 2%;
margin: 2%;
background: #aaaaee55;
border:5px inset #338;
font-size: 90%;
}
</Style>
</Component>
```
##### Example 3: Maintaining a separate index list
Consider the case of including 30 survey data JSON files:
```modulo
<ContentList -load=json>
./survey-data/001.json
./survey-data/002.json
...
./survey-data/030.json
</ContentList>
```
Clearly maintaining a long list like this is difficult. Thus, it's best to
split it into a separate file. For example, the above can be rewritten into
a separate file as such:
```modulo
<ContentList -load=json -src="./survey_file_list.csv"></ContentList>
```
Then, using tools external to Modulo, we can maintain this
`survey_file_list.csv` file to make sure it has all the names of the files we
want to load. For example, using a shell such as `bash` or `zsh`, we can write:
```
find ./survey-data/ -name '*.json' > ./survey_file_list.csv
```
By re-running this "find" command, the CSV file will be updated. By combining
the above with the `entr` command, this can be done automatically whenever
changes are detected. However, that is beyond the scope of this document.
##### Example 4: Article Markdown Powered CMS
```modulo
edit: demo=modulo_embed
<ContentList -load="md">
static/exampledata/article1.md.htm
static/exampledata/article2.md.htm
static/exampledata/article3.md.htm
</ContentList>
<Component name=App>
<Template>
{% for file in global.definitions.contentlist.files %}
<article>
<h4 style="float:right">{{ file.date }}</h4>
<h3><a href="{{ file.Source }}">{{ file.title }}</a></h3>
<p>{{ file.description }}</p>
<div style="font-size: 80%;">{{ file.body|truncate:200|syntax:"md"|safe }}</div>
</article>
{% endfor %}
</Template>
<Style>
article {
padding: 2%;
margin: 2%;
background: #aaaaee55;
border:5px inset #338;
}
h3 { font-size: 1.1rem; }
</Style>
</Component>
```
##### Example 5: "E-Commerce" Markdown Powered CMS
It's also useful to use this for CMS files, for example for a E-Commerce store.
See below for many simple Markdown files get loaded and formatted. Note that
their extension are ommitted; however, they are Markdown-HTML files.
```modulo
edit: demo=modulo_embed
<ContentList -load=md -name=product_list>
static/exampledata/wood-chair
static/exampledata/plush-chair
</ContentList>
<Component mode=vanish name=App>
<Template>
{% for product in global.definitions.product_list.files %}
<article>
<h4>{{ product.title }}</h4>
{{ product.body|syntax:"md"|safe }}
<a href="#purchase.html?product_id={{ product.product_id }}">
<strong>${{ product.cost }}</strong> BUY
</a>
</article>
{% endfor %}
</Template>
<Style>
* { margin: 0; padding: 0 }
article {
background: pink;
border: 8px outset pink;
padding: 3px;
font-size: 0.9rem;
color: #115;
display: block;
}
a {
background: salmon;
border: 8px outset salmon;
display: inline-block;
color: white;
text-decoration: none;
margin-bottom: 10px;
}
</Style>
</Component>
```
<!--
Example: Custom 404.html router:
for (const [ path, replacement ] of modulo.definitions.routes.data) {
const re = path.replace(/:([a-z]+)/, '.+?') // check for "/path/:var/"
if (re.test(modulo.filePath)) { // Match, internally rewrite
modulo.filePath = modulo.filePath.replace(re, replacement)
break;
}
}
-->