docs: Syntax highlighting for mkdocs (#984)

* feat:forward context processors variables in context in ISOLATED mode

	provide context_processors_data property to Component to access those variables in Component

* refactor: internalize RequestContext and pass HttpRequest internally

* docs: document HttpRequest and context processors

* docs: use djc_py code blocks for component definitions

---------

Co-authored-by: Lilian Durey <dureylilian@gmail.com>
This commit is contained in:
Juro Oravec 2025-02-20 11:47:14 +01:00 committed by GitHub
parent 1f7e28db22
commit 314ec77d3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 142 additions and 76 deletions

View file

@ -105,7 +105,7 @@ For live examples, see the [Community examples](../../overview/community.md#comm
It's also a good idea to have a common prefix for your components, so they can be easily distinguished from users' components. In the example below, we use the prefix `my_` / `My`.
```py
```djc_py
from typing import Dict, NotRequired, Optional, Tuple, TypedDict
from django_components import Component, SlotFunc, register, types

View file

@ -106,7 +106,7 @@ Then navigate to these URLs:
### 1. Define document HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
from django_components import Component, types
# HTML into which a fragment will be loaded using HTMX
@ -141,7 +141,7 @@ class MyPage(Component):
### 2. Define fragment HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
class Frag(Component):
def get(self, request):
return self.render_to_response(
@ -184,7 +184,7 @@ urlpatterns = [
### 1. Define document HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
from django_components import Component, types
# HTML into which a fragment will be loaded using AlpineJS
@ -225,7 +225,7 @@ class MyPage(Component):
### 2. Define fragment HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
class Frag(Component):
def get(self, request):
# IMPORTANT: Don't forget `type="fragment"`
@ -281,7 +281,7 @@ urlpatterns = [
### 1. Define document HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
from django_components import Component, types
# HTML into which a fragment will be loaded using JS
@ -321,7 +321,7 @@ class MyPage(Component):
### 2. Define fragment HTML
```py title="[root]/components/demo.py"
```djc_py title="[root]/components/demo.py"
class Frag(Component):
def get(self, request):
return self.render_to_response(

View file

@ -107,7 +107,7 @@ have all the keys that were passed to the `provide` tag.
## Full example
```py
```djc_py
@register("child")
class ChildComponent(Component):
template = """

View file

@ -27,7 +27,7 @@ the locations by inserting following Django template tags:
So if you have a component with JS and CSS:
```python
```djc_py
from django_components import Component, types
class MyButton(Component):

View file

@ -85,9 +85,9 @@ This has two modes:
Consider this example:
```python
```djc_py
class Outer(Component):
template = \"\"\"
template = """
<div>
{% component "inner" %}
{% fill "content" %}
@ -95,7 +95,7 @@ This has two modes:
{% endfill %}
{% endcomponent %}
</div>
\"\"\"
"""
```
- `"django"` - `my_var` has access to data from `get_context_data()` of both `Inner` and `Outer`.
@ -108,7 +108,7 @@ This has two modes:
Given this template:
```python
```djc_py
@register("root_comp")
class RootComp(Component):
template = """
@ -148,7 +148,7 @@ all the data defined in the outer layers, like the `{% with %}` tag.
Given this template:
```python
```djc_py
class RootComp(Component):
template = """
{% with cheese="feta" %}

View file

@ -19,7 +19,7 @@ Components can now be used as views:
Here's an example of a calendar component defined as a view:
```python
```djc_py
# In a file called [project root]/components/calendar.py
from django_components import Component, ComponentView, register

View file

@ -9,7 +9,7 @@ Components can be rendered outside of Django templates, calling them as regular
The component class defines `render` and `render_to_response` class methods. These methods accept positional args, kwargs, and slots, offering the same flexibility as the `{% component %}` tag:
```py
```djc_py
class SimpleComponent(Component):
template = """
{% load component_tags %}

View file

@ -28,7 +28,7 @@ HTML / JS / CSS with a component:
However, you can freely mix these for different languages:
```py
```djc_py
class MyTable(Component):
template: types.django_html = """
<div class="welcome">

View file

@ -256,7 +256,7 @@ Then:
## Full example for `html_attrs`
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template: t.django_html = """

View file

@ -78,7 +78,7 @@ rendered = template.render(RequestContext(request, {}))
The data from context processors is automatically available within the component's template.
```python
```djc_py
class MyComponent(Component):
template = """
<div>

View file

@ -9,7 +9,7 @@ For example, here's the calendar component from
the [Getting started](../../getting_started/your_first_component.md) tutorial,
defined in a single file:
```python title="[project root]/components/calendar.py"
```djc_py title="[project root]/components/calendar.py"
from django_components import Component, register, types
@register("calendar")

View file

@ -469,7 +469,7 @@ _Added in version 0.76_:
Consider a component with slot(s). This component may do some processing on the inputs, and then use the processed variable in the slot's default template:
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template = """
@ -498,7 +498,7 @@ Using scoped slots consists of two steps:
To pass the data to the `slot` tag, simply pass them as keyword attributes (`key=value`):
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template = """
@ -649,14 +649,14 @@ So it's possible to define a `name` key on a dictionary, and then spread that on
You can dynamically pass all slots to a child component. This is similar to
[passing all slots in Vue](https://vue-land.github.io/faq/forwarding-slots#passing-all-slots):
```py
```djc_py
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
return {
"slots": self.input.slots,
}
template: """
template = """
<div>
{% component "child" %}
{% for slot_name in slots %}

View file

@ -25,7 +25,7 @@ inheritance follows these rules:
For example:
```python
```djc_py
class BaseCard(Component):
template = """
<div class="card">
@ -37,7 +37,7 @@ class BaseCard(Component):
border: 1px solid gray;
}
"""
js = "console.log('Base card loaded');"
js = """console.log('Base card loaded');"""
# This class overrides parent's template, but inherits CSS and JS
class SpecialCard(BaseCard):
@ -94,7 +94,7 @@ All other attributes and methods (including the [`Component.View`](../../referen
For example:
```python
```djc_py
class BaseForm(Component):
template = """
<form>

View file

@ -202,7 +202,7 @@ of HTML attributes (usually called `attrs`) to pass to the underlying template.
In such cases, we may want to define some HTML attributes statically, and other dynamically.
But for that, we need to define this dictionary on Python side:
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template = """
@ -229,7 +229,7 @@ as component kwargs, so we can keep all the relevant information in the template
we prefix the key with the name of the dict and `:`. So key `class` of input `attrs` becomes
`attrs:class`. And our example becomes:
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template = """

View file

@ -50,7 +50,7 @@ class Calendar(Component):
Alternatively, you can "inline" HTML, JS, and CSS right into the component class:
```py
```djc_py
from django_components import Component
class Calendar(Component):

View file

@ -7,7 +7,7 @@ associated with components, and how we render them.
1. First of all, when we consider a component, it has two kind of dependencies - the "inlined" JS and CSS, and additional linked JS and CSS via `Media.js/css`:
```py
```djc_py
from django_components import Component, types
class MyTable(Component):

View file

@ -15,7 +15,7 @@
```
And components that make use of `abc.html` via `include` or `extends`:
```py
```djc_py
from django_components import Component, register
@register("my_comp_extends")
@ -66,7 +66,7 @@
```py
@register("my_comp")
class MyComp(Component):
template_file = "abc.html"
template_file = "abc.html"
```
Then:
@ -110,37 +110,34 @@
uses `extends`. In that case, just as you would expect, the `block inner` inside
`abc.html` will render `OVERRIDEN`:
````py
```djc_py
@register("my_comp")
class MyComp(Component):
template_file = """
{% extends "abc.html" %}
{% block inner %}
OVERRIDEN
{% endblock %}
"""
```
````
template = """
{% extends "abc.html" %}
{% block inner %}
OVERRIDEN
{% endblock %}
"""
```
4. This is where it gets interesting (but still intuitive). You can insert even
new `slots` inside these "overriding" blocks:
```py
```djc_py
@register("my_comp")
class MyComp(Component):
template_file = """
{% extends "abc.html" %}
template = """
{% extends "abc.html" %}
{% load component_tags %}
{% block "inner" %}
OVERRIDEN
{% slot "new_slot" %}
hello
{% endslot %}
{% endblock %}
"""
{% load component_tags %}
{% block "inner" %}
OVERRIDEN
{% slot "new_slot" %}
hello
{% endslot %}
{% endblock %}
"""
```
And you can then pass fill for this `new_slot` when rendering the component:

View file

@ -9,7 +9,7 @@ weight: 1
2. Next, in your component, set typings of `Component.template/css/js` to `types.django_html`, `types.css`, and `types.js` respectively. The extension will recognize these and will activate syntax highlighting.
```python title="[project root]/components/calendar.py"
```djc_py title="[project root]/components/calendar.py"
# In a file called [project root]/components/calendar.py
from django_components import Component, register, types
@ -21,12 +21,19 @@ class Calendar(Component):
}
template: types.django_html = """
<div class="calendar-component">Today's date is <span>{{ date }}</span></div>
<div class="calendar-component">
Today's date is <span>{{ date }}</span>
</div>
"""
css: types.css = """
.calendar-component { width: 200px; background: pink; }
.calendar-component span { font-weight: bold; }
.calendar-component {
width: 200px;
background: pink;
}
.calendar-component span {
font-weight: bold;
}
"""
js: types.js = """
@ -43,7 +50,7 @@ class Calendar(Component):
With PyCharm (or any other editor from Jetbrains), you don't need to use `types.django_html`, `types.css`, `types.js` since Pycharm uses [language injections](https://www.jetbrains.com/help/pycharm/using-language-injections.html).
You only need to write the comments `# language=<lang>` above the variables.
```python
```djc_py
from django_components import Component, register
@register("calendar")
@ -55,13 +62,20 @@ class Calendar(Component):
# language=HTML
template= """
<div class="calendar-component">Today's date is <span>{{ date }}</span></div>
<div class="calendar-component">
Today's date is <span>{{ date }}</span>
</div>
"""
# language=CSS
css = """
.calendar-component { width: 200px; background: pink; }
.calendar-component span { font-weight: bold; }
.calendar-component {
width: 200px;
background: pink;
}
.calendar-component span {
font-weight: bold;
}
"""
# language=JS
@ -73,3 +87,45 @@ class Calendar(Component):
})()
"""
```
## Pygments
[Pygments](https://pygments.org/) is a syntax highlighting library written in Python. It's also what's used by this documentation site ([mkdocs-material](https://squidfunk.github.io/mkdocs-material/)) to highlight code blocks.
To write code blocks with syntax highlighting, you need to install the [`pygments-djc`](https://pypi.org/project/pygments-djc/) package.
```bash
pip install pygments-djc
```
And then initialize it by importing `pygments_djc`:
```python
import pygments_djc
```
Now you can write code blocks with syntax highlighting.
```txt
\```djc_py
from django_components import Component, register
@register("calendar")
class Calendar(Component):
template= """
<div class="calendar-component">
Today's date is <span>{{ date }}</span>
</div>
"""
css = """
.calendar-component {
width: 200px;
background: pink;
}
.calendar-component span {
font-weight: bold;
}
"""
\```
```

View file

@ -88,7 +88,7 @@ Read on to learn about all the exciting details and configuration possibilities!
- Each component can include its own HTML, CSS, and JS, or additional third-party JS and CSS.
- HTML, CSS, and JS can be defined on the component class, or loaded from files.
```python
```djc_py
from django_components import Component
@register("calendar")

View file

@ -14,7 +14,7 @@ the signal is triggered for each component.
Import from django as `django.test.signals.template_rendered`.
```python
```djc_py
from django.test.signals import template_rendered
# Setup a callback function

3
docs/scripts/setup.py Normal file
View file

@ -0,0 +1,3 @@
# Allow us to use `djc_py` / `djc_python` code blocks.
# Importing this package automatically registers the `djc_py` lexer onto Pygments.
import pygments_djc # noqa: F401

View file

@ -12,7 +12,7 @@ the signal is triggered for each component.
Import from django as `django.test.signals.template_rendered`.
```python
```djc_py
from django.test.signals import template_rendered
# Setup a callback function

View file

@ -123,6 +123,7 @@ plugins:
closing_tag: "!}"
- gen-files:
scripts:
- docs/scripts/setup.py
- docs/scripts/reference.py
- literate-nav:
nav_file: SUMMARY.md

View file

@ -11,4 +11,5 @@ mypy
playwright
requests
types-requests
whitenoise
whitenoise
pygments-djc

View file

@ -8,7 +8,7 @@ asgiref==3.8.1
# via django
black==24.10.0
# via -r requirements-dev.in
cachetools==5.5.0
cachetools==5.5.1
# via tox
certifi==2024.8.30
# via requests
@ -16,15 +16,15 @@ cfgv==3.4.0
# via pre-commit
chardet==5.2.0
# via tox
charset-normalizer==3.4.0
charset-normalizer==3.4.1
# via requests
click==8.1.7
click==8.1.8
# via black
colorama==0.4.6
# via tox
distlib==0.3.9
# via virtualenv
django==5.1.5
django==5.1.6
# via -r requirements-dev.in
djc-core-html-parser==1.0.1
# via -r requirements-dev.in
@ -32,7 +32,7 @@ filelock==3.16.1
# via
# tox
# virtualenv
flake8==7.1.1
flake8==7.1.2
# via
# -r requirements-dev.in
# flake8-pyproject
@ -40,7 +40,7 @@ flake8-pyproject==1.2.3
# via -r requirements-dev.in
greenlet==3.1.1
# via playwright
identify==2.6.3
identify==2.6.7
# via pre-commit
idna==3.10
# via requests
@ -85,6 +85,10 @@ pyee==12.0.0
# via playwright
pyflakes==3.2.0
# via flake8
pygments==2.19.1
# via pygments-djc
pygments-djc==1.0.1
# via -r requirements-dev.in
pyproject-api==1.8.0
# via tox
pytest==8.3.4
@ -93,7 +97,7 @@ pyyaml==6.0.2
# via pre-commit
requests==2.32.3
# via -r requirements-dev.in
sqlparse==0.5.2
sqlparse==0.5.3
# via django
tox==4.24.1
# via -r requirements-dev.in

View file

@ -59,7 +59,7 @@ cssselect2==0.7.0
# via cairosvg
defusedxml==0.7.1
# via cairosvg
django==5.1.5
django==5.1.6
# via hatch.envs.docs
ghp-import==2.1.0
# via mkdocs
@ -178,7 +178,11 @@ platformdirs==4.3.6
pycparser==2.22
# via cffi
pygments==2.19.1
# via mkdocs-material
# via
# mkdocs-material
# pygments-djc
pygments-djc==1.0.1
# via -r requirements-dev.in
pymdown-extensions==10.14.3
# via
# hatch.envs.docs