Skip to content

Commit

Permalink
Feature/1 doc (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-yin authored May 31, 2024
1 parent f31473a commit 5ad9af3
Show file tree
Hide file tree
Showing 18 changed files with 225 additions and 552 deletions.
18 changes: 0 additions & 18 deletions docs/source/context.md

This file was deleted.

61 changes: 0 additions & 61 deletions docs/source/getting_started.md

This file was deleted.

Binary file removed docs/source/images/preview-index.png
Binary file not shown.
Binary file added docs/source/images/preview-v1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/preview-v2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/source/images/small-modal-preview.png
Binary file not shown.
10 changes: 2 additions & 8 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
django-lookbook
=====================

A simple way to create reusable components in Django, inspired by Rails' ViewComponent.
Empower your Django development with this pluggable app for creating a robust component library. Includes preview system, documentation engine, and parameter editor for building modular UI effortlessly.

Topics
------
Expand All @@ -10,10 +10,4 @@ Topics
:maxdepth: 2

install.md
overview.md
getting_started.md
slot.md
templates.md
context.md
preview.md
testing.md
write_preview.md
203 changes: 169 additions & 34 deletions docs/source/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,189 @@
$ pip install django-lookbook
```

`django-viewcomponent` will also be installed as a dependency.

Then add the app into `INSTALLED_APPS` in settings.py

```python
INSTALLED_APPS = [
...,
'django_lookbook',
"django_viewcomponent",
"django_lookbook",
]
```

Modify `TEMPLATES` section of settings.py as follows:
Add code below in settings.py

```python
VIEW_COMPONENTS = {
# we will put previews in this directory later
"preview_base": ["previews"],
}

# to make iframe work
X_FRAME_OPTIONS = "SAMEORIGIN"
```

1. Remove `'APP_DIRS': True,`
2. add `loaders` to `OPTIONS` list and set it to following value:
Update urls.py

```python
TEMPLATES = [
{
...,
'OPTIONS': {
'context_processors': [
...
],
'loaders':[(
'django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'django_lookbook.loaders.ComponentLoader',
]
)],
},
},
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path("previews/", include("django_viewcomponent.urls")), # new
path("lookbook/", include("django_lookbook.urls")), # new
]
```

(**Optional**) To avoid loading the app in each template using ``` {% load viewcomponent_tags %} ```, you can add the tag as a 'builtin' in settings.py
Next, let's create *previews/hello_preview.py*

```python
TEMPLATES = [
{
...,
'OPTIONS': {
'context_processors': [
...
],
'builtins': [
'django_lookbook.templatetags.viewcomponent_tags', # new
]
},
},
]
from django.template import Context, Template
from django_viewcomponent.preview import ViewComponentPreview


class HelloComponentPreview(ViewComponentPreview):
def hello_world(self, **kwargs):
"""
This is a simple test for you to check how doc of the preview works
"""
template = Template(
"""<div>Hello World</div>""",
)
return template.render(Context({}))

def hello_world_with_name(self, name=None, **kwargs):
"""
This preview is to display hello world for a specific name
"""
name = name if name else "Michael Yin"
template = Template(
"""<div>Hello {{ name }}</div>""",
)
return template.render(Context({'name': name}))
```

Notes:

1. We create `HelloWorldComponentPreview` which inherits from `ViewComponentPreview`, the class name `HelloComponentPreview` can be seen as a `group` which can contains multiple previews.
2. We define two methods `hello_world` and `hello_world_with_name` which will be used to render the preview

```bash
├── previews
│   └── hello_preview.py
```

```bash
# create db tables and launch Django server
(venv)$ python manage.py migrate
(venv)$ python manage.py runserver
```

Now please check on [http://127.0.0.1:8000/lookbook](http://127.0.0.1:8000/lookbook):

1. The preview has been automatically detected and can be seen in the left sidebar
2. You can see the UI of the preview on the right side and final HTML source code can also be seen
3. The docstring of the preview has been extracted and display in the `Notes` tab, `Markdown` syntax is supported

![](./images/preview-v1.png)

Each time we visit a preview, the method would be called and the final result would be displayed in the top iframe.

## Override Template

In some cases, you might need to render HTML code which need work with CSS and JS. You can override the `preview` template to include them.

Create *django_viewcomponent/preview.html* in the project `templates` directory

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>

<div>
{{ preview_html }}
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous"></script>
</body>
</html>
```

1. We import Bootstrap CSS and JS to the page.
2. `preview_html` is the HTML generated by the preview method.

Now if we refresh the page and check again, the `preview` HTML should be rendered with Bootstrap CSS and JS.

If you have other frontend assets such as Alpine.js, jQuery or CSS file, **you should remember to include them in this template file**.

### Params Editor

Next, let's make our preview work with dynamic parameters.

Update *previews/hello_preview.py*

```python
from django import forms
from django.template import Context, Template
from django_viewcomponent.preview import ViewComponentPreview
from django_lookbook.utils import register_form_class # new


class HelloForm(forms.Form): # new
"""
This is to show how to add parameter editor to preview
"""
name = forms.CharField(
label="Name",
max_length=100,
help_text="Enter name text",
initial="",
)


class HelloComponentPreview(ViewComponentPreview):
def hello_world(self, **kwargs):
"""
This is a simple test for you to check how doc of the preview works
"""
template = Template(
"""<div>Hello World</div>""",
)
return template.render(Context({}))

@register_form_class(HelloForm) # new
def hello_world_with_name(self, name=None, **kwargs):
"""
This preview is to display hello world for a specific name
"""
name = name if name else "Michael Yin"
template = Template(
"""<div>Hello {{ name }}</div>""",
)
return template.render(Context({'name': name}))
```

Notes:

1. We defined a `HelloForm`, which is a regular Django form, nothing special.
2. Use `@register_form_class(HelloForm)` to attach the form class to the method `hello_world_with_name`

If we check the `hello_world_with_name` preview's `Params` tab, we can see the form.

And then, let's input `Elon Musk` in the `name` field, we can see the top iframe is also updated in real-time.

![](./images/preview-v2.png)

In this case, the `name` field value is passed to the `hello_world_with_name` method, then it can generate HTML according to the value.
51 changes: 0 additions & 51 deletions docs/source/overview.md

This file was deleted.

Loading

0 comments on commit 5ad9af3

Please sign in to comment.