Skip to content
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

Feature/1 doc #2

Merged
merged 2 commits into from
May 31, 2024
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
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