Syntax
HTML#
Inside gutt-files you can use any HTML.
Variable#
Construction for assign some value to variable.
Name of variable should be started with dollar $
and contain latin symbols,
numbers or dash -
.
<variable name={$variable-name} value={$variable-value} />
<h1>{$variable-name}</h1>
Data structure
This is very tricky question. Because Gutt doesn't work with data in directly way. Gutt
provides syntax and pass parsed tree to platform. And that platform works with assumed data
structures. There are some primitive types: number
, string
,
boolean
. And one a bit complicated. Basicly it is kind of map
(key-value). And stringifier may interpretate this map as it wish. There are three
stringifiers exist at this moment. Two of them written on Javascript (NodeJS and browser)
and one of them written on PHP. In both case this map structure work in next way. If all
keys have type number
then it is simple array
. If even one of keys
has string then we deal with associated array
in PHP and object
in Javascript.
This is the syntax of primitive types:
<variable name={$type-number} value={1} />
<variable name={$type-string} value={'This is a string'} />
<variable name={$type-string} value={"This is a string"} />
<variable name={$type-string} value="This is a string" /><!-- the same effect as previous two cases -->
<variable name={$type-boolean} value={true} />
<variable name={$type-boolean} value={false} />
This is the syntax of map
.
<variable name={$type-map} value={[1, 2, 3, 4, 5]} />
<variable name={$type-map} value={['key0': 'item1', 'key1': 'item2', 'key2': 'item3', 'key3': 'item4', 'key4': 'item5']} />
If key begins with latin symbol and contains only latin symbols and numbers you can use short form access to field with dot:
<variable name={$type-map} value={['key0': 'item1', 'key1': 'item2', 'key2': 'item3', 'key3': 'item4', 'key4': 'item5']} />
<h1>{$type-map.key1}</h1>
Or you can use universal access:
<variable name={$type-map} value={['field with with difficult key': 'field value']} />
<h1>{$type-map['field with with difficult key']}</h1>
Value of map
field may be another map
:
<variable name={$type-map} value={[['name': 'Max'], ['name': 'Payne']]} />
<h1>{$type-map[0].name}, {$type-map[1]['name']}</h1>
There are two range operators. Opened and closed. Both of them create arrays of numbers:
<variable name={$opened-array} value={[0...5]} />
<variable name={$closed-array} value={[0..5]} />
<div>Opened array contains numbers from 0 to 5 without 5 at the end.</div>
<div>closed array contains numbers from 0 to 5 with 5 at the end.</div>
So. If you pass real user id to this template, you will see it in <h3 />
tag. Untill then you see deafult 123
.
If#
<if test={$variable == 3}>
<div>This statement is true</div>
</if>
<if />
doesn't support else
. Because html likely syntax
doesn't assume constructions which can close nesting and open it at the same time.
<if test={$variable == 3}>
<div>This statement is true</div>
<else> <!--doesn't work this way -->
<div>This statement is not true</div>
</if>
If you need else
or elseif
statements, use
<switch />
Attribute#
This construction can help you with adding attributes in according with some variables
You can use it right after tag defining:
<div>
<attribute name="id" value="div-id" />
</div>
Or you can wrap it in <if />
construction:
<div>
<if test={$do-we-need-add-this-attribute}>
<attribute name="id" value="yes-we-do" />
</if>
</div>
Also you can wrap this statement in more complicated constructions you will find at this page
If attribute already exists this statement going to replace it.
Switch#
This is the way to make elseif
and else
statements.
<switch>
<case test={$statement-one}>
<div>Statement 1</div>
</case>
<case test={$statement-two}>
<div>Statement 2</div>
</case>
<default>
<div>Default statement</div>
</default>
</switch>
You define switch
and put case
s inside. If you want
to do something when no one case worked – use default
.
For each#
This is how you may iterate map
s.
<variable name={$type-map} value={['key0': 'item1', 'key1': 'item2', 'key2': 'item3', 'key3': 'item4', 'key4': 'item5']} />
<for-each key={$key} item={$item} from={$type-map}>
<h1>{$key} – {$item}</h1>
</for-each>
Import#
Best part has began. Power of this templater can be found in the imports. First of all use
import
tag:
<import name="included-template" from="./relative/path/to/template.gutt" />
name
— string which can contain latin symbols and at least one dash symbol
-
After template can be used:
<included-template />
Or you can pass some children.
<import name="included-template" from="./relative/path/to/template.gutt" />
<article>
<included-template>
<h1>This children would be passed inside including template</h1>
</included-template>
</article>
Let's look at included template which places by path
./relative/path/to/template.gutt
(remember?):
<div title="wrapper for children">
<slot />
</div>
Result is going to be:
<article>
<div title="wrapper for children">
<h1>This children would be passed inside including template</h1>
</div>
</article>
There is such thing as scope and Gutt support some system of scopes. Main template and included template have different scopes. But only one for each template. It's better illustrate on example. This is main template:
<import name="included-template" from="./relative/path/to/template.gutt" />
<!-- i define variable at this level -->
<variable name={$some-variable} value={1} />
<included-template>
<!-- and it's accessible at this level as well -->
<!-- this construction going to change origin value -->
<variable name={$some-variable} value={$some-variable + 1} />
</included-template>
<!-- value of variable is goint to output. and it is equal 2 -->
{$some-variable}
This is included template. I try to use previous variable:
<div>
<!-- this variable doesn't exists here yet -->
{$some-variable}
</div>
But i can define it inside included template:
<div>
<variable name={$some-variable} value={13} />
</div>
And this definition doesn't change the original value at main template. Because of the different scopes.
Param#
You can pass some data inside template. But sometime you can forgot about it.
<param />
can help you. You can assign some default value to variable if
this variable wasn't passed.
<param name={$user-id} value={123} />
<h1>User id is {$user-id}</h1>
Slot#
<slot />
is a placeholder for passing children. I can be placeholder with fallback if you don‘t pass any children
This is regular use case:
<import name="included-template" from="./relative/path/to/template.gutt" />
<article>
<included-template>
<h1>Children</h1>
</included-template>
</article>
<aside>
<slot />
</aside>
<article>
<aside>
<h1>Children</h1>
</aside>
</article>
Use case with fallback:
<import name="included-template" from="./relative/path/to/template.gutt" />
<article>
<included-template /><!-- no passed children />
</article>
<aside>
<slot>
<h2>Fallback</h2>
</slot>
</aside>
<article>
<aside>
<h2>Fallback</h2>
</aside>
</article>
Self#
For recursive import you can use self
statement.
<param name={$data} value={[]} />
<div>
<for-each item={$item} from={$data}>
<div>
{$item.value}
</div>
<if test={$item.children?}>
<self data={$item.children} />
</if>
</for-each>
</div>
Use-state#
Usually the result of all platform dependent stringifiers is the function accepts state. State is a data you pass to top levet component. If you need a part of the original state in some n-level component you should pass this data n-1 times through all nestings. This is quite inconvenient.
In the world of redux you can pass any data from global state to any component with connect-function.
use-state
is the same idea – you can get any part of the state at component any level.
Let's assume you have state:
["articles": [
[
"title": "This is the first article title",
"description": "This is the first article description"
], [
"title": "This is the second article title",
"description": "This is the second article description"
]
]]
And you have structure of document:
|-entry-component.gutt
|-layout-component.gutt
|-content-page.gutt
|-content-component.gutt
|-article-list.gutt <- here you want to see articles from the state
|-article-item.gutt
So, instead of passing articles
through all components like this:
<!-- entry-component.gutt -->
<import name="layout-component" from="./layout-component.gutt" />
<import name="content-page" from="./content-page.gutt" />
<layout-component>
<content-page articles={$articles} /><!-- one -->
</layout-component>
<!-- content-page.gutt -->
<import name="content-component" from="./content-component.gutt" />
<content-component articles={$articles} /><!-- two -->
<!-- content-component.gutt -->
<import name="article-list" from="./article-list.gutt" />
<article-list articles={$articles} /><!-- three -->
<!-- article-list.gutt -->
<import name="article-item" from="./article-item.gutt" />
<for-each item={$article} from={$articles} />
<article-item article={$article} />
</for-each>
You can get articles from the state directly:
<import name="article-item" from="./article-item.gutt" />
<use-state name={$articles} />
<for-each item={$article} from={$articles} />
<article-item article={$article} /><!-- here is the justified usage of passing data to nested component -->
</for-each>
You also can insure yourself with setting default value:
<use-state name={$articles} value={[]} />
Warning! You can't use variable with keys in the name
-attribute like name={$articles[0]}
.
Classes#
There is a helper for better syntax class names. For example you pass class name
to imported component and put it to class
attribute:
<import name="site-gallery" from="./site-gallery.gutt" />
<h1>This is out gallery</h1>
<site-gallery class="gallery" />
<section class={classes("gallery-container", $class)}>
...
</section>
<h1>This is out gallery</h1>
<section class="gallery-container gallery">
...
</section>