Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mario-deluna/tattoo
Tattoo, A simple hyper text programming language.
https://github.com/mario-deluna/tattoo
Last synced: 3 months ago
JSON representation
Tattoo, A simple hyper text programming language.
- Host: GitHub
- URL: https://github.com/mario-deluna/tattoo
- Owner: mario-deluna
- License: mit
- Created: 2015-05-09T18:22:53.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2020-01-27T18:41:33.000Z (almost 5 years ago)
- Last Synced: 2024-10-15T21:17:01.796Z (3 months ago)
- Language: PHP
- Homepage:
- Size: 146 KB
- Stars: 6
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Tattoo Language
===============Tattoo is a simple hyper text programming / template language that renders into HTML.
[![Build Status](https://travis-ci.org/mario-deluna/Tattoo.svg)](https://travis-ci.org/mario-deluna/Tattoo)
[![Packagist](https://img.shields.io/packagist/dt/mario-deluna/tattoo.svg)]()
[![Packagist](https://img.shields.io/packagist/l/mario-deluna/tattoo.svg)]()
[![GitHub release](https://img.shields.io/github/release/mario-deluna/tattoo.svg)]()```tattoo
h1 => 'Welcome to Tattoo :)'
```_There are still PHP5.3 users and I don't want to discriminate these outlaws. Means Tattoo works from 5.3 to 7._
**Tattoo is not finished but in heavy development.**
## Tell me more!
A programming language written in PHP that compiles into PHP? When all you have is a hammer everything starts to look like a nail hu?
There is no real use case where you would build a stand alone Tattoo application. So making Tattoo work as a library seemed to be best way to go. Why PHP? Huge community, pretty fast and Im used to the syntax.
## Installation
Composer, whoop whoop.
```
$ composer require mario-deluna/tattoo
```## Usage
```php
$tattoo = new Tattoo\Tattoo(array('cache' => 'path/to/my/cache/dir/'));echo $tattoo->render('/path/to/a/tattoofile.tto', array(
'name' => $_GET['name'],
));
``````tattoo
h1.page-title => 'Hello ' % @name
```## The great goal
After years of developing web applications I've got kind of sick that the only thing that always stayed a mess was the HTML markup. So there was this idea stuck in my head of a templating engine that actually was a programming language.
Let me show you an example:
```html
```
This something i've seen a lot. We have got two inline statements here and honestly I dont know how to format that piece of code decently. Well this is the same piece of code in tattoo:
```tattoo
[ul #main-navigation .nav]
{
[li][a .navigation-item ~ home] => 'Home'
{
if @currentUrl == '/' {
@this.class.add('navigation-item-active')
@this.parent.class.add('active')
}
}
}
```
Tattoo considers html tags as scoped objects this allows you to write your markup in a real new dynamic way.
---
## Syntax
Let's just drive directly into the syntax.
### Nodes
Tattoo _nodes_ are basically HTML tags. So let's write the alltime classic hello world:
```tattoo
h1 => "Hello World"
```
```html
Hello World
```
You can use the first argument to add classes and set the nodes id.
```tattoo
h1 #page-title .underlined => "Hello World"
```
```html
Hello World
```
All other arguments will be used as node attributes.
```tattoo
a.btn.btn-sm, href: '/login' => 'Sign in'
```
```html
Sign In
```
#### Value less nodes
Sometimes you want to create a node without any contents.
```tattoo
[img src: 'logo.png']
```
```html
```
#### Scoped nodes
Obviously you are going to build a tree structure with tattoo. Node definitions inside `[]` allow a scope.
```tattoo
[div.image-container]
{
[img src: 'wallpaper.jpg']
}
```
```html
```
You are still able to directly assign a text value.
```tattoo
[p] => 'Hello '
{
span => 'World'
}
```
```html
Hello World
```
#### Node tree
Often you have a tree with many levels that just contain one child. Instead of creating a scope for every level you can just forward them.
```tattoo
[header][nav.navbar][ul][li.active][a href: '/'] => 'Home'
{
i.glyphicon ~ home => ''
}
```
```html
```
#### Appending classes
```tattoo
[div.row][div .col ~ md-4 ~ sm-6 ~ xs-12]
{
a .btn ~ lg ~ primary ~ block => 'Click Me'
}
```
```html
```
---
## OLD STUFF KEEP UNTIL I REWROTE EVERYTHING
```tattoo
[form #login-form, action: '/login', method: 'post']
{
p .info => "Please provide your login information."
[input ]
}
```
```tattoo
button.btn title: 'Amazing Tooltip', data: {toggle: 'tooltip', placement: 'left'} => 'Hello!'
```
```html
Hello!
```
### tag with scope
HTML:
```html
Please provide you login information.
```
### modifying scope data
```
[a .ajax-trigger, href: "/notes/save/"]
{
@this.data: {
noteId: 123,
userId: 42,
revision: 1
};
@this.text = "Save your Note"
}
```
HTML:
```html
Save your Note
```
### The are vars
```
@applicationName = "Tattoo Application"
[head] {
title => 'Welcome | ' + @applicationName
}
[body][footer] {
span .small => 'Powerd by ' + @applicationName
}
```
HTML:
```html
Welcome | Tattoo Application
Powerd by Tattoo Application
```
### Loops and tree modifications
```
@pages = {
{ title: 'Home', link: '/home/', isActive: false },
{ title: 'About', link: '/about/', isActive: true },
{ title: 'Terms', link: '/terms/', isActive: false }
}
[ul .navigation]
{
each @page in @pages
{
[li][a .navigation-item, href: @page.link]
{
span.navigation-item-title => @page.title
if @page.isActive
{
@this.parent.class.add('active')
}
}
}
}
```
HTML:
```html
```
### Extending tags
```
// the '*' tells tattoo to not automatically print the tag
extend input*: @input
{
[div .form-group]
{
@input.id = 'input-' + @input.name
label .form-label, for: @input.id => @input.placeholder
@input.class.add( 'form-control' )
if [email protected] {
@this.type = 'text'
}
render @input
}
}
[form action: '/login', method: 'post']
{
[input name: 'username', placeholder: 'your username']
[input name: 'password', placeholder: 'your password', type: 'password']
}
```
HTML:
```html
your username
your password
```
### Views
```
view page-header
{
default @title = 'Unknown'
default @subtitle = ''
default @underline = true
[div .page-title]
{
[h1]
{
print @title + ' '
if @subtitle
{
small .subtitle => @subtitle
}
if @underline
{
[hr .page-title-underline]{}
}
}
}
}
[page-header title: 'Welcome', subtitle: 'to tattoo']
```
HTML:
```html
Welcome to tattoo
```
## Notes
_Notes to myself and everyone who's bored._
A node ( `[div]`, `span => 'foo'` ) always directly represents an element. All given data of such a node object is interpreted as element attribute.
Extending (`extend`) a node allows to a callback like thingy after a the given node has been created also from the context of the node.
Preparing (`prepare`) does the same thing as extend but the callback acts before any custom data is passed.
A view does not stand in any context of a node so all given data / arguments have to be handeled by the view itself.
You should be able to store nodes in variables and modify them before printing. ( see `concept/objectvars.tto`, `concept/bootstrapmodal.tto` )
Only nodes can be printed. When you print a string or a number to parser basically creates a text node.
A view can be loaded using the dobule point `:` initiator.