docs: add 2-level tabs, add examples and plugins, move comunity, split release notes (#1345)
Some checks are pending
Docs - build & deploy / docs (push) Waiting to run
Run tests / build (ubuntu-latest, 3.10) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.11) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.12) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.13) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.8) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.9) (push) Waiting to run
Run tests / build (windows-latest, 3.10) (push) Waiting to run
Run tests / build (windows-latest, 3.11) (push) Waiting to run
Run tests / build (windows-latest, 3.12) (push) Waiting to run
Run tests / build (windows-latest, 3.13) (push) Waiting to run
Run tests / build (windows-latest, 3.8) (push) Waiting to run
Run tests / build (windows-latest, 3.9) (push) Waiting to run
Run tests / test_docs (3.13) (push) Waiting to run
Run tests / test_sampleproject (3.13) (push) Waiting to run

This commit is contained in:
Juro Oravec 2025-08-18 08:58:09 +02:00 committed by GitHub
parent 373d5c7332
commit 8b9b93787f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 736 additions and 87 deletions

View file

@ -94,7 +94,7 @@
- Fix typo preventing benchmarking ([#1235](https://github.com/django-components/django-components/pull/1235)) - Fix typo preventing benchmarking ([#1235](https://github.com/django-components/django-components/pull/1235))
## 🚨📢 v0.140.0 ## v0.140.0 🚨📢
⚠️ Major release ⚠️ - Please test thoroughly before / after upgrading. ⚠️ Major release ⚠️ - Please test thoroughly before / after upgrading.
@ -118,7 +118,7 @@ Summary:
- Component caching can now consider slots (opt-in) - Component caching can now consider slots (opt-in)
- And lot more... - And lot more...
#### 🚨📢 BREAKING CHANGES #### BREAKING CHANGES 🚨📢
**Middleware** **Middleware**
@ -564,7 +564,7 @@ Summary:
render_dependencies(content, strategy="document") render_dependencies(content, strategy="document")
``` ```
#### 🚨📢 Deprecation #### Deprecation 🚨📢
**Component API** **Component API**
@ -1573,9 +1573,9 @@ Summary:
- `Component.get_context_data()` can now omit a return statement or return `None`. - `Component.get_context_data()` can now omit a return statement or return `None`.
## 🚨📢 v0.136 ## v0.136 🚨📢
#### 🚨📢 BREAKING CHANGES #### BREAKING CHANGES 🚨📢
- Component input validation was moved to a separate extension [`djc-ext-pydantic`](https://github.com/django-components/djc-ext-pydantic). - Component input validation was moved to a separate extension [`djc-ext-pydantic`](https://github.com/django-components/djc-ext-pydantic).
@ -2090,13 +2090,15 @@ If you see any broken links or other issues, please report them in [#922](https:
- Prevent rendering Component tags during fill discovery stage to fix a case when a component inside the default slot - Prevent rendering Component tags during fill discovery stage to fix a case when a component inside the default slot
tried to access provided data too early. tried to access provided data too early.
## 🚨📢 v0.110 ## v0.110 🚨📢
_25 Nov 2024_
⚠️ Attention ⚠️ - Please update to v0.117 to fix known bugs. See [#791](https://github.com/django-components/django-components/issues/791) and [#789](https://github.com/django-components/django-components/issues/789) and [#818](https://github.com/django-components/django-components/issues/818). ⚠️ Attention ⚠️ - Please update to v0.117 to fix known bugs. See [#791](https://github.com/django-components/django-components/issues/791) and [#789](https://github.com/django-components/django-components/issues/789) and [#818](https://github.com/django-components/django-components/issues/818).
### General ### General
#### 🚨📢 BREAKING CHANGES #### BREAKING CHANGES 🚨📢
- Installation changes: - Installation changes:
@ -2173,7 +2175,7 @@ importing them.
### Tags ### Tags
#### 🚨📢 BREAKING CHANGES #### BREAKING CHANGES 🚨📢
- `{% component_dependencies %}` tag was removed. Instead, use `{% component_js_dependencies %}` and `{% component_css_dependencies %}` - `{% component_dependencies %}` tag was removed. Instead, use `{% component_js_dependencies %}` and `{% component_css_dependencies %}`
@ -2414,7 +2416,9 @@ importing them.
{% endcomponent %} {% endcomponent %}
``` ```
## 🚨📢 v0.100 ## v0.100 🚨📢
_11 Sep 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2438,6 +2442,8 @@ importing them.
## v0.97 ## v0.97
_6 Sep 2024_
#### Fix #### Fix
- Fixed template caching. You can now also manually create cached templates with [`cached_template()`](https://github.com/django-components/django-components#template_cache_size---tune-the-template-cache) - Fixed template caching. You can now also manually create cached templates with [`cached_template()`](https://github.com/django-components/django-components#template_cache_size---tune-the-template-cache)
@ -2453,15 +2459,19 @@ importing them.
## v0.96 ## v0.96
_4 Sep 2024_
#### Feat #### Feat
- Run-time type validation for Python 3.11+ - If the `Component` class is typed, e.g. `Component[Args, Kwargs, ...]`, the args, kwargs, slots, and data are validated against the given types. (See [Runtime input validation with types](https://github.com/django-components/django-components#runtime-input-validation-with-types)) - Run-time type validation for Python >=3.11 - If the `Component` class is typed, e.g. `Component[Args, Kwargs, ...]`, the args, kwargs, slots, and data are validated against the given types. (See [Runtime input validation with types](https://github.com/django-components/django-components#runtime-input-validation-with-types))
- Render hooks - Set `on_render_before` and `on_render_after` methods on `Component` to intercept or modify the template or context before rendering, or the rendered result afterwards. (See [Component hooks](https://github.com/django-components/django-components#component-hooks)) - Render hooks - Set `on_render_before` and `on_render_after` methods on `Component` to intercept or modify the template or context before rendering, or the rendered result afterwards. (See [Component hooks](https://github.com/django-components/django-components#component-hooks))
- `component_vars.is_filled` context variable can be accessed from within `on_render_before` and `on_render_after` hooks as `self.is_filled.my_slot` - `component_vars.is_filled` context variable can be accessed from within `on_render_before` and `on_render_after` hooks as `self.is_filled.my_slot`
## 0.95 ## v0.95
_29 Aug 2024_
#### Feat #### Feat
@ -2473,6 +2483,8 @@ importing them.
## v0.94 ## v0.94
_28 Aug 2024_
#### Feat #### Feat
- django_components now automatically configures Django to support multi-line tags. (See [Multi-line tags](https://github.com/django-components/django-components#multi-line-tags)) - django_components now automatically configures Django to support multi-line tags. (See [Multi-line tags](https://github.com/django-components/django-components#multi-line-tags))
@ -2481,6 +2493,8 @@ importing them.
## v0.93 ## v0.93
_27 Aug 2024_
#### Feat #### Feat
- Spread operator `...dict` inside template tags. (See [Spread operator](https://github.com/django-components/django-components#spread-operator)) - Spread operator `...dict` inside template tags. (See [Spread operator](https://github.com/django-components/django-components#spread-operator))
@ -2491,7 +2505,9 @@ importing them.
- Component library authors can now configure `CONTEXT_BEHAVIOR` and `TAG_FORMATTER` settings independently from user settings. - Component library authors can now configure `CONTEXT_BEHAVIOR` and `TAG_FORMATTER` settings independently from user settings.
## 🚨📢 v0.92 ## v0.92 🚨📢
_22 Aug 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2505,6 +2521,8 @@ importing them.
## v0.90 ## v0.90
_18 Aug 2024_
#### Feat #### Feat
- All tags (`component`, `slot`, `fill`, ...) now support "self-closing" or "inline" form, where you can omit the closing tag: - All tags (`component`, `slot`, `fill`, ...) now support "self-closing" or "inline" form, where you can omit the closing tag:
@ -2532,7 +2550,7 @@ importing them.
{% endcomponent %} {% endcomponent %}
``` ```
While `django_components.shorthand_component_formatter` allows you to write components like so: While `django_components.component_shorthand_formatter` allows you to write components like so:
```django ```django
{% button href="..." disabled %} {% button href="..." disabled %}
@ -2540,7 +2558,9 @@ importing them.
{% endbutton %} {% endbutton %}
``` ```
## 🚨📢 v0.85 ## v0.85 🚨📢
_29 Jul 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2557,7 +2577,9 @@ importing them.
- Previously, autodiscovery handled relative files in `STATICFILES_DIRS`. To align with Django, `STATICFILES_DIRS` now must be full paths ([Django docs](https://docs.djangoproject.com/en/5.2/ref/settings/#std-setting-STATICFILES_DIRS)). - Previously, autodiscovery handled relative files in `STATICFILES_DIRS`. To align with Django, `STATICFILES_DIRS` now must be full paths ([Django docs](https://docs.djangoproject.com/en/5.2/ref/settings/#std-setting-STATICFILES_DIRS)).
## 🚨📢 v0.81 ## v0.81 🚨📢
_12 Jun 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2571,17 +2593,23 @@ importing them.
## v0.80 ## v0.80
_1 Jun 2024_
#### Feat #### Feat
- Vue-like provide/inject with the `{% provide %}` tag and `inject()` method. - Vue-like provide/inject with the `{% provide %}` tag and `inject()` method.
## 🚨📢 v0.79 ## v0.79 🚨📢
_1 Jun 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
- Default value for the `COMPONENTS.context_behavior` setting was changes from `"isolated"` to `"django"`. If you did not set this value explicitly before, this may be a breaking change. See the rationale for change [here](https://github.com/django-components/django-components/issues/498). - Default value for the `COMPONENTS.context_behavior` setting was changes from `"isolated"` to `"django"`. If you did not set this value explicitly before, this may be a breaking change. See the rationale for change [here](https://github.com/django-components/django-components/issues/498).
## 🚨📢 v0.77 ## v0.77 🚨📢
_23 May 2024_
#### BREAKING #### BREAKING
@ -2604,13 +2632,17 @@ importing them.
## v0.74 ## v0.74
_12 May 2024_
#### Feat #### Feat
- `{% html_attrs %}` tag for formatting data as HTML attributes - `{% html_attrs %}` tag for formatting data as HTML attributes
- `prefix:key=val` construct for passing dicts to components - `prefix:key=val` construct for passing dicts to components
## 🚨📢 v0.70 ## v0.70 🚨📢
_1 May 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2620,11 +2652,15 @@ importing them.
## v0.67 ## v0.67
_17 Apr 2024_
#### Refactor #### Refactor
- Changed the default way how context variables are resolved in slots. See the [documentation](https://github.com/django-components/django-components/tree/0.67#isolate-components-slots) for more details. - Changed the default way how context variables are resolved in slots. See the [documentation](https://github.com/django-components/django-components/tree/0.67#isolate-components-slots) for more details.
## 🚨📢 v0.50 ## v0.50 🚨📢
_26 Feb 2024_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2636,23 +2672,31 @@ importing them.
## v0.34 ## v0.34
_27 Jan 2024_
#### Feat #### Feat
- Components as views, which allows you to handle requests and render responses from within a component. See the [documentation](https://github.com/django-components/django-components#use-components-as-views) for more details. - Components as views, which allows you to handle requests and render responses from within a component. See the [documentation](https://github.com/django-components/django-components#use-components-as-views) for more details.
## v0.28 ## v0.28
_18 May 2023_
#### Feat #### Feat
- 'implicit' slot filling and the `default` option for `slot` tags. - 'implicit' slot filling and the `default` option for `slot` tags.
## v0.27 ## v0.27
_11 Apr 2023_
#### Feat #### Feat
- A second installable app `django_components.safer_staticfiles`. It provides the same behavior as `django.contrib.staticfiles` but with extra security guarantees (more info below in [Security Notes](https://github.com/django-components/django-components#security-notes)). - A second installable app `django_components.safer_staticfiles`. It provides the same behavior as `django.contrib.staticfiles` but with extra security guarantees (more info below in [Security Notes](https://github.com/django-components/django-components#security-notes)).
## 🚨📢 v0.26 ## v0.26 🚨📢
_14 Mar 2023_
#### BREAKING CHANGES #### BREAKING CHANGES
@ -2662,6 +2706,8 @@ importing them.
## v0.22 ## v0.22
_26 Jul 2022_
#### Feat #### Feat
- All files inside components subdirectores are autoimported to simplify setup. - All files inside components subdirectores are autoimported to simplify setup.
@ -2670,6 +2716,8 @@ importing them.
## v0.17 ## v0.17
_10 Sep 2021_
#### BREAKING CHANGES #### BREAKING CHANGES
- Renamed `Component.context` and `Component.template` to `get_context_data` and `get_template_name`. The old methods still work, but emit a deprecation warning. - Renamed `Component.context` and `Component.template` to `get_context_data` and `get_template_name`. The old methods still work, but emit a deprecation warning.

View file

@ -4,7 +4,11 @@
nav: nav:
- overview - overview
- Getting Started: getting_started - Getting Started: getting_started
- concepts - "Documentation: Concepts": concepts
- guides - "Documentation: API Reference": reference
- API Documentation: reference - "Documentation: Guides": guides
- Release Notes: release_notes.md - "Documentation: Upgrading": upgrading
- plugins
- examples
- community
- Release Notes: releases

7
docs/community/.nav.yml Normal file
View file

@ -0,0 +1,7 @@
# `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav
nav:
- Questions & Help: help.md
- Contributing: contributing.md
- Development: development.md
- Code of Conduct: code_of_conduct.md
- Dev Guides: devguides

View file

@ -11,12 +11,12 @@ you out with the rest!
For feature requests or suggestions, please open either a discussion or an issue. For feature requests or suggestions, please open either a discussion or an issue.
## Getting involved ### Getting involved
django_components is still under active development, and there's much to build, django_components is still under active development, and there's much to build,
so come aboard! so come aboard!
## Sponsoring ### Sponsoring
Another way you can get involved is by [donating](https://github.com/django-components/django-components) Another way you can get involved is by [donating](https://github.com/django-components/django-components)
to the development of django_components. to the development of django_components.

View file

@ -189,4 +189,4 @@ python scripts/validate_links.py --rewrite
## Development guides ## Development guides
Head over to [Dev guides](../guides/devguides/dependency_mgmt.md) for a deep dive into how django_components' features are implemented. Head over to [Dev guides](./devguides/dependency_mgmt.md) for a deep dive into how django_components' features are implemented.

3
docs/community/help.md Normal file
View file

@ -0,0 +1,3 @@
The best place to ask questions is in our [Github Discussion board](https://github.com/django-components/django-components/discussions).
Please, before opening a new discussion, [check if similar discussion wasn't opened already](https://github.com/django-components/django-components/discussions?discussions_q=).

View file

@ -1,6 +1,6 @@
You can publish and share your components for others to use. Below you will find the steps to do so. You can publish and share your components for others to use. Below you will find the steps to do so.
For live examples, see the [Community examples](../../overview/community.md#community-examples). For live examples, see the [Examples](../../examples/index.md).
## Writing component libraries ## Writing component libraries

View file

@ -91,7 +91,7 @@ MyTable.render(
## Live examples ## Live examples
For live interactive examples, [start our demo project](../../overview/development.md#developing-against-live-django-app) For live interactive examples, [start our demo project](../../community/development.md#developing-against-live-django-app)
(`sampleproject`). (`sampleproject`).
Then navigate to these URLs: Then navigate to these URLs:

3
docs/examples/.nav.yml Normal file
View file

@ -0,0 +1,3 @@
# `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav
nav:
- Examples: overview.md

14
docs/examples/overview.md Normal file
View file

@ -0,0 +1,14 @@
`django-components` makes it easy to share components between projects
([See how to package components](../concepts/advanced/component_libraries.md)).
Here you will find public examples of components and component libraries.
If you have components that would be useful to others, open a pull request to add them to this collection.
### Icons
- [djc-heroicons](https://pypi.org/project/djc-heroicons/) - Icons from HeroIcons.com for django-components.
### HTMX
- [`django-htmx-components`](https://github.com/iwanalabs/django-htmx-components) - A set of components for use with [htmx](https://htmx.org/).

View file

@ -1,5 +1,6 @@
# `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav # `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav
nav: nav:
- Installation: installation.md
- Create your first component: your_first_component.md - Create your first component: your_first_component.md
- Adding JS and CSS: adding_js_and_css.md - Adding JS and CSS: adding_js_and_css.md
- Components in templates: components_in_templates.md - Components in templates: components_in_templates.md

View file

@ -2,4 +2,3 @@
nav: nav:
- setup - setup
- other - other
- Dev Guides: devguides

View file

@ -0,0 +1,283 @@
{# This overrides the nav-item partial from mkdocs-material v9.6.17 #}
{# https://github.com/squidfunk/mkdocs-material/blob/c89a66bf39bb7f472e925753367ff8e464e0d683/src/templates/partials/nav-item.html #}
{# Majority of the file is the original, so our changes are highlighted #}
{# with `OUR CHANGES START` and `OUR CHANGES END` #}
<!-- Render navigation link status -->
{% macro render_status(nav_item, type) %}
{% set class = "md-status md-status--" ~ type %}
<!-- Render icon with title (or tooltip), if given -->
{% if config.extra.status and config.extra.status[type] %}
<span
class="{{ class }}"
title="{{ config.extra.status[type] }}"
>
</span>
<!-- Render icon only -->
{% else %}
<span class="{{ class }}"></span>
{% endif %}
{% endmacro %}
<!-- Render navigation link content -->
{% macro render_content(nav_item, ref) %}
{% set ref = ref or nav_item %}
<!-- Navigation link icon -->
{% if nav_item.meta and nav_item.meta.icon %}
{% include ".icons/" ~ nav_item.meta.icon ~ ".svg" %}
{% endif %}
<!-- ==================== OUR CHANGES START ==================== -->
{# Insert line break between group name and title #}
{# E.g. `Documentation: API Reference` -> `Documentation:<br>API Reference` #}
{% if ": " in ref.title %}
{% set parts = ref.title.split(": ", 1) %}
{% set title = parts[0] ~ ":<br>" | safe ~ parts[1] %}
{% else %}
{% set title = ref.title %}
{% endif %}
<!-- ==================== OUR CHANGES END ==================== -->
<!-- Navigation link title -->
<span class="md-ellipsis">
{{ title }}
<!-- Navigation link subtitle -->
{% if nav_item.meta and nav_item.meta.subtitle %}
<br />
<small>{{ nav_item.meta.subtitle }}</small>
{% endif %}
</span>
<!-- Navigation link status -->
{% if nav_item.meta and nav_item.meta.status %}
{{ render_status(nav_item, nav_item.meta.status) }}
{% endif %}
{% endmacro %}
<!-- Render navigation item (pruned) -->
{% macro render_pruned(nav_item, ref) %}
{% set ref = ref or nav_item %}
{% set first = nav_item.children | first %}
<!-- Recurse, if the first item has further nested items -->
{% if first and first.children %}
{{ render_pruned(first, ref) }}
<!-- Navigation link -->
{% else %}
<a href="{{ first.url | url }}" class="md-nav__link">
{{ render_content(ref) }}
<!-- Only render toggle if there's at least one nested item -->
{% if nav_item.children | length > 0 %}
<span class="md-nav__icon md-icon"></span>
{% endif %}
</a>
{% endif %}
{% endmacro %}
<!-- Render navigation item -->
{% macro render(nav_item, path, level, parent) %}
<!-- Determine classes -->
{% set class = "md-nav__item" %}
{% if nav_item.active %}
{% set class = class ~ " md-nav__item--active" %}
{% endif %}
<!-- Determine active page for paginated views -->
{% if nav_item.pages %}
{% if page in nav_item.pages %}
{% set nav_item = page %}
{% endif %}
{% endif %}
<!-- Navigation item with nested items -->
{% if nav_item.children %}
<!-- Determine all nested items that are index pages -->
{% set _ = namespace(index = none) %}
{% if "navigation.indexes" in features %}
{% for item in nav_item.children %}
{% if item.is_index and _.index is none %}
{% set _.index = item %}
{% endif %}
{% endfor %}
{% endif %}
{% set index = _.index %}
<!-- Navigation tabs -->
{% if "navigation.tabs" in features %}
<!-- Render 1st level active item as section -->
{% if level == 1 and nav_item.active %}
{% set class = class ~ " md-nav__item--section" %}
{% set is_section = true %}
{% endif %}
<!-- Navigation tabs + sections -->
{% if "navigation.sections" in features %}
<!-- Render 2nd level items with nested items as sections -->
{% if level == 2 and parent.active %}
{% set class = class ~ " md-nav__item--section" %}
{% set is_section = true %}
{% endif %}
{% endif %}
<!-- Navigation sections -->
{% elif "navigation.sections" in features %}
<!-- Render 1st level items with nested items as sections -->
{% if level == 1 %}
{% set class = class ~ " md-nav__item--section" %}
{% set is_section = true %}
{% endif %}
{% endif %}
<!-- Navigation pruning -->
{% if "navigation.prune" in features %}
<!-- Prune item if it is not a section and not active -->
{% if not is_section and not nav_item.active %}
{% set class = class ~ " md-nav__item--pruned" %}
{% set is_pruned = true %}
{% endif %}
{% endif %}
<!-- Nested navigation item -->
<li class="{{ class }} md-nav__item--nested">
{% if not is_pruned %}
{% set checked = "checked" if nav_item.active %}
<!-- Determine checked and indeterminate state -->
{% if "navigation.expand" in features and not checked %}
{% set indeterminate = "md-toggle--indeterminate" %}
{% endif %}
<!-- Active checkbox expands items contained within nested section -->
<input
class="md-nav__toggle md-toggle {{ indeterminate }}"
type="checkbox"
id="{{ path }}"
{{ checked }}
/>
<!-- Toggle to expand nested items -->
{% if not index %}
{% set tabindex = "0" if not is_section %}
<label
class="md-nav__link"
for="{{ path }}"
id="{{ path }}_label"
tabindex="{{ tabindex }}"
>
{{ render_content(nav_item) }}
<span class="md-nav__icon md-icon"></span>
</label>
<!-- Toggle to expand nested items with link to index page -->
{% else %}
{% set class = "md-nav__link--active" if index == page %}
<div class="md-nav__link md-nav__container">
<a
href="{{ index.url | url }}"
class="md-nav__link {{ class }}"
>
{{ render_content(index, nav_item) }}
</a>
<!-- Only render toggle if there's at least one more page -->
{% if nav_item.children | length > 1 %}
{% set tabindex = "0" if not is_section %}
<label
class="md-nav__link {{ class }}"
for="{{ path }}"
id="{{ path }}_label"
tabindex="{{ tabindex }}"
>
<span class="md-nav__icon md-icon"></span>
</label>
{% endif %}
</div>
{% endif %}
<!-- Nested navigation -->
<nav
class="md-nav"
data-md-level="{{ level }}"
aria-labelledby="{{ path }}_label"
aria-expanded="{{ nav_item.active | tojson }}"
>
<label class="md-nav__title" for="{{ path }}">
<span class="md-nav__icon md-icon"></span>
{{ nav_item.title }}
</label>
<ul class="md-nav__list" data-md-scrollfix>
<!-- Nested navigation item -->
{% for item in nav_item.children %}
{% if not index or item != index %}
{{ render(item, path ~ "_" ~ loop.index, level + 1, nav_item) }}
{% endif %}
{% endfor %}
</ul>
</nav>
<!-- Pruned navigation item -->
{% else %}
{{ render_pruned(nav_item) }}
{% endif %}
</li>
<!-- Currently active page -->
{% elif nav_item == page %}
<li class="{{ class }}">
{% set toc = page.toc %}
<!-- State toggle -->
<input
class="md-nav__toggle md-toggle"
type="checkbox"
id="__toc"
/>
<!-- Hack: see partials/toc.html for more information -->
{% set first = toc | first %}
{% if first and first.level == 1 %}
{% set toc = first.children %}
{% endif %}
<!-- Navigation link to table of contents -->
{% if toc %}
<label class="md-nav__link md-nav__link--active" for="__toc">
{{ render_content(nav_item) }}
<span class="md-nav__icon md-icon"></span>
</label>
{% endif %}
<a
href="{{ nav_item.url | url }}"
class="md-nav__link md-nav__link--active"
>
{{ render_content(nav_item) }}
</a>
<!-- Table of contents -->
{% if toc %}
{% include "partials/toc.html" %}
{% endif %}
</li>
<!-- Navigation item -->
{% else %}
<li class="{{ class }}">
<a href="{{ nav_item.url | url }}" class="md-nav__link">
{{ render_content(nav_item) }}
</a>
</li>
{% endif %}
{% endmacro %}

View file

@ -0,0 +1,213 @@
{# This overrides the tabs partial from mkdocs-material v9.6.17 #}
{# https://github.com/squidfunk/mkdocs-material/blob/c89a66bf39bb7f472e925753367ff8e464e0d683/src/templates/partials/tabs.html #}
{#- This macro populates the `grouped_dict`. It doesn't render any HTML. -#}
{% macro group_tabs(nav, grouped_dict) %}
{% for nav_item in nav %}
{#- If tab title contains a colon, split it into group and title. -#}
{% if ': ' in nav_item.title %}
{% set parts = nav_item.title.split(': ', 1) %}
{% set group_name = parts[0] %}
{% set title = parts[1] %}
{% set is_group = True %}
{% else %}
{% set group_name = nav_item.title %}
{% set title = nav_item.title %}
{% set is_group = False %}
{% endif %}
{% if group_name not in grouped_dict %}
{% set group = {"title": group_name, "url": "", "active": False, "is_group": is_group, "items": []} %}
{% set _ = grouped_dict.update({group_name: group}) %}
{% else %}
{% set group = grouped_dict[group_name] %}
{% endif %}
{# Make copies of the nav items, so we can modify the titles #}
{% if is_group %}
{% set item_copy = {"title": title, "url": nav_item.url, "active": nav_item.active, "children": nav_item.children} %}
{% set _ = group["items"].append(item_copy) %}
{% else %}
{% set _ = group["items"].append(nav_item) %}
{% endif %}
{% if nav_item.__class__.__name__ == "Page" and nav_item.active %}
{% set _ = group.update({"active": True}) %}
{% endif %}
{% endfor %}
{% endmacro %}
{# Taken from mkdocs-material v9.6.17 #}
{# https://github.com/squidfunk/mkdocs-material/blob/c89a66bf39bb7f472e925753367ff8e464e0d683/src/templates/partials/tabs-item.html#L67 #}
{% macro render_group_tab(group) %}
<!-- Determine classes -->
{% set class = "md-tabs__item" %}
{% if group.active %}
{% set class = class ~ " md-tabs__item--active" %}
{% endif %}
<li class="{{ class }}" data-tab-group="{{ group.title }}">
<a
href="#"
class="md-tabs__link"
style="cursor: pointer;"
>
{{ group.title }}
</a>
</li>
{% endmacro %}
{# Define the dictionary that will hold the grouped tabs #}
{# And then call the macro to populate the dictionary. This call produces no output. #}
{% set grouped_nav = {} %}
{{ group_tabs(nav, grouped_nav) }}
{# -------------- ACTUAL RENDER STARTS HERE -------------- #}
{% import "partials/tabs-item.html" as item with context %}
<!-- Navigation tabs -->
<nav
class="md-tabs"
aria-label="{{ lang.t('tabs') }}"
data-md-component="tabs"
>
<div class="md-grid">
<ul class="md-tabs__list">
{% for nav_group in grouped_nav.values() %}
{% if nav_group["is_group"] %}
{{ render_group_tab(nav_group) }}
{% else %}
{{ item.render(nav_group["items"][0]) }}
{% endif %}
{% endfor %}
</ul>
{% for nav_group in grouped_nav.values() %}
{% if nav_group["is_group"] %}
<ul class="md-tabs__list tabs-hidden" data-tab-group="{{ nav_group.title }}">
{% for nav_item in nav_group["items"] %}
{{ item.render(nav_item) }}
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</div>
</nav>
<script>
// Set up event listeners, so that, if user clicks on a top-level tab group,
// then we will show the sub-tabs for that group only.
(() => {
const topLevelTabGroups = document.querySelectorAll('li[data-tab-group]');
topLevelTabGroups.forEach(li => {
li._tabGroupHoverTimeout = null;
const linkGroup = li.dataset.tabGroup;
// Allow to permanently open/close the tab group by clicking.
li.addEventListener('click', () => {
li._tabGroupIsOpen ? selectTabGroup(null) : selectTabGroup(linkGroup);
li._tabGroupIsOpen = !li._tabGroupIsOpen;
if (li._tabGroupIsOpen && li._tabGroupHoverTimeout) {
clearTimeout(li._tabGroupHoverTimeout);
li._tabGroupHoverTimeout = null;
}
});
// Allow to temporarily open the tab group by hovering over it.
li.addEventListener('mouseenter', () => {
if (li._tabGroupHoverTimeout) {
clearTimeout(li._tabGroupHoverTimeout);
li._tabGroupHoverTimeout = null;
}
if (li._tabGroupIsOpen) return;
selectTabGroup(linkGroup);
});
li.addEventListener('mouseleave', () => {
if (li._tabGroupIsOpen) return;
delayedCloseTabGroup(li);
});
});
// Also add listeners to the sub-tabs container, so that if user moves
// cursor from the top-level group to sub-tabs, then the container will remain open.
const subTabsContainers = document.querySelectorAll('ul[data-tab-group]');
subTabsContainers.forEach(ul => {
ul.addEventListener('mouseenter', () => {
const tabGroup = ul.dataset.tabGroup;
const toggle = document.querySelector(`li[data-tab-group="${tabGroup}"]`);
if (toggle._tabGroupIsOpen || toggle._tabGroupHoverTimeout === null) return;
clearTimeout(toggle._tabGroupHoverTimeout);
toggle._tabGroupHoverTimeout = null;
});
ul.addEventListener('mouseleave', () => {
const tabGroup = ul.dataset.tabGroup;
const toggle = document.querySelector(`li[data-tab-group="${tabGroup}"]`);
if (toggle._tabGroupIsOpen) return;
delayedCloseTabGroup(toggle);
});
});
function selectTabGroup(groupName) {
const tabGroups = document.querySelectorAll('ul[data-tab-group]');
for (const tabGroupEl of tabGroups) {
const tabGroup = tabGroupEl.dataset.tabGroup;
if (tabGroup === groupName) {
tabGroupEl.classList.remove('tabs-hidden');
} else {
tabGroupEl.classList.add('tabs-hidden');
}
}
}
function delayedCloseTabGroup(toggle) {
toggle._tabGroupHoverTimeout = setTimeout(() => {
if (toggle._tabGroupIsOpen || toggle._tabGroupHoverTimeout === null) {
toggle._tabGroupHoverTimeout = null;
return;
};
toggle._tabGroupHoverTimeout = null;
selectTabGroup(null);
}, 100);
}
})();
</script>
<style>
/* Styles for animated tabs visibility */
.md-tabs__list {
transition: max-height 0.3s ease-in-out;
overflow: hidden;
max-height: 100px;
}
/* Collapse the tabs when the attribute is present */
.md-tabs__list.tabs-hidden {
max-height: 0;
}
/* Custom styling for the sub-tabs */
.md-tabs__list[data-tab-group] {
position: absolute;
width: 100%;
max-width: 61rem;
background-color: var(--md-primary-fg-color);
border-top: 1px var(--md-primary-fg-color--dark) solid;
}
.md-tabs__list[data-tab-group] .md-tabs__item {
height: 2.1rem;
}
.md-tabs__list[data-tab-group] .md-tabs__link {
font-size: 0.63rem;
margin-top: 0.7rem;
}
</style>

View file

@ -2,12 +2,6 @@
nav: nav:
- Welcome to Django Components: welcome.md - Welcome to Django Components: welcome.md
- Compatibility: compatibility.md - Compatibility: compatibility.md
- Installation: installation.md
- Security notes 🚨: security_notes.md - Security notes 🚨: security_notes.md
- Migrating: migrating.md
- Community: community.md
- Contributing: contributing.md
- Development: development.md
- Performance: performance.md - Performance: performance.md
- Code of Conduct: code_of_conduct.md
- License: license.md - License: license.md

View file

@ -1,15 +0,0 @@
## Community questions
The best place to ask questions is in our [Github Discussion board](https://github.com/django-components/django-components/discussions).
Please, before opening a new discussion, [check if similar discussion wasn't opened already](https://github.com/django-components/django-components/discussions?discussions_q=).
## Community examples
One of our goals with `django-components` is to make it easy to share components between projects
([see how to package components](../concepts/advanced/component_libraries.md)).
If you have a set of components that you think would be useful to others, please open a pull request to add them to the list below.
- [django-htmx-components](https://github.com/iwanalabs/django-htmx-components): A set of components for use with [htmx](https://htmx.org/).
- [djc-heroicons](https://pypi.org/project/djc-heroicons/): A component that renders icons from [Heroicons.com](https://heroicons.com/).

View file

@ -1,3 +1,14 @@
We track the performance of `django-components` using [ASV](https://asv.readthedocs.io/en/stable/). We track the performance of `django-components` using [ASV](https://asv.readthedocs.io/en/stable/).
See the [benchmarks dashboard](../../benchmarks). See the [benchmarks dashboard](../../benchmarks).
Our aim is to be at least as fast as Django templates.
As of `0.130`, `django-components` is ~4x slower than Django templates.
| | Render time|
|----------|----------------------|
| django | 68.9±0.6ms |
| django-components | 259±4ms |
See the [full performance breakdown](https://django-components.github.io/django-components/latest/benchmarks/) for more information.

View file

@ -515,31 +515,3 @@ def test_my_table():
{% calendar date="2024-11-06" %} {% calendar date="2024-11-06" %}
{% endcalendar %} {% endcalendar %}
``` ```
## Performance
Our aim is to be at least as fast as Django templates.
As of `0.130`, `django-components` is ~4x slower than Django templates.
| | Render time|
|----------|----------------------|
| django | 68.9±0.6ms |
| django-components | 259±4ms |
See the [full performance breakdown](https://django-components.github.io/django-components/latest/benchmarks/) for more information.
## Release notes
Read the [Release Notes](../release_notes.md)
to see the latest features and fixes.
## Community examples
One of our goals with `django-components` is to make it easy to share components between projects. Head over to the [Community examples](./community.md#community-examples) to see some examples.
## Contributing and development
Get involved or sponsor this project - [See here](./contributing.md)
Running django-components locally for development - [See here](./development.md)

3
docs/plugins/.nav.yml Normal file
View file

@ -0,0 +1,3 @@
# `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav
nav:
- index: index.md

0
docs/plugins/index.md Normal file
View file

View file

@ -4,7 +4,7 @@
Below are all the URL patterns that will be added by adding `django_components.urls`. Below are all the URL patterns that will be added by adding `django_components.urls`.
See [Installation](../overview/installation.md#adding-support-for-js-and-css) See [Installation](../getting_started/installation.md#adding-support-for-js-and-css)
on how to add these URLs to your Django project. on how to add these URLs to your Django project.
Django components already prefixes all URLs with `components/`. So when you are Django components already prefixes all URLs with `components/`. So when you are

View file

@ -1 +0,0 @@
--8<-- "CHANGELOG.md"

View file

@ -0,0 +1,109 @@
import pathlib
import re
from datetime import datetime
import mkdocs_gen_files
from mkdocs_gen_files import Nav
# Project root, relative to this script
ROOT = pathlib.Path(__file__).parent.parent.parent
def generate_release_notes():
"""
Reads CHANGELOG.md, splits it into per-version pages,
and generates an index page with links to all versions.
"""
changelog_path = ROOT / "CHANGELOG.md"
releases_dir = pathlib.Path("releases")
# Create the output directory if it doesn't exist
(ROOT / "docs" / releases_dir).mkdir(parents=True, exist_ok=True)
with open(changelog_path, "r", encoding="utf-8") as f:
changelog_content = f.read()
# Split the changelog by version headers (e.g., "## vX.Y.Z")
# The regex uses a positive lookahead (?=...) to keep the delimiter in the split part.
versions_raw = re.split(r"(?=^##\s+)", changelog_content, flags=re.MULTILINE)
# The navigation object for the release notes section
release_nav = Nav()
# The first item is the main title '# Release notes\n\n', so we skip it.
for version_chunk in versions_raw[1:]:
# The first line is the version header, e.g., "## v0.142.0"
header_line, body = version_chunk.strip().split("\n", 1)
# Individual releases may contain the date of release, e.g.
# ```md
# ## 🚨📢 v0.100
# _11 Sep 2024_
# ```
#
# We want to extract the date, and move it from the body to the title.
date_str = None
# Check for date in format '_DD Mon YYYY_', e.g. "_11 Sep 2024_"
date_match = re.search(r"_(\d{1,2}\s+\w{3}\s+\d{4})_", body)
if date_match:
date_str = date_match.group(1)
body = body.replace(date_str, "").strip()
# Extract the full title from the header, e.g., "🚨📢 v0.140.0"
version_title_full = header_line.replace("##", "").strip()
# Get a clean version string for the filename, e.g., "v0.140.0",
# By removing any emojis, whitespace, and other non-alphanumeric characters.
version_string_clean, _ = re.subn(r"[^a-zA-Z0-9.-_]", "", version_title_full)
if not version_string_clean.startswith("v"):
version_string_clean = "v" + version_string_clean
# Prepare title for navigation, e.g. "v0.140.0 (2024-09-11)"
nav_title = version_title_full
if date_str:
parsed_date = datetime.strptime(date_str, "%d %b %Y")
formatted_date = parsed_date.strftime("%Y-%m-%d")
nav_title += f" ({formatted_date})"
# Generate file name like `v0.140.0.md`
filename = f"{version_string_clean}.md"
page_path = releases_dir / filename
# Create the content for the individual release page
# We use the full title from the changelog for the page's H1
page_content = f"# {nav_title}\n\n{body}"
# Write the individual release page file
with mkdocs_gen_files.open(page_path.as_posix(), "w", encoding="utf-8") as f:
f.write(page_content)
# Add this page to our navigation structure
release_nav[nav_title] = page_path.as_posix()
# Generate the index page that lists all releases
index_path = releases_dir / "index.md"
with mkdocs_gen_files.open(index_path.as_posix(), "w", encoding="utf-8") as f:
f.write("# Release Notes\n\n")
f.write("Here you can find the release notes for all versions of Django-Components.\n\n")
# Manually build the list with correct relative links
for nav_item in release_nav.items():
if nav_item.title and nav_item.filename:
# nav_item.filename is like 'releases/v0.123.md'. We need just 'v0.123.md'.
relative_filename = pathlib.Path(nav_item.filename).name
f.write(f"* [{nav_item.title}]({relative_filename})\n")
# Generate the .nav.yml file for ordering in the sidebar
nav_yml_path = releases_dir / ".nav.yml"
with mkdocs_gen_files.open(nav_yml_path.as_posix(), "w", encoding="utf-8") as f:
f.write("nav:\n")
f.write(" - index.md\n")
for nav_item in release_nav.items():
if nav_item.filename:
relative_filename = pathlib.Path(nav_item.filename).name
f.write(f" - {relative_filename}\n")
# Run the script
generate_release_notes()

View file

@ -2,7 +2,7 @@
Below are all the URL patterns that will be added by adding `django_components.urls`. Below are all the URL patterns that will be added by adding `django_components.urls`.
See [Installation](../overview/installation.md#adding-support-for-js-and-css) See [Installation](../getting_started/installation.md#adding-support-for-js-and-css)
on how to add these URLs to your Django project. on how to add these URLs to your Django project.
Django components already prefixes all URLs with `components/`. So when you are Django components already prefixes all URLs with `components/`. So when you are

3
docs/upgrading/.nav.yml Normal file
View file

@ -0,0 +1,3 @@
# `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav
nav:
- Upgrading in pre-v1.0: v0.md

View file

@ -6,8 +6,6 @@ We try to minimize the number of breaking changes, but sometimes it's unavoidabl
When upgrading, please read the [Release notes](../../release_notes). When upgrading, please read the [Release notes](../../release_notes).
## Migrating in pre-v1.0
If you're on older pre-v1.0 versions of django-components, we recommend doing step-wise If you're on older pre-v1.0 versions of django-components, we recommend doing step-wise
upgrades in the following order: upgrades in the following order:

View file

@ -26,8 +26,7 @@ validation:
theme: theme:
name: "material" name: "material"
# Uncomment to extend / override files from the theme custom_dir: docs/overrides
# custom_dir: docs/overrides
features: features:
- content.action.edit - content.action.edit
- content.action.view - content.action.view
@ -124,6 +123,7 @@ plugins:
scripts: scripts:
- docs/scripts/setup.py - docs/scripts/setup.py
- docs/scripts/reference.py - docs/scripts/reference.py
- docs/scripts/gen_release_notes.py
- awesome-nav - awesome-nav
- git-revision-date-localized: - git-revision-date-localized:
enabled: !ENV [CI, false] enabled: !ENV [CI, false]

View file

@ -270,7 +270,7 @@ def main():
print() print()
print() print()
print("Add this to docs/overview/development.md:\n") print("Add this to docs/community/development.md:\n")
pyenv = build_pyenv(python_to_django) pyenv = build_pyenv(python_to_django)
print(pyenv) print(pyenv)
print() print()