Flask-Materialize

An extension that includes Materialize CSS (http://materializecss.com/) in your project, without any boilerplate code.


Keywords
flask, materialize, materializecss, material, design, css, html, layout, bootstrap, responsive, widgets, wtforms, templates
License
MIT
Install
pip install Flask-Materialize==0.2.4

Documentation

=============== Flask-Materialize

Flask-Materialize packages MaterializeCSS https://github.com/Dogfalo/materialize into an extension that mostly consists of a blueprint named 'material'. It can also create links to serve Materialize from a CDN and works with no boilerplate code in your application.

Materialise has recently moved from 0.100 to version 1.0.0 RC 2, and this extension updates the original extension to this latest version. It also updates the version of jQuery loaded by the extension from 1.11 to 3.3.1

Usage

First, easily install the package with pip install flask-material

A sample helloworld app:
hello_world.py
Yes, I know this is a long helloworld, but, you'll have a great base to start with if you follow along!

from flask import Flask, render_template  
from flask_materialize import Material  
from flask_wtf import Form, RecaptchaField
from flask_wtf.file import FileField
from wtforms import TextField, HiddenField, ValidationError, RadioField,\
    BooleanField, SubmitField, IntegerField, FormField, validators
from wtforms.validators import Required

app = Flask(__name__)  
Material(app)  
app.config['SECRET_KEY'] = 'USE-YOUR-OWN-SECRET-KEY-DAMNIT'
app.config['RECAPTCHA_PUBLIC_KEY'] = 'TEST'

# straight from the wtforms docs:
class TelephoneForm(Form):
    country_code = IntegerField('Country Code', [validators.required()])
    area_code = IntegerField('Area Code/Exchange', [validators.required()])
    number = TextField('Number')

class ExampleForm(Form):
    field1 = TextField('First Field', description='This is field one.')
    field2 = TextField('Second Field', description='This is field two.',
                       validators=[Required()])
    hidden_field = HiddenField('You cannot see this', description='Nope')
    recaptcha = RecaptchaField('A sample recaptcha field')
    radio_field = RadioField('This is a radio field', choices=[
        ('head_radio', 'Head radio'),
        ('radio_76fm', "Radio '76 FM"),
        ('lips_106', 'Lips 106'),
        ('wctr', 'WCTR'),
    ])
    checkbox_field = BooleanField('This is a checkbox',
                                  description='Checkboxes can be tricky.')

    # subforms
    mobile_phone = FormField(TelephoneForm)

    # you can change the label as well
    office_phone = FormField(TelephoneForm, label='Your office phone')

    ff = FileField('Sample upload')

    submit_button = SubmitField('Submit Form')


    def validate_hidden_field(form, field):
        raise ValidationError('Always wrong')

@app.route('/')  
def hello_world():
      form = ExampleForm()   
      return render_template('test.html', form = form)  

if __name__ == '__main__':  
    app.run(debug = True)  

templates/test.html with silly macros

{% extends "material/base.html" %}
{% import "material/utils.html" as util %}
{% import "material/wtf.html" as wtf %}

{% block title %}Hello, world!{% endblock %}

{% block content %}
{{ container() }}
        {{ row() }}
                {{ col(['s12', 'm6']) }}
                	{{ util.card('Hello world!', wtf.quick_form(form) )}}
                {{ enddiv() }}
                {{ col(['s12', 'm6'])}}
                	{{ util.card('Isn\'t Flask great?', '<p>I really do enjoy it!</p>', [['https://bitbucket.org/cyberspy/flask_materialize', 'My Bitbucket']])}}
            	{{ enddiv() }}
        {{ enddiv() }}
{{ enddiv() }}
{% endblock %}

OR templates/test.html without silly macros

{% extends "material/base.html" %}
{% import "material/utils.html" as util %}
{% import "material/wtf.html" as wtf %}

{% block title %}Hello, world!{% endblock %}

{% block content %}
<div class="container">
        <div class="row">
                <div class="col s12 m6">
                	{{ util.card('Hello world!', wtf.quick_form(form) )}}
                </div>
                <div class="col s12 m6">
                	{{ util.card('Isn\'t Flask great?', '<p>I really do enjoy it!</p>', [['https://bitbucket.org/cyberspy/flask_materialize', 'My Bitbucket']])}}
            	</div>
        </div>
</div>
{% endblock %}

This makes some new templates available, containing blank pages that include all Material resources, and have predefined blocks where you can put your content.

Available Blocks

{{block doc}}

Starts: Above <!DOCTYPE html>
Ends: Below </html>

{{block html_attribs}}  

Starts: Inside the <html> tag
Ends: Inside the <html> tag

{{block head}}

Starts: Just after the <head> tag
Ends: Just before the </head> tag

{{block title}}

Starts: Just inside the <title> tag
Ends: Before </title> tag

{{block metas}}

Starts: Inside the <head> block, after </title>. Automatically includes
<meta name="viewport" content="width=device-width, initial-scale=1.0"> Be sure to call super() if you want this meta tag
Ends: Within <head> block, just before {{block styles}}

{{block styles}}

Starts: Inside the head block, after the metas block closes. Includes a link to material.css, Material Icons and Roboto - both as web fonts from Google. Be sure to include {{ super() }} Ends: Just before </head>

{{block body_attribs}}

Starts: Just after <body
Ends: Just before > in the top <body> tag.
<body{% block body_attribs %}{% endblock body_attribs %}>

{{block body}}

Starts: Immediately after <body>
Contains: {{block navbar}}
Contains: {{block content}}
Contains: {{block scripts}} which includes materialize.js and jquery.js, be sure to include {{ super() }}
Contains: {{block footer}}
Ends: Just above </body>

Available Macros

Be sure you are using {% import "material/utils.html" as util %} in your HTML document.

Icon
Simply do: {{ util.icon('ICON-NAME-WITHOUT-MDI', ['SIZE', 'OPTIONAL-CSS-CLASSES']) }}

Button
Macro prototype: {{ util.form_button(content, class = [], type='submit', name='action', icon = False, iconclass=[] }}

**Note**  
Class already includes btn. Everything else must be added.  
<button class="btn {{ class|join(' ') }}" type="{{type}}" name="{{name}}">{{content}}
{% if icon %}<i class="{{ iconclass|join(' ') }} right"></i>{% endif %}</button>

Card
Card prototype: {{ util.card('CARD-TITLE', 'CARD-CONTENT-CAN-USE-HTML-HERE', [['http://google.com/LINK.html', 'Link Title'], ['http://www.google.co.uk/link2.html', 'Link Title2']]) }}
Card does not include any row, or column sizes. You must wrap the card in your desired size.


**These may or may not be useful, feedback requested. **

Container
{{ container() }} Generates <div class="container">

Row
{{ row() }} Generates <div class="row">

Col
{{ col( ['s12', 'm6'] ) }} Generates <div class="col s12 m6">

Enddiv
{{ enddiv() }} Generates </div>

TODO

  • Fix WTF forms integration (quick form)
  • Finish documentation
  • Additional Macros
  • Demo site

Notes

This is largely a fork from the excellent work at https://github.com/mbr/flask-bootstrap and https://github.com/HellerCommaA/flask-materialize