Skip to content

Commit 3253838

Browse files
committed
Add more documentation of patterns known to work
1 parent cbdd3f4 commit 3253838

17 files changed

+539
-126
lines changed

README.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ This package automates the maintenance of UI pattern libraries or styleguides fo
1616
- Override Django templates tags as needed to mock the template’s dependencies.
1717
- Document your patterns with Markdown.
1818

19+
## Why you need this
20+
21+
Pattern libraries will change your workflow for the better:
22+
23+
- They help separate concerns, both in code, and between members of a development team.
24+
- If needed, they make it possible for UI development to happen before models and views are created.
25+
- They encourage code reuse – defining independent UI components, that can be reused across apps, or ported to other projects.
26+
- It makes it much simpler to test UI components – no need to figure out where they’re used across a site or app.
27+
1928
## Documentation
2029

2130
Documentation is available at [torchbox.github.io/django-pattern-library/](https://torchbox.github.io/django-pattern-library/), with source files in the `docs` directory.
@@ -24,10 +33,6 @@ Documentation is available at [torchbox.github.io/django-pattern-library/](https
2433
- Guides
2534
- Reference
2635

27-
## Examples of usage
28-
29-
At [Torchbox](https://torchbox.com/), we use this package for all of the Wagtail websites we build, for example [rca.ac.uk](https://github.com/torchbox/rca-wagtail-2019).
30-
3136
## Contributing
3237

3338
See anything you like in here? Anything missing? We welcome all support, whether on bug reports, feature requests, code, design, reviews, tests, documentation, and more. Please have a look at our [contribution guidelines](https://github.com/torchbox/django-pattern-library/blob/master/CONTRIBUTING.md).

docs/getting-started.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ TEMPLATES = [
5858

5959
### Pattern library settings
6060

61-
Still in Django settings, set the `PATTERN_LIBRARY` setting. Here is an example showing the defaults:
61+
Still in Django settings, set the [`PATTERN_LIBRARY`](./reference/api.md#pattern_library) setting. Here is an example showing the defaults:
6262

6363
```python
6464
PATTERN_LIBRARY = {
@@ -83,7 +83,7 @@ PATTERN_LIBRARY = {
8383
}
8484
```
8585

86-
Note the templates in your `PATTERN_LIBRARY` settings must be available to [template loaders](https://docs.djangoproject.com/en/3.1/ref/templates/api/#loader-types).
86+
Note the templates in your [`PATTERN_LIBRARY`](./reference/api.md#pattern_library) settings must be available to [template loaders](https://docs.djangoproject.com/en/3.1/ref/templates/api/#loader-types).
8787

8888
### URLs
8989

@@ -165,6 +165,15 @@ context:
165165
attribution: Haddaway
166166
```
167167
168+
We could also provide it with a custom name:
169+
170+
```yaml
171+
name: Quote Block
172+
context:
173+
quote: What is love?
174+
attribution: Haddaway
175+
```
176+
168177
And that’s it! Our `quote_block` should finally appear in the pattern library, along with its rendering with this mock data.
169178

170179
![Screenshot of the quote_block template](images/getting-started/getting-started-complete.png)

docs/guides/customizing-template-rendering.md

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Customizing template rendering
22

3-
## Customizing the patterns’ surroundings
3+
## Customizing all patterns’ surroundings
44

55
All patterns that are not pages are rendered within a base page template. The pattern library will render patterns inside the `content` block, which you can tweak to change how patterns are displayed.
66

@@ -21,3 +21,28 @@ You can for example add a theme wrapper around the components:
2121
```jinja2
2222
<body class="{% block body_class %}{% endblock %}{% if pattern_library_rendered_pattern %} pattern-library-template{% endif %}">
2323
```
24+
25+
## Customizing a single pattern’s rendering
26+
27+
There is no API to customize a single pattern’s rendering, but it can be done by using pattern-library-only templates. For example, with our `quote_block.html` component:
28+
29+
```django
30+
<blockquote class="quote-block block--spacing">
31+
<div class="quote-block__text">
32+
<p class="quote-block__quote">{{ quote }}</p>
33+
{% if attribution %}
34+
<p class="quote-block__attribution">{{ attribution }}</p>
35+
{% endif %}
36+
</div>
37+
</blockquote>
38+
```
39+
40+
We could create another template next to it called `quote_block_example.html`,
41+
42+
```django
43+
<div class="pattern-library bg bg--light">
44+
{% include "patterns/components/quote_block/quote_block.html" with attribution=attribution quote=quote %}
45+
</div>
46+
```
47+
48+
This is a fair amount of boilerplate, but neatly solves the problem per pattern.

docs/guides/overriding-template-tags.md

+10-12
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,25 @@
22

33
The package overrides the following Django tags:
44

5-
* `{% extends %}`
6-
* `{% include %}`
5+
- `{% extends %}`
6+
- `{% include %}`
77

8-
It's required to allow us to define fake template context
9-
and override other template tags in `yaml` files.
10-
This package uses custom behaviour for these tags only when
11-
rendering pattern library and falls back to Django's standard behaviour
12-
on all other cases.
8+
It's required to allow us to define fake template context and override other template tags in YAML files.
9+
This package uses custom behaviour for these tags only when rendering pattern library and falls back to Django's standard behaviour on all other cases.
1310

1411
The override process has two parts:
1512

16-
1. Override your template tag with a mock implementation
17-
2. Define fake result for your tag in a `yaml` file
13+
1. Override your template tag with a mock implementation
14+
2. Define fake result for your tag in a YAML file
1815

1916
### When do I need to override a template tag?
2017

2118
Ideally your pattern library should be independent, so it doesn't fail when
2219
you run it with a project that has no entries in DB or on a local machine
23-
without internet connection. This means that you need to override
24-
a template tag when it hits DB or any other resource
25-
(cache, or requests URL, for example).
20+
without internet connection.
21+
This means that you need to override a template tag when it hits DB or any other resource (cache, or requests URL, for example).
22+
23+
You amy also need to override template tags in other cases, when data provided by the pattern library’s context mocking is of a different type to what Django would expect – this is because the pattern library only uses data types that are de-serializable from YAML.
2624

2725
### Override modes
2826

docs/guides/reuse-across-projects.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Reuse across projects
2+
3+
django-pattern-library is designed to be useful for component reuse within a single project, but it can also be set up to create a component library reusable between multiple projects. Reusing pattern library components is a matter of packaging and publishing a Django app (that happens to contain a lot of templates, CSS, and JS).
4+
5+
Here are the rough steps:
6+
7+
- **Decide where to store the shared pattern library**. Whether it has its own repository, whether it’s published on PyPI, or in another way.
8+
- **Choose a versioning and release methodology**. With multiple projects reusing the code, it’s important for them to be able to pin specific versions, and have a clear sense of how to do updates.
9+
- **Provide a pattern library development environment**. Developers will need a way to iterate on pattern library components in isolation from the projects the UI components are reused in.
10+
11+
## Static files
12+
13+
As part of your pattern library’s build process, make sure that the static files (CSS, JS, etc.) of each component can be reused individually of each-other. Different projects likely will reuse different components, and you don’t want to be paying the performance cost of loading components you don’t need.
14+
15+
## Useful resources
16+
17+
- Django’s official [How to write reusable apps](https://docs.djangoproject.com/en/3.1/intro/reusable-apps/)
18+
- InVision’s [Guide to Design Systems](https://www.invisionapp.com/inside-design/guide-to-design-systems/)

docs/guides/workflows-that-work.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Workflows that work
2+
3+
The workflow of developing UI components in a pattern library can be quite different from one-off templates that are only rendered where they are used. Here are tips to make the most of it.
4+
5+
## Keep the pattern library in sync
6+
7+
One of the upsides of having the pattern library built with Django is that the HTML templates can never go out of sync – but the data can! Make sure your template context and tag overrides keep in sync with your actual templates. This can for example be part of a code review checklist.
8+
9+
## Document your patterns
10+
11+
Patterns support defining a custom `name` in YAML, as well as rendering fully-fledged documentation in Markdown. Create a file next to the template to document it:
12+
13+
```markdown
14+
This template can be used in different places. In streamfield block
15+
or directly in a page template. To use this template pass `call_to_action` into context.
16+
17+
Example:
18+
19+
{% include "patterns/molecules/cta/call_to_action.html" with call_to_action=call_to_action %}
20+
```
21+
22+
## Back-end first
23+
24+
Traditionally, Django development starts from models and everything else is derived from it. This is very natural from a back-end perspective – first define your data model, then the view(s) that reuse it, and finally templates.
25+
26+
We generally recommend this approach, but keep in mind that:
27+
28+
- With this workflow it’s natural to write templates that are heavily tied to the database structure, and as such not very reusable, and may be out of touch with visual design (which generally uses basic data structures like lists and mappings)
29+
- There will be work to do to reconcile the data structure as defined by the back-end, with what is mandated by the designs.
30+
31+
To mitigate this effort, and overall make templates more reusable, take the time to massage data into simple structures that map better to visual representations.
32+
33+
## Front-end first
34+
35+
Alternatively, the pattern library makes it possible to write templates without models and views. This can be very convenient if your project’s schedule requires this kind of progression.
36+
37+
With this approach, keep in mind that:
38+
39+
- When creating the template from UI principles, there will be assumptions made about the underlying data structures to be provided by Django. Templates will be heavily tied to their visual design (which generally uses basic data structures like lists and mappings), and may be out of touch with the models once they are created.
40+
- There will be work to do to reconcile the data structure as defined in the UI components, with what is mandated by the models.
41+
42+
To mitigate this effort, and overall make templates more reusable, take the time to massage data into simple structures that map better to visual representations.

docs/index.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@ Here is a screenshot of the pattern library in action:
1616

1717
[![Screenshot of the pattern library UI, with navigation, pattern rendering, and configuration](images/pattern-library-screenshot.webp)](images/pattern-library-screenshot.webp)
1818

19+
## Why you need this
20+
21+
Pattern libraries will change your workflow for the better:
22+
23+
- They help separate concerns, both in code, and between members of a development team.
24+
- If needed, they make it possible for UI development to happen before models and views are created.
25+
- They encourage code reuse – defining independent UI components, that can be reused across apps, or ported to other projects.
26+
- It makes it much simpler to test UI components – no need to figure out where they’re used across a site or app.
27+
1928
## Why this exists
2029

2130
We want to make it possible for developers to maintain large pattern libraries with minimal fuss – no copy-pasting of templates between a static library and the “production” templates.
2231

23-
There are a lot of alternative solutions for building pattern libraries, or to have [UI development playgrounds](https://www.componentdriven.org/). At [Torchbox](https://torchbox.com/) we mainly use Django and Wagtail, and we found it hard to maintain large libraries with those tools that have no awareness of Django Templates.
24-
This is our attempt to solve this issue, bringing [Pattern Lab](http://patternlab.io/) to the Django world.
32+
There are a lot of alternative solutions for building pattern libraries, or to have [UI development playgrounds](https://www.componentdriven.org/).
33+
At [Torchbox](https://torchbox.com/) we mainly use Django and Wagtail, and we found it hard to maintain large libraries with those tools that have no awareness of Django Templates.
34+
This is our attempt to solve this issue – [Pattern Lab](http://patternlab.io/) goes Django!
2535

2636
To learn more about how this package can be used, have a look at our talk:
2737

docs/recipes/image-include.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Image include
2+
3+
```jinja2
4+
<img src="{{ imageSmall.url }}" data-src="{{ imageLarge.url }}" width="{{ width }}" height="{{ height }}" alt="{{ imageLarge.alt }}" class="{{ classList }} lazyload">
5+
```
6+
7+
YAML:
8+
9+
```yaml
10+
context:
11+
width: '720'
12+
height: '400'
13+
imageSmall:
14+
url: https://source.unsplash.com/pZ-XFIrJMtE/360x200
15+
imageLarge:
16+
url: https://source.unsplash.com/pZ-XFIrJMtE/720x400
17+
```

docs/recipes/image-lazyload.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Image lazy load
2+
3+
```jinja2
4+
{% image slide.image fill-100x71 as imageSmall %}
5+
{% image slide.image fill-829x585 as imageLarge %}
6+
7+
{% include "patterns/atoms/image/image--lazyload.html" with imageSmall=imageSmall width=829 height=585 imageLarge=imageLarge classList='slide__image' %}
8+
```
9+
10+
```yaml
11+
tags:
12+
image:
13+
slide.image fill-100x71 as imageSmall:
14+
target_var: imageSmall
15+
raw:
16+
url: '//placekitten.com/100/71'
17+
slide.image fill-829x585 as imageLarge:
18+
target_var: imageLarge
19+
raw:
20+
url: '//placekitten.com/829/585'
21+
width: '829'
22+
height: '585'
23+
```

docs/recipes/inclusion-tags.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Inclusion tags
2+
3+
```jinja2
4+
<div class="footer__action">
5+
{% footernav %}
6+
</div>
7+
```
8+
9+
```yaml
10+
tags:
11+
footernav:
12+
"":
13+
template_name: "patterns/molecules/navigation/footernav.html"
14+
```

docs/recipes/looping-for-tags.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
## Looping over a template tag
2+
3+
For a template such as:
4+
5+
```jinja2
6+
{% social_media_links as social_links %}
7+
<ul class="footer__social-links">
8+
{% for link in social_links %}
9+
{# Only render if we have a link #}
10+
{% if link.url %}
11+
<li class="social-item social-item--{{link.type}}">
12+
<a class="social-item__link" href="{{link.url}}" aria-label="{{link.label}}">
13+
<svg class="social-item__icon" width="24" height="24" aria-hidden="true" focusable="false">
14+
<use xlink:href="#{{link.type}}"></use>
15+
</svg>
16+
</a>
17+
</li>
18+
{% endif %}
19+
{% endfor %}
20+
</ul>
21+
```
22+
23+
You can use the following syntax to mock the tag’s output:
24+
25+
```yaml
26+
tags:
27+
social_media_links:
28+
as social_links:
29+
raw:
30+
- url: '#'
31+
type: twitter
32+
label: Twitter
33+
- url: '#'
34+
type: facebook
35+
label: Facebook
36+
- url: '#'
37+
type: instagram
38+
label: Instagram
39+
- url: '#'
40+
type: youtube
41+
label: YouTube
42+
- url: '#'
43+
type: linkedin
44+
label: LinkedIn
45+
```

docs/recipes/multiple-variants.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Multiple template variants
2+
3+
See [#87](https://github.com/torchbox/django-pattern-library/issues/87). There is currently no support for trying out a single component with different variations in context or tag overrides, but this can worked around by creating pattern-library-only templates.
4+
5+
For example, for this `call_to_action` template:
6+
7+
```django
8+
<div class="call-to-action">
9+
<img class="call-to-action__image" src="{{ call_to_action.illustration.url }}" alt="">
10+
<p class="call-to-action__heading heading heading--three">{{ call_to_action.title }}</p>
11+
{% include "patterns/atoms/link/link.html" with type="primary" classes="call-to-action__link" href=call_to_action.get_link_url text=call_to_action.get_link_text %}
12+
</div>
13+
```
14+
15+
We can try it out once with the following YAML:
16+
17+
```yaml
18+
context:
19+
call_to_action:
20+
title: Will you help us protect these magnificant creatures in the UK waters?
21+
illustration:
22+
url: /static/images/illustrations/sharks.svg
23+
get_link_text: Sign up for our appeal
24+
get_link_url: '#'
25+
```
26+
27+
If we want to try multiple variants, simply create a custom template for pattern library usage only, that renders `call_to_action` multiple times:
28+
29+
```django
30+
<div class="pl-frame pl-frame--white">
31+
<h2>Call to action</h2>
32+
{% for call_to_action in ctas %}
33+
<div class="pl-row {% if call_to_action.classes %}{{ call_to_action.classes }}{% endif %}">
34+
<p>{{ call_to_action.type }}</p>
35+
{% include "patterns/molecules/cta/call_to_action.html" with call_to_action=call_to_action %}
36+
</div>
37+
{% endfor %}
38+
</div>
39+
```
40+
41+
```yaml
42+
context:
43+
ctas:
44+
- type: Call to action
45+
title: Will you help us protect these magnificant creatures in the UK waters?
46+
illustration:
47+
url: /static/images/illustrations/sharks.svg
48+
get_link_text: Sign up for our appeal
49+
get_link_url: '#'
50+
- type: Call to action with short title
51+
title: Will you help us?
52+
illustration:
53+
url: /static/images/illustrations/sharks.svg
54+
get_link_text: Sign up for our appeal
55+
get_link_url: '#'
56+
- type: Call to action with long title
57+
title: Will you help us protect these magnificant and learn how to make environmentally responsible choices when buying seafood?
58+
illustration:
59+
url: /static/images/illustrations/sharks.svg
60+
get_link_text: Sign up for our appeal
61+
get_link_url: '#'
62+
```

0 commit comments

Comments
 (0)