diff --git a/bootstrap3/templates/bootstrap3/index.html b/bootstrap3/templates/bootstrap3/index.html index 085f1850..1433775e 100644 --- a/bootstrap3/templates/bootstrap3/index.html +++ b/bootstrap3/templates/bootstrap3/index.html @@ -15,9 +15,11 @@ diff --git a/bootstrap4/templates/bootstrap4/index.html b/bootstrap4/templates/bootstrap4/index.html index 883f0799..d7ebfa37 100644 --- a/bootstrap4/templates/bootstrap4/index.html +++ b/bootstrap4/templates/bootstrap4/index.html @@ -14,8 +14,11 @@ - + diff --git a/bulma/__init__.py b/bulma/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bulma/admin.py b/bulma/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/bulma/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/bulma/forms.py b/bulma/forms.py new file mode 100644 index 00000000..32f85c40 --- /dev/null +++ b/bulma/forms.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- +import datetime + +from django import forms +from django.forms import modelform_factory +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout, Div, HTML, Field +from crispy_forms.bootstrap import AppendedText, PrependedText, PrependedAppendedText +from django.utils import timezone + +from crispy_bulma.bulma import InlineCheckboxes, InlineRadios +from crispy_bulma.layout import Button, Column, IconField, FormGroup, Row, Submit +from crispy_bulma.widgets import FileUploadInput + +from bulma.models import WithFileField + + +class MessageForm(forms.Form): + text_input = forms.CharField( + help_text="help on a text_input", + ) + text_input_a = forms.CharField() + text_input_b = forms.CharField() + text_input_c = forms.CharField() + + integer_input = forms.IntegerField() + decimal_input = forms.DecimalField() + url_input = forms.URLField() + time_input = forms.TimeField() + date_input = forms.DateField() + datetime_input = forms.DateTimeField() + password_input = forms.CharField(widget=forms.PasswordInput, label="Password") + + textarea = forms.CharField( + widget=forms.Textarea(), + help_text="help on a textarea", + ) + + radio_buttons = forms.ChoiceField( + choices=( + ('option_one', + "Option one is this and that be sure to include why it's great"), + ('option_two', + "Option two can is something else and selecting it will deselect option one") + ), + widget=forms.RadioSelect, + initial='option_two', + help_text="help on a radio_buttons", + ) + + inline_radio_buttons = forms.ChoiceField( + choices=( + ('option_one', 'option_one'), + ('option_two', 'option_two') + ), + widget=forms.RadioSelect, + initial='option_two', + help_text="help on a inline_radio_buttons", + ) + + checkboxes = forms.MultipleChoiceField( + choices=( + ('option_one', + "Option one is this and that be sure to include why it's great"), + ('option_two', + 'Option two can also be checked and included in form results'), + ('option_three', + 'Option three can yes, you guessed it also be checked and included in form results') + ), + initial='option_one', + widget=forms.CheckboxSelectMultiple, + help_text="Note: Labels surround all the options for much larger click areas and a more usable form.", + ) + + inline_checkboxes = forms.MultipleChoiceField( + choices=( + ('bird', + "it's a bird"), + ('plane', + "it's a plane"), + ('dunno', + "it's something else !") + ), + initial='option_one', + widget=forms.CheckboxSelectMultiple, + help_text="help on a inline_checkboxes", + ) + + grouped_checkboxes = forms.MultipleChoiceField( + choices=( + ('Group 1', + ((1, "Option one"), + (2, "Option two"), + (3, "Option three"))), + ('Group 2', + ((4, "Option four"), + (5, "Option five"), + (6, "Option six"))), + ), + initial=(1,), + widget=forms.CheckboxSelectMultiple, + help_text="help on a grouped_checkboxes", + ) + + icon_field = forms.CharField( + help_text="Here's more help text this time on an icon field" + ) + + appended_text = forms.CharField( + help_text="Here's more help text" + ) + + appended_text2 = forms.CharField( + help_text="And a bigger appended text field" + ) + + appended_select = forms.ChoiceField( + label="Select field with appended text", + choices=[(1, "Choice 1"), (2, "Choice 2")], + help_text="Some help text" + ) + + prepended_appended_select = forms.ChoiceField( + label="Select field with both preprended and appended text", + choices=[(1, "Choice 1"), (2, "Choice 2")], + help_text="Some help text" + ) + + prepended_select = forms.ChoiceField( + label="Select field with prepended text", + choices=[(1, "Choice 1"), (2, "Choice 2")], + help_text="Some help text" + ) + + prepended_text = forms.CharField() + + prepended_text_two = forms.CharField() + + select = forms.ChoiceField( + choices=(('1', 'North'), ('2', 'South'), ('3', 'East'), ('4', 'West')), + help_text='Direction to go' + ) + + multicolon_select = forms.MultipleChoiceField( + choices=(('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5')), + help_text=( + 'This strange option climbing out of the box is in the examples too ' + 'Only without Flexbox ' + 'https://v4-alpha.getbootstrap.com/components/forms/#form-controls'), + ) + + split_datetime_field = forms.SplitDateTimeField( + initial=timezone.now() + ) + boolean_field = forms.BooleanField() + + file_field = forms.FileField( + label="file_field", + widget=FileUploadInput(), + help_text='with widgets.FileInput()' + ) + + file_field_raw = forms.FileField( + label="file_field_raw", + help_text='with default widget', + ) + + # Bulma + helper = FormHelper() + helper.layout = Layout( + Field('text_input', css_class='form-control-lg'), + Field('textarea', rows="3", css_class='is-primary is-large'), + 'radio_buttons', + InlineRadios('inline_radio_buttons'), + Field('checkboxes', style="background: #FAFAFA"), + InlineCheckboxes('inline_checkboxes'), + IconField("icon_field", icon_prepend="fa fa-user"), + 'select', + Field('multicolon_select', size="5"), + 'boolean_field', + Field('file_field', css_class='is-primary is-large'), + 'file_field_raw', + # TODO + # 'grouped_checkboxes', + Row( + Column('text_input_a','text_input_b'), + Column('text_input_c'), + ), + "integer_input", + "decimal_input", + "url_input", + "time_input", + "date_input", + + # TODO + #'split_datetime_field', + FormGroup( + Submit('save_changes', 'Save changes', css_class="is-primary is-large"), + Button('Cancel'), + ), + "datetime_input", + "password_input", + + FormGroup( + Submit('save_changes', 'Save changes', css_class="is-primary"), + Button('Cancel'), + ), + + ) + + +class HorizontalMessageForm(forms.Form): + text_input = forms.CharField() + text_input_a = forms.CharField() + text_input_b = forms.CharField() + text_input_c = forms.CharField() + + textarea = forms.CharField( + widget=forms.Textarea(), + ) + + radio_buttons = forms.ChoiceField( + choices=( + ('option_one', + "Option one is this and that be sure to include why it's great"), + ('option_two', + "Option two can is something else and selecting it will deselect option one") + ), + widget=forms.RadioSelect, + initial='option_two', + help_text="help on a radio_buttons", + ) + + inline_radio_buttons = forms.ChoiceField( + choices=( + ('option_one', 'option_one'), + ('option_two', 'option_two') + ), + widget=forms.RadioSelect, + initial='option_two', + help_text="help on a inline_radio_buttons", + ) + + checkboxes = forms.MultipleChoiceField( + choices=( + ('option_one', + "Option one is this and that be sure to include why it's great"), + ('option_two', + 'Option two can also be checked and included in form results'), + ('option_three', + 'Option three can yes, you guessed it also be checked and included in form results') + ), + initial='option_one', + widget=forms.CheckboxSelectMultiple, + help_text="Note: Labels surround all the options for much larger click areas and a more usable form.", + ) + + inline_checkboxes = forms.MultipleChoiceField( + choices=( + ('bird', + "it's a bird"), + ('plane', + "it's a plane"), + ('dunno', + "it's something else !") + ), + initial='option_one', + widget=forms.CheckboxSelectMultiple, + help_text="help on a inline_checkboxes", + ) + + appended_text = forms.CharField( + help_text="Here's more help text" + ) + + appended_text2 = forms.CharField( + help_text="And a bigger appended text field" + ) + + prepended_text = forms.CharField() + + prepended_text_two = forms.CharField() + + select = forms.ChoiceField( + choices=(('1', 'North'), ('2', 'South'), ('3', 'East'), ('4', 'West')), + help_text='Direction to go' + ) + + multicolon_select = forms.MultipleChoiceField( + choices=(('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5')), + help_text=( + 'This strange option climbing out of the box is in the examples too ' + 'Only without Flexbox ' + 'https://v4-alpha.getbootstrap.com/components/forms/#form-controls'), + ) + + boolean_field = forms.BooleanField() + file_field = forms.FileField( + widget=FileUploadInput(), + help_text='with FileInput widget', + required=True, + ) + + file_field_raw = forms.FileField( + help_text='with default widget', + required=True, + ) + + # Bulma + helper = FormHelper() + helper.layout = Layout( + Field('text_input', css_class='form-control-lg'), + Field('textarea', rows="3", css_class='form-control-lg'), + Field('radio_buttons'), + InlineRadios('inline_radio_buttons'), + Field('checkboxes', style="background: #FAFAFA"), + InlineCheckboxes('inline_checkboxes'), + Field('select'), + Field('multicolon_select'), + Field('boolean_field'), + Field('file_field'), + Field('file_field_raw'), + FormGroup( + Submit('save_changes', 'Save changes', css_class="is-primary"), + Button('Cancel'), + ), + ) + helper.form_horizontal = True + + + + +class WithFileForm(forms.ModelForm): + class Meta: + fields = ['my_file', 'my_char'] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['my_file'].widget = FileUploadInput() + + +FormWithFileField = modelform_factory(WithFileField, form=WithFileForm) +class HorizontalModelForm(forms.ModelForm): + class Meta: + model = WithFileField + fields = '__all__' + helper = FormHelper() + helper.form_horizontal = True diff --git a/bulma/migrations/__init__.py b/bulma/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bulma/models.py b/bulma/models.py new file mode 100644 index 00000000..a435b0d3 --- /dev/null +++ b/bulma/models.py @@ -0,0 +1,6 @@ +from django.db import models + +# Create your models here. +class WithFileField(models.Model): + my_file = models.FileField(null=True, blank=True, help_text="help") + my_char = models.CharField(null=True, blank=True, help_text="help", max_length=32) diff --git a/bulma/templates/bulma/base.html b/bulma/templates/bulma/base.html new file mode 100644 index 00000000..e119d023 --- /dev/null +++ b/bulma/templates/bulma/base.html @@ -0,0 +1,16 @@ + + + + Bulma | Crispy Forms Test Project + + + + + + +
+ {% block content %} + {% endblock %} +
+ + diff --git a/bulma/templates/bulma/index.html b/bulma/templates/bulma/index.html new file mode 100644 index 00000000..3cc92220 --- /dev/null +++ b/bulma/templates/bulma/index.html @@ -0,0 +1,69 @@ +{% extends 'bulma/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} + + +
+
+

Bulma

+
+ {% csrf_token %} +
+
+

Default form

+ {% crispy default_form %} +
+
+
+
+

Default form with failing validation #

+ {% crispy default_form_failing %} +
+
+
+
+

Model form #

+ {% crispy model_form %} +
+
+
+
+

Horizontal Model form #

+ {% crispy horizontal_model_form %} +
+
+
+
+

Horizontal form #

+ {% crispy horizontal_form %} +
+
+
+
+

Horizontal form with failing validation #

+ {% crispy horizontal_form_failing %} +
+
+
+
+
+{% endblock %} diff --git a/bulma/tests.py b/bulma/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/bulma/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/bulma/views.py b/bulma/views.py new file mode 100644 index 00000000..efcfee8f --- /dev/null +++ b/bulma/views.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +import os + +import errno +from django.conf import settings +from django.shortcuts import render + +from bulma.models import WithFileField +from bulma.forms import FormWithFileField, HorizontalMessageForm, HorizontalModelForm, MessageForm + + +def index(request): + settings.CRISPY_TEMPLATE_PACK = 'bulma' + + filename = '.' + ("/somedire" * 10) + try: + os.makedirs(filename) + except FileExistsError as e: + assert e.errno is errno.EEXIST + filename += "/" + ("myfile-" * 10) + ".txt" + with open(filename, "w") as f: + f.write('Hello world') + instance = WithFileField(my_file=filename) + + # This view is missing all form handling logic for simplicity of the example + return render(request, 'bulma/index.html', + { + 'model_form': FormWithFileField( + instance=instance, + prefix='model_form', + ), + 'horizontal_model_form': HorizontalModelForm( + instance=instance, + prefix='horizontal_model_form', + ), + 'default_form': MessageForm( + data=request.POST if request.method == "POST" else None, + prefix='default_form', + ), + 'horizontal_form': HorizontalMessageForm( + data=request.POST if request.method == "POST" else None, + prefix='horizontal_form', + ), + 'default_form_failing': MessageForm( + data={}, + prefix='default_form_failing', + ), + 'horizontal_form_failing': HorizontalMessageForm( + data={}, + prefix='horizontal_form_failing', + ), + }) diff --git a/django_rendering/templates/django_rendering/index.html b/django_rendering/templates/django_rendering/index.html index 75b7cdcb..b3267cea 100644 --- a/django_rendering/templates/django_rendering/index.html +++ b/django_rendering/templates/django_rendering/index.html @@ -12,10 +12,13 @@ Bootstrap 3 - + diff --git a/requirements.txt b/requirements.txt index 378c9da6..7a47cf97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ django-crispy-forms>=1.9.0 # Use pip install -e ../django-crispy-forms for Django>=3.0.7 gunicorn>=20.0.4 pytz>=2019.3 +crispy-bulma>=0.8.0 diff --git a/semantic/templates/semantic/index.html b/semantic/templates/semantic/index.html index 7f516d9a..2277c027 100644 --- a/semantic/templates/semantic/index.html +++ b/semantic/templates/semantic/index.html @@ -5,8 +5,10 @@
diff --git a/test_project/settings.py b/test_project/settings.py index bca6eb8f..5ef47eb1 100644 --- a/test_project/settings.py +++ b/test_project/settings.py @@ -43,10 +43,12 @@ # dependencies 'crispy_forms', 'crispy_forms_semantic_ui', + 'crispy_bulma', # internal apps 'bootstrap3', 'bootstrap4', 'semantic', + 'bulma', 'django_rendering', ) @@ -78,7 +80,7 @@ }, ] -CRISPY_ALLOWED_TEMPLATE_PACKS = ('bootstrap', 'uni_form', 'bootstrap3', 'bootstrap4', 'semantic-ui',) +CRISPY_ALLOWED_TEMPLATE_PACKS = ('bootstrap', 'uni_form', 'bootstrap3', 'bootstrap4', 'bulma', 'semantic-ui',) WSGI_APPLICATION = 'test_project.wsgi.application' diff --git a/test_project/urls.py b/test_project/urls.py index 2081a646..347519dc 100644 --- a/test_project/urls.py +++ b/test_project/urls.py @@ -17,6 +17,7 @@ from bootstrap3.views import index as bootstrap_3_preview from bootstrap4.views import index as bootstrap_4_preview +from bulma.views import index as bulma_preview from semantic.views import index as semantic_preview from django_rendering.views import index as django_rendering_preview @@ -25,5 +26,6 @@ path('django', django_rendering_preview, name='django_rendering.views.index'), path('bootstrap3', bootstrap_3_preview, name='bootstrap3.views.index'), path('bootstrap4', bootstrap_4_preview, name='bootstrap4.views.index'), + path('bulma', bulma_preview, name='bulma.views.index'), path('semantic', semantic_preview, name='semantic.views.index'), ]