Skip to content

Documentation overhaul #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ jobs:
- pip install poetry
- poetry install
script:
- cp README.md docs/README.md
- poetry run mkdocs build
deploy:
- provider: pages
Expand Down
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ npm run build
npm run start
```

### Documentation

The project’s documentation website is built with [MkDocs](https://www.mkdocs.org/).

```sh
# One-off build.
poetry run mkdocs build
# Rebuild the docs as you work on them
poetry run mkdocs serve
```

## Running the tests

To run the python tests, use the script in the root of the repo:
Expand Down
156 changes: 29 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,150 +1,52 @@
# Django pattern library
# [django-pattern-library](https://torchbox.github.io/django-pattern-library/)

[![PyPI](https://img.shields.io/pypi/v/django-pattern-library.svg)](https://pypi.org/project/django-pattern-library/) [![PyPI downloads](https://img.shields.io/pypi/dm/django-pattern-library.svg)](https://pypi.org/project/django-pattern-library/) [![Travis](https://travis-ci.com/torchbox/django-pattern-library.svg?branch=master)](https://travis-ci.com/torchbox/django-pattern-library) [![Total alerts](https://img.shields.io/lgtm/alerts/g/torchbox/django-pattern-library.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/torchbox/django-pattern-library/alerts/)

A module for Django that helps you to build pattern libraries.
> UI pattern libraries for Django templates

![Screenshot of the pattern library UI, with navigation, pattern rendering, and configuration](https://github.com/raw/torchbox/django-pattern-library/master/.github/pattern-library-screenshot.webp)

## Documentation

Documentation is located on GitHub in [`docs/`](https://github.com/torchbox/django-pattern-library/tree/master/docs).

## Objective

At the moment, the main focus is to allow developers and designers
use exactly the same Django templates in a design pattern library
and in production code.

There are a lot of alternative solutions for building
pattern libraries already. Have a look at [Pattern Lab](http://patternlab.io/) and
[Astrum](http://astrum.nodividestudio.com/), for example.
But at [Torchbox](https://torchbox.com/) we mainly use Python and Django and
we find it hard to maintain layout on big projects in several places:
in a project's pattern library and in actual production code. This is our
attempt to solve this issue and reduce the amount of copy-pasted code.

To learn more about how this package can be used, have a look at our Wagtail Space 2020 talk: [Reusable UI components: A journey from React to Wagtail](https://www.youtube.com/watch?v=isrOufI7TKc)

[![Reusable UI components: A journey from React to Wagtail](https://github.com/raw/torchbox/django-pattern-library/master/.github/pattern-library-talk-youtube.webp)](https://www.youtube.com/watch?v=isrOufI7TKc)

## Concepts
To understand how `django-pattern-library` works, the following concepts are important.

### Patterns
Any template that is displayed by the pattern library is referred to as a pattern. Patterns are divided into two categories: fragments and pages.

### Fragments
A fragment is a pattern whose markup does not include all of the resources (typically CSS and Javascript) for it to be displayed correctly on its own. This is typical for reusable component templates which depend on global stylesheets or Javascript bundles to render and behave correctly.

To enable them to be correctly displayed in the pattern library, `django-pattern-library` will inject the rendered markup of fragments into the **pattern base template** specified by `PATTERN_LIBRARY['PATTERN_BASE_TEMPLATE_NAME']`.

This template should include references to any required static files. The rendered markup of fragments will be available in the `pattern_library_rendered_pattern` context variable (see the tests for [an example](https://github.com/torchbox/django-pattern-library/blob/master/tests/templates/patterns/base.html)).

### Pages
In contrast to fragments, pages are patterns that include everything they need to be displayed correctly in their markup. Pages are defined by `PATTERN_LIBRARY['BASE_TEMPLATE_NAMES']`.

Any template in that list — or that extends a template in that list — is considered a page and will be displayed as-is when rendered in the pattern library.

It is common practice for page templates to extend the pattern base template to avoid duplicate references to stylesheets and Javascript bundles. Again, [an example](https://github.com/torchbox/django-pattern-library/blob/master/tests/templates/patterns/base_page.html) of this can be seen in the tests.
## Features

## How to install
This package automates the maintenance of UI pattern libraries or styleguides for Django projects, and allows developers to experiment with Django templates without having to create Django views and models.

First install the library:
- Create reusable patterns by creating Django templates files as usual.
- All patterns automatically show up in the pattern library’s interface.
- Define data as YAML files for the templates to render with the relevant Django context.
- Override Django templates tags as needed to mock the template’s dependencies.
- Document your patterns with Markdown.

```sh
pip install django-pattern-library
# ... or...
poetry add django-pattern-library
```
## Why you need this

Pattern libraries will change your workflow for the better:

Then, in your Django settings, add `pattern_library` into your `INSTALLED_APPS`, and `pattern_library.loader_tags` to `OPTIONS['builtins']` into the `TEMPLATES` setting. For example:
- They help separate concerns, both in code, and between members of a development team.
- If needed, they make it possible for UI development to happen before models and views are created.
- They encourage code reuse – defining independent UI components, that can be reused across apps, or ported to other projects.
- It makes it much simpler to test UI components – no need to figure out where they’re used across a site or app.

```python
INSTALLED_APPS = [
# ...
'pattern_library',
# ...
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'builtins': ['pattern_library.loader_tags'],
},
},
]
```

Note that this module only supports the Django template backend.

### Settings

Next, set the `PATTERN_LIBRARY` setting. Here's an example showing the defaults:

```python
PATTERN_LIBRARY = {
# PATTERN_BASE_TEMPLATE_NAME is the template that fragments will be wrapped with.
# It should include any required CSS and JS and output
# `pattern_library_rendered_pattern` from context.
'PATTERN_BASE_TEMPLATE_NAME': 'patterns/base.html',
# Any template in BASE_TEMPLATE_NAMES or any template that extends a template in
# BASE_TEMPLATE_NAMES is a "page" and will be rendered as-is without being wrapped.
'BASE_TEMPLATE_NAMES': ['patterns/base_page.html'],
'TEMPLATE_SUFFIX': '.html',
# SECTIONS controls the groups of templates that appear in the navigation. The keys
# are the group titles and the values are lists of template name prefixes that will
# be searched to populate the groups.
'SECTIONS': (
('atoms', ['patterns/atoms']),
('molecules', ['patterns/molecules']),
('organisms', ['patterns/organisms']),
('templates', ['patterns/templates']),
('pages', ['patterns/pages']),
),
}

```

Note that the templates in your `PATTERN_LIBRARY` settings must be available to your project's
[template loaders](https://docs.djangoproject.com/en/3.1/ref/templates/api/#loader-types).

### URLs

Include `pattern_library.urls` in your `urlpatterns`. Here's an example `urls.py`:

```python
from django.apps import apps
from django.conf.urls import url, include

urlpatterns = [
# ... Your URLs
]
## Documentation

if apps.is_installed('pattern_library'):
urlpatterns += [
url(r'^pattern-library/', include('pattern_library.urls')),
]
```
Documentation is available at [torchbox.github.io/django-pattern-library/](https://torchbox.github.io/django-pattern-library/), with source files in the `docs` directory.

This package is not intended for production. It is **highly recommended** to only enable this package in testing environments for a restricted, trusted audience. One simple way to do this is to only expose its URLs if `apps.is_installed('pattern_library')`, as demonstrated above, and only have the app installed in environment-specific settings.
- [Getting started](https://torchbox.github.io/django-pattern-library/getting-started/)
- Guides
- [Defining template context](https://torchbox.github.io/django-pattern-library/guides/defining-template-context/)
- [Overriding template tags](https://torchbox.github.io/django-pattern-library/guides/overriding-template-tags/)
- [Customizing template rendering](https://torchbox.github.io/django-pattern-library/guides/customizing-template-rendering/)
- [Workflows that work](https://torchbox.github.io/django-pattern-library/guides/workflows-that-work/)
- Reference
- [API & settings](https://torchbox.github.io/django-pattern-library/reference/api/)
- [Known issues and limitations](https://torchbox.github.io/django-pattern-library/reference/known-issues/)

## Contributing

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).

If you just want to set up the project on your own computer, the contribution guidelines also contain all of the setup commands.
If you want to set up the project on your own computer, the contribution guidelines also contain all of the setup commands.

## Credits

View the full list of [contributors](https://github.com/torchbox/django-pattern-library/graphs/contributors). [BSD](https://github.com/torchbox/django-pattern-library/blob/master/LICENSE) licensed.

Project logo from [FxEmoji](https://github.com/mozilla/fxemoji). Documentation website built with [MkDocs](https://www.mkdocs.org/), and hosted in [GitHub Pages](https://pages.github.com/).
5 changes: 5 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Documentation

This documentation is built as a website with [MkDocs](https://www.mkdocs.org/): [torchbox.github.io/django-pattern-library/](https://torchbox.github.io/django-pattern-library/). The documentation uses non-standard Markdown extensions, and will be best viewed on the website rather than GitHub.

To build locally, view the project’s `CONTRIBUTING.md`.
179 changes: 179 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Getting started

## Installation

django-pattern-library is available [on PyPI](https://pypi.org/project/django-pattern-library/). First install it in your Django project:

```sh
# With pip,
pip install django-pattern-library
# Alternatively, with Poetry,
poetry add --dev django-pattern-library
```

### Compatibility

We support:

- Django 2.2.x, 3.0.x, 3.1.x
- Python 3.6, 3.7, 3.8
- Django Templates only, no Jinja support

## Configuration

### Django settings

In your Django settings file, add `pattern_library` to `INSTALLED_APPS`:

```python
INSTALLED_APPS = [
# ...
"pattern_library",
# ...
]
```

Also add `pattern_library.loader_tags` to `OPTIONS["builtins"]` into the `TEMPLATES` setting:

```python hl_lines="13 14 15"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
"builtins": [
"pattern_library.loader_tags"
],
},
},
]
```

### Pattern library settings

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

```python
PATTERN_LIBRARY = {
# Groups of templates for the pattern library navigation. The keys
# are the group titles and the values are lists of template name prefixes that will
# be searched to populate the groups.
"SECTIONS": (
("components", ["patterns/components"]),
("pages", ["patterns/pages"]),
),

# Configure which files to detect as templates.
"TEMPLATE_SUFFIX": ".html",

# Set which template components should be rendered inside of,
# so they may use page-level component dependencies like CSS.
"PATTERN_BASE_TEMPLATE_NAME": "patterns/base.html",

# Any template in BASE_TEMPLATE_NAMES or any template that extends a template in
# BASE_TEMPLATE_NAMES is a "page" and will be rendered as-is without being wrapped.
"BASE_TEMPLATE_NAMES": ["patterns/base_page.html"],
}
```

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).

### URLs

Include `pattern_library.urls` in your `urlpatterns`. Here is an example `urls.py`:

```python
from django.apps import apps
from django.urls import include, path

urlpatterns = [
# … Your URLs
]

if apps.is_installed("pattern_library"):
urlpatterns += [
path("pattern-library/", include("pattern_library.urls")),
]
```

!!! warning "Security"

This package isn’t intended for production usage, and hasn’t received extensive security scrutiny.

It is **highly recommended** to only enable this package in testing environments, for a restricted, trusted audience. One way to do this is to only expose its URLs if `apps.is_installed("pattern_library")`, as demonstrated above, and only have the app installed in environment-specific settings.

---

Alright, now that we got this far, we can navigate to `http://localhost:8000/pattern-library/` to see our pattern library! But if we tried to do this now, we would likely get a `PatternLibraryEmpty` error – this is expected, as we haven’t added any patterns yet.

![Screenshot of the PatternLibraryEmpty error message from Django](images/getting-started/PatternLibraryEmpty.png)

Now let’s look at adding our first template!

## First pattern

Now we’ve done all of the configuration – let’s create a UI component. We’ll use `quote-block` as an example, and place it at `patterns/components/quote_block/quote_block.html` inside one of our Django apps:

```jinja2
<blockquote class="quote-block block--spacing">
<div class="quote-block__text">
<p class="quote-block__quote">{{ quote }}</p>
{% if attribution %}
<p class="quote-block__attribution">{{ attribution }}</p>
{% endif %}
</div>
</blockquote>
```

### Base template

We additionally need to customize a base template, so the standalone component can be rendered within a page with CSS. This is what the `PATTERN_BASE_TEMPLATE_NAME` setting is for. As a separate template in `patterns/base.html`:

```jinja2 hl_lines="11"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Base</title>
</head>
<body>
{% block content %}
{# pattern_library_rendered_pattern is where the pattern library will inject the rendered pattern. #}
{{ pattern_library_rendered_pattern }}
{% endblock %}
</body>
</html>
```

`quote_block` should now appear in the pattern library UI menu! But the template doesn’t display anything – we additionally need to provide it with test data.

### Component data

We can provide context and tags overrides for our new component by creating a `quote_block.yaml` YAML file alongside the HTML, at `patterns/components/quote_block/quote_block.yaml` in our example.

```yaml
context:
quote: What is love?
attribution: Haddaway
```

We could also provide it with a custom name:

```yaml
name: Quote Block
context:
quote: What is love?
attribution: Haddaway
```

And that’s it! Our `quote_block` should finally appear in the pattern library, along with its rendering with this mock data.

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