form-jekyll 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +83 -0
  3. data/_includes/elements/helptext.html +3 -0
  4. data/_includes/elements/label.html +1 -0
  5. data/_includes/fields/address.html +41 -0
  6. data/_includes/fields/checkbox.html +27 -0
  7. data/_includes/fields/email.html +12 -0
  8. data/_includes/fields/file.html +14 -0
  9. data/_includes/fields/group.html +3 -0
  10. data/_includes/fields/header.html +3 -0
  11. data/_includes/fields/link.html +6 -0
  12. data/_includes/fields/number.html +20 -0
  13. data/_includes/fields/paragraph.html +1 -0
  14. data/_includes/fields/phone.html +14 -0
  15. data/_includes/fields/price.html +16 -0
  16. data/_includes/fields/radio.html +34 -0
  17. data/_includes/fields/select.html +15 -0
  18. data/_includes/fields/text.html +18 -0
  19. data/_includes/fields/textarea.html +12 -0
  20. data/_includes/pagination.html +14 -0
  21. data/_includes/render_field.html +55 -0
  22. data/_includes/render_form.html +34 -0
  23. data/_includes/sfgov/alpha-banner.html +7 -0
  24. data/_includes/sfgov/footer.html +49 -0
  25. data/_includes/sfgov/header.html +47 -0
  26. data/_layouts/default.html +59 -0
  27. data/_sass/sfgov.scss +471 -0
  28. data/_sass/variables.scss +462 -0
  29. data/assets/css/main.scss +886 -0
  30. data/assets/css/style.scss +146 -0
  31. data/assets/favicon.ico +0 -0
  32. data/assets/images/globe-blue.svg +1 -0
  33. data/assets/images/logo-white.svg +100 -0
  34. data/assets/images/logo.svg +1 -0
  35. data/assets/images/settings-toggle.svg +3 -0
  36. data/assets/images/sfgov.svg +8 -0
  37. data/assets/js/jquery.js +2 -0
  38. data/assets/js/script.js +187 -0
  39. data/assets/js/validator.js +9 -0
  40. metadata +129 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c9949aec210ca48d310c1d9b61680302a77780315361fe4a2344f83925f4548d
4
+ data.tar.gz: '08ef7fa015ad34b53f29b1dc75a45ef07bd28c95142dbeb9128f7dd7de915654'
5
+ SHA512:
6
+ metadata.gz: 9e4cdf7453cff305635708a0d02614b728a3a777c0fb4464e3f58d327aa729645af94fd555cf6c3df9a0b80056e5706c766bffc18475451413426d578388ff7f
7
+ data.tar.gz: 7dc2246b0331309f16821eda509311019467929d6e2f181482c588e6fa1dfa367d7bfacb88d00facc156ecb41b0fc8cf6d201e34dfb660de2bca04a7cf511ae9
@@ -0,0 +1,83 @@
1
+ # form-jekyll
2
+
3
+ ### Goals of this tool
4
+
5
+ - Designers can prototype, comment, and iterate on forms as easily as they might a Google Doc.
6
+
7
+ - Designers can easily give external stakeholders a realistic preview of how a form will work.
8
+
9
+ ### What is it?
10
+
11
+ `form-jekyll` is a Jekyll theme that lets you easily build a prototype of an SF.GOV form in a YAML file. Right now, it lets you add:
12
+
13
+ - Multiple field types
14
+ - Custom error messages
15
+ - Custom input widths, tied to the `maxlength` attribute
16
+ - Conditionals for radio buttons, checkboxes, and text fields
17
+ - "Less than" or "greater than" conditionals for number fields
18
+ - Markdown-formatted content
19
+
20
+
21
+ Since YAML is easy to read, non-technical colleagues can easily give feedback on form design and content inside a GitHub pull request. And because GitHub Pages uses Jekyll, you can easily deploy a form to a webpage and send the link to external stakeholders.
22
+
23
+ ### Example
24
+
25
+ ```
26
+ - title: Page Title
27
+ fields:
28
+ - label: Name
29
+
30
+ - label: Phone number
31
+ type: phone
32
+ error: You need to enter a valid phone number.
33
+
34
+ - label: Do you have an email address?
35
+ type: radio
36
+ options:
37
+ - label: Yes
38
+ shows: email-field
39
+
40
+ - label: No
41
+ hides: email-field
42
+
43
+ - group: email-field
44
+ fields:
45
+ - label: Enter your email address here
46
+ type: email
47
+
48
+ - label: How did you hear about us?
49
+ optional: true
50
+ ```
51
+
52
+ ### Field properties
53
+
54
+ | Property name | Description | Expected format |
55
+ |----------|---------------------------------------------------------------------------------------|-----------------------|
56
+ | `title` | The title of the current page | Plain text |
57
+ | `fields` | The fields within a page or `group`. | A nested list of fields |
58
+ | `label` | The field's label | Plain text |
59
+ | `helptext` | The field's help text | Markdown |
60
+ | `type` | The input type. For a full list of fields, see the file names in `_includes/fields.` | Plain text |
61
+ | `options` | The possible answers for `radio`, `checkbox`, and `select` fields. | A list of options |
62
+ | `checked` | Determines whether a radio or checkbox option should be checked by default. | `true` |
63
+ | `optional` | Determines whether a field is optional | `true` |
64
+ | `other` | Determines whether a set of radio buttons or checkboxes has an "Other" option | `true` |
65
+ | `error` | The custom error message that should display if the field is invalid or blank. | Plain text |
66
+ | `shows` | The name of the `group` that should be conditionally shown if this field is checked. | The name of a `group` |
67
+ | `level` | The header level for `header` fields. For example, `level: 1` will produce an H1. | A number between `1` and `5`|
68
+ | `group` | The name of the group of fields you wish to conditionally show or hide. | Plain text |
69
+ | `size` | The vertical height of a textarea | `small`, `medium` or `large` |
70
+ | `unit` | The desired units of a number field (e.g. "yards", "liters", "days") | Plain text |
71
+ | `url` | The URL of a link. | Plain text |
72
+ | `maxlength` | The maximum character length of a number or text field. | A number between `1` and `15` |
73
+ | `if` | The logic that will trigger a conditional for a free-text field. | <ul><li markdown="1">Plain text or a number (for exact matches)</li><li markdown="1">`<X` to match all numbers less than X (e.g. `<49`)</li><li markdown="1">`>X` to match all numbers greater than X (e.g. `>49`)</li> |
74
+ | `address-fields` | The inputs to show in an address fields. (All inputs are visible by default.) | A nested list containing `street`, `city`, `state` and `zip` |
75
+
76
+
77
+
78
+
79
+ ### Local development
80
+
81
+ - Setup Jekyll - https://jekyllrb.com/docs/installation/
82
+ - Install Gemfile - `bundle install`
83
+ - Run Jekyll - `bundle exec jekyll serve`
@@ -0,0 +1,3 @@
1
+ {% if helptext %}
2
+ <div class="help-text" data-valtype='help'>{{ helptext | markdownify | improve }}</div>
3
+ {% endif %}
@@ -0,0 +1 @@
1
+ {{ label | markdownify | remove: '<p>' | remove: '</p>' | improve}}{% if optional %} <span class="optional">(optional)</span>{% endif %}
@@ -0,0 +1,41 @@
1
+ {% assign address-error = "You need to fill in a complete address." %}
2
+
3
+ <fieldset class="field-address">
4
+ <legend>{% include elements/label.html %}</legend>
5
+
6
+ {% if address-fields contains 'street' or address-fields == 'full' %}
7
+ <label for="{{ name}}-line1">Address Line 1</label>
8
+ <input type="text" id="{{ name}}-line1" {% unless optional %}required="required" data-error="{{ address-error }}"{% endunless %}>
9
+
10
+ <label for="{{ name}}-line2">Address Line 2 {% unless optional %}<span class="optional">(optional)</span>{% endunless %}</label>
11
+ <input type="text" id="{{ name }}-line2">
12
+ {% endif %}
13
+
14
+
15
+ {% if address-fields contains 'city' or address-fields == 'full' %}
16
+ <label for="{{ name}}-city">City</label>
17
+ <input type="text" id="{{ name}}-city" {% unless optional %}required="required" data-error="{{ address-error }}"{% endunless %}>
18
+ {% endif %}
19
+
20
+ {% if address-fields contains 'state' or address-fields == 'full' %}
21
+ <div class="field-address-state">
22
+ <label for="{{ name}}-state">State</label>
23
+ <select id="{{ name}}-state" {% unless optional %}required="required" data-error="{{ address-error }}"{% endunless %}>
24
+ <option value="">Choose a state</option>
25
+ {% for state in site.data.states %}
26
+ <option value="{{ state.value }}">{{ state.text }}</option>
27
+ {% endfor %}
28
+ </select>
29
+ </div>
30
+ {% endif %}
31
+
32
+ {% if address-fields contains 'zip' or address-fields == 'full' %}
33
+ <div class="field-address-zip">
34
+ <label for="{{ name}}-zip" {% unless optional %}required="required" data-error="{{ address-error }}"{% endunless %}>ZIP Code</label>
35
+ <input type="text" id="{{ name}}-zip" maxlength="5" class="length-5">
36
+ </div>
37
+ {% endif %}
38
+
39
+ {% include elements/helptext.html %}
40
+
41
+ </fieldset>
@@ -0,0 +1,27 @@
1
+ <fieldset>
2
+ {% if options %}
3
+ <legend class=" control-label valtype" for="{{ name }}" data-valtype="label">{% include elements/label.html %}</legend>
4
+ {% endif %}
5
+
6
+ <div class="field-container valtype" data-valtype="checkboxes">
7
+ {% if options %}
8
+ {% for option in options %}
9
+ <label class="checkbox">
10
+ <input type="checkbox" value="{{ option.label }}" name="{{ name }}"
11
+ {% if option.checked %}checked="checked"{% endif %}
12
+ {% if option.shows %} data-shows="{{ option.shows }}"{% endif %}
13
+ {% if option.hides %} data-hides="{{ option.hides }}"{% endif %}
14
+ >
15
+ <span>{{ option.label | markdownify | remove: '<p>' | remove: '</p>' | improve}}</span>
16
+ </label>
17
+ {% endfor %}
18
+ {% else %}
19
+ <label class="checkbox">
20
+ <input type="checkbox" value="{{ label }}" name="{{ name }}" {% if checked %}checked="checked"{% endif %}>
21
+ <span>{{ label | markdownify | remove: '<p>' | remove: '</p>' | improve}}</span>
22
+ </label>
23
+ {% endif %}
24
+
25
+ {% include elements/helptext.html %}
26
+ </div>
27
+ </fieldset>
@@ -0,0 +1,12 @@
1
+ <label class="control-label valtype" for="{{ name}}" data-valtype="label">{% include elements/label.html %}</label>
2
+ <div class="field-container">
3
+ <input type="email" id="{{ name }}" placeholder="" class="form-control input-md valtype" data-valtype="placeholder"
4
+ {% unless optional %} required="required"{% endunless %}
5
+ {% if error %}
6
+ data-error="{{ error }}"
7
+ {% else %}
8
+ data-error="You need to enter a valid email address."
9
+ {% endif %}
10
+ >
11
+ {% include elements/helptext.html %}
12
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="field-container">
2
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
3
+ <span class="label">
4
+ {% include elements/label.html %}
5
+ </span>
6
+ <input class="input-file" id="{{ name }}" type="file"
7
+ {% unless optional %} required="required"{% endunless %}
8
+ {% if error %} data-error="{{ error }}"
9
+ {% else %} data-error="You need to upload a file."{% endif %}>
10
+ <span class="file-custom" data-filename=""></span>
11
+ </label>
12
+
13
+ {% include elements/helptext.html %}
14
+ </div>
@@ -0,0 +1,3 @@
1
+ <div data-group="{{ group }}">
2
+ {% include render_field.html %}
3
+ </div>
@@ -0,0 +1,3 @@
1
+ <h{{ level | default: "2"}}>
2
+ {{ label | markdownify | remove: '<p>' | remove: '</p>' }}
3
+ </h{{ level | default: "2"}}>
@@ -0,0 +1,6 @@
1
+ <div class="field-link">
2
+ {% if description %}
3
+ <p>{{ description }}</p>
4
+ {% endif %}
5
+ <a href="{{ url }}" target="_blank">{{ label | improve}}</a>
6
+ </div>
@@ -0,0 +1,20 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+ <div class="field-container">
5
+ <input type="text"
6
+ id="{{ name }}"
7
+ placeholder=""
8
+ class="form-control input-md valtype
9
+ length-{{maxlength | default: '5' }}"
10
+ data-valtype="placeholder"
11
+ {% unless optional %} required="required"{% endunless %}
12
+ {% if "if" %} data-if="{{ if }}"{% endif %}
13
+ {% if shows %} data-shows="{{ shows }}"{% endif %}
14
+ {% if error %} data-error="{{ error }}"{% endif %}
15
+ {% if maxlength %} maxlength="{{maxlength | default: '5'}}"{% endif %}
16
+ >
17
+ <span class="units">{{ unit }}</span>
18
+
19
+ {% include elements/helptext.html %}
20
+ </div>
@@ -0,0 +1 @@
1
+ {{ label | markdownify | improve }}
@@ -0,0 +1,14 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+ <div class="field-container">
5
+ <input type="text" name="{{ name }}" placeholder="" class="form-control input-md valtype length-13" data-valtype="placeholder"
6
+ {% unless optional %} required="required"{% endunless %}
7
+ {% if error %}
8
+ data-error="{{ error }}"
9
+ {% else %}
10
+ data-error="You need to enter a valid phone number."
11
+ {% endif %}>
12
+
13
+ {% include elements/helptext.html %}
14
+ </div>
@@ -0,0 +1,16 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+
5
+ <div class="field-container">
6
+ <div class="prepended dollar">$</div>
7
+ <input type="text" name="{{ name }}" placeholder="" class="form-control input-md valtype" data-valtype="placeholder"
8
+ {% unless optional %} required="required"{% endunless %}
9
+ {% if error %}
10
+ data-error="{{ error }}"
11
+ {% else %}
12
+ data-error="You need to enter a valid price."
13
+ {% endif %}>
14
+
15
+ {% include elements/helptext.html %}
16
+ </div>
@@ -0,0 +1,34 @@
1
+ <fieldset>
2
+ <legend class=" control-label valtype" for="{{ name }}" data-valtype="label">
3
+ {% include elements/label.html %}
4
+ </legend>
5
+ <div class="field-container valtype" data-valtype="radios">
6
+ {% for option in options %}
7
+ <label class="radio">
8
+ <input type="radio" value="{{ option.label }}" name="{{ name }}"
9
+ {% if option.checked %} checked="checked"{% endif %}
10
+ {% if option.shows %} data-shows="{{ option.shows }}"{% endif %}
11
+ {% if option.hides %} data-hides="{{ option.hides }}"{% endif %}
12
+ {% unless optional %} required="required"{% endunless %}
13
+ {% if error %}
14
+ data-error="{{ error }}"
15
+ {% else %}
16
+ data-error="You must select an option."
17
+ {% endif %}>
18
+ <span>{{ option.label | markdownify | remove: '<p>' | remove: '</p>' | improve }}</span>
19
+ </label>
20
+ {% endfor %}
21
+ {% if other %}
22
+ <label class="other-label radio">
23
+ <input type="radio" value="Other" name="{{ name }}">
24
+ <span>Other</span>
25
+ </label>
26
+ <div class="other-input">
27
+ <label for="{{ name }}-other">Write more information here</label>
28
+ <input type="text">
29
+ </div>
30
+ {% endif %}
31
+
32
+ {% include elements/helptext.html %}
33
+ </div>
34
+ </fieldset>
@@ -0,0 +1,15 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+ <div class="field-container">
5
+ <select class="form-control input-md valtype" data-valtype="option" name="{{ name }}"
6
+ {% unless optional %} required="required"{% endunless %}
7
+ {% if error %} data-error="{{ error }}" {% endif %}>
8
+ {{ options }}
9
+ {% for option in options %}
10
+ <option value="{{ option.label }}">{{ option.label }}</option>
11
+ {% endfor %}
12
+ </select>
13
+
14
+ {% include elements/helptext.html %}
15
+ </div>
@@ -0,0 +1,18 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+ <div class="field-container">
5
+ <input type="text"
6
+ id="{{ name }}"
7
+ placeholder=""
8
+ class="form-control input-md valtype
9
+ {% if maxlength %} length-{{ maxlength }}{% endif %}"
10
+ data-valtype="placeholder"
11
+ {% unless optional %} required="required"{% endunless %}
12
+ {% if "if" %} data-if="{{ if }}"{% endif %}
13
+ {% if shows %} data-shows="{{ shows }}"{% endif %}
14
+ {% if error %} data-error="{{ error }}"{% endif %}
15
+ {% if maxlength %} maxlength="{{ maxlength }}"{% endif %}
16
+ >
17
+ {% include elements/helptext.html %}
18
+ </div>
@@ -0,0 +1,12 @@
1
+ <label class="control-label valtype" for="{{ name }}" data-valtype="label">
2
+ {% include elements/label.html %}
3
+ </label>
4
+ <div class="field-container">
5
+ <div class="textarea">
6
+ <textarea class="form-control valtype textarea-{{ size | default: 'small' }}" data-valtype="textarea" name="{{ name }}"
7
+ {% unless optional %} required="required"{% endunless %}
8
+ {% if error %} data-error="{{ error }}"{% endif %} /> </textarea>
9
+
10
+ {% include elements/helptext.html %}
11
+ </div>
12
+ </div>
@@ -0,0 +1,14 @@
1
+ {% if forloop.length > 1 %}
2
+ <div class="form-group pagination">
3
+ {% if forloop.first %}
4
+ <a href="javascript:void(0);" class="btn btn-lg form-section-next">Start</a>
5
+ {% else %}
6
+ <a href="javascript:void(0);" class="btn btn-lg form-section-prev">Previous</a>
7
+ {% if forloop.last %}
8
+ <a href="javascript:void(0);" id="submit" class="btn btn-lg submit">Submit</a>
9
+ {% else %}
10
+ <a href="javascript:void(0);" class="btn btn-lg form-section-next">Next</a>
11
+ {% endif %}
12
+ {% endif %}
13
+ </div>
14
+ {% endif %}
@@ -0,0 +1,55 @@
1
+ {% for field in fields %}
2
+ {% comment %}
3
+ Assign variables
4
+ {% endcomment %}
5
+
6
+ {% if field.address-fields %}
7
+ {% assign address-fields = field.address-fields %}
8
+ {% else %}
9
+ {% assign address-fields = 'full' %}
10
+ {% endif %}
11
+
12
+ {% assign description = field.description %}
13
+ {% assign error = field.error %}
14
+ {% assign fields = field.fields %}
15
+ {% assign group = field.group %}
16
+ {% assign helptext = field.helptext %}
17
+ {% assign if = field.if %}
18
+ {% assign label = field.label %}
19
+ {% assign level = field.level %}
20
+ {% assign maxlength = field.maxlength %}
21
+ {% capture name %}{{ label | slugify }}-field-{{ forloop.index }}{% endcapture %}
22
+ {% assign optional = field.optional %}
23
+ {% assign options = field.options %}
24
+ {% assign other = field.other %}
25
+ {% assign shows = field.shows %}
26
+ {% assign size = field.size %}
27
+ {% assign unit = field.unit %}
28
+ {% assign url = field.url %}
29
+
30
+ {% comment %}
31
+ Render each field
32
+ {% endcomment %}
33
+
34
+ {% capture includepath %}fields/{{field.type}}.html{% endcapture %}
35
+
36
+ {% if field.group %}
37
+ {% include fields/group.html %}
38
+ {% elsif field.type == 'header' %}
39
+ {% include {{ includepath }} %}
40
+ {% elsif field.type == 'paragraph' %}
41
+ {% include {{ includepath }} %}
42
+ {% elsif field.type == 'link' %}
43
+ {% include {{ includepath }} %}
44
+ {% else %}
45
+ <div class="form-group field-{{ field.type }}">
46
+ {% if field.type %}
47
+ {% include {{ includepath }} %}
48
+ {% else %}
49
+ {% include fields/text.html %}
50
+ {% endif %}
51
+ <p class="help-block with-errors"></p>
52
+ </div>
53
+ {% endif %}
54
+
55
+ {% endfor %}
@@ -0,0 +1,34 @@
1
+ {% capture currentform %}{{ include.form }}{% endcapture %}
2
+
3
+ {% for page in site.data[currentform] %}
4
+
5
+ {% assign fields = page.fields %}
6
+ {% assign label = page.title %}
7
+
8
+ <div class="form-section"{% if page.group %} data-group="{{ page.group }}"{% endif %}>
9
+
10
+ {% comment %} Page headers {% endcomment %}
11
+ <header class="hero-banner default">
12
+ <h1>
13
+ {{ label | markdownify | remove: '<p>' | remove: '</p>' }}
14
+ </h1>
15
+ {% if page.description %}
16
+ {{ page.description | markdownify | improve }}
17
+ {% endif %}
18
+ </header>
19
+
20
+ <div class="form-content">
21
+ <div class="form-content-inner">
22
+
23
+ <div class="nav-on-top">
24
+ {% include pagination.html %}
25
+ </div>
26
+ {% comment %} Render fields in the page {% endcomment %}
27
+ {% include render_field.html %}
28
+
29
+ {% include pagination.html %}
30
+ </div>
31
+ </div>
32
+
33
+ </div>
34
+ {% endfor %}