Skip to content

Commit 4938ff7

Browse files
reset a bunch of files
1 parent 95e8f8c commit 4938ff7

File tree

7 files changed

+279
-27
lines changed

7 files changed

+279
-27
lines changed

.pre-commit-config.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
default_language_version:
2-
python: python3.13
2+
python: python3.12
33

44
repos:
55
- repo: https://github.com/pre-commit/pre-commit-hooks
6-
rev: v4.5.0
6+
rev: v5.0.0
77
hooks:
88
- id: trailing-whitespace
99
- id: end-of-file-fixer
1010
- id: check-toml
1111
- id: check-yaml
1212

1313
- repo: https://github.com/adamchainz/django-upgrade
14-
rev: 1.16.0
14+
rev: 1.21.0
1515
hooks:
1616
- id: django-upgrade
1717
args: [--target-version, "4.2"]
1818

1919
- repo: https://github.com/astral-sh/ruff-pre-commit
20-
rev: v0.2.1
20+
rev: v0.6.9
2121
hooks:
2222
- id: ruff
2323
args: [--fix]
2424
- id: ruff-format
2525

2626
- repo: https://github.com/adamchainz/blacken-docs
27-
rev: 1.16.0
27+
rev: 1.18.0
2828
hooks:
2929
- id: blacken-docs
3030
alias: autoformat
@@ -45,7 +45,7 @@ repos:
4545
files: '^(?!.*\.min\..*)(?P<name>[\w-]+(\.[\w-]+)*\.(js|jsx|ts|tsx|yml|yaml|css))$'
4646

4747
- repo: https://github.com/djlint/djLint
48-
rev: v1.34.1
48+
rev: v1.35.2
4949
hooks:
5050
- id: djlint-reformat-django
5151
- id: djlint-django
@@ -62,12 +62,12 @@ repos:
6262
types_or: [html, jsx, tsx]
6363

6464
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
65-
rev: v2.12.0
65+
rev: v2.14.0
6666
hooks:
6767
- id: pretty-format-toml
6868
args: [--autofix]
6969

7070
- repo: https://github.com/abravalheri/validate-pyproject
71-
rev: v0.16
71+
rev: v0.20.2
7272
hooks:
7373
- id: validate-pyproject

.readthedocs.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ version: 2
66
build:
77
os: ubuntu-22.04
88
tools:
9-
python: "3.13"
9+
python: "3.12"
1010
commands:
1111
- asdf plugin add just && asdf install just latest && asdf global just latest
1212
- asdf plugin add uv && asdf install uv latest && asdf global uv latest
1313
- just docs cog
14-
- uv run --extra docs sphinx-build docs $READTHEDOCS_OUTPUT/html
14+
- just docs build $READTHEDOCS_OUTPUT/html
1515

1616
sphinx:
17-
configuration: docs/conf.py
17+
configuration: docs/conf.py
1818

1919
formats:
20-
- pdf
21-
- epub
20+
- pdf
21+
- epub

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# Authors
22

33
- Josh Thomas <[email protected]>
4+
- Jeff Triplett [@jefftriplett](https://github.com/jefftriplett)

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ We adhere to Django's Code of Conduct in all interactions and expect all contrib
1010

1111
## Setup
1212

13-
The following setup steps assume you are using a Unix-like operating system, such as Linux or macOS, and that you have a [supported](README.md#requirements) version of Python installed. If you are using Windows, you will need to adjust the commands accordingly. If you do not have Python installed, you can visit [python.org](https://www.python.org/) for instructions on how to install it for your operating system.
13+
The following setup steps assume you are using a Unix-like operating system, such as Linux or macOS, and that you have a [supported](https://django-simple-nav.westervelt.dev/en/latest/#requirements) version of Python installed. If you are using Windows, you will need to adjust the commands accordingly. If you do not have Python installed, you can visit [python.org](https://www.python.org/) for instructions on how to install it for your operating system.
1414

1515
1. Fork the repository and clone it locally.
1616
2. Create a virtual environment and activate it. You can use whatever tool you prefer for this. Below is an example using the Python standard library's `venv` module:

Justfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ bootstrap:
2525
coverage:
2626
@just nox coverage
2727

28+
demo:
29+
@just nox demo
30+
2831
lint:
2932
uv run --with pre-commit-uv pre-commit run --all-files
3033
just fmt

README.md

Lines changed: 241 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,265 @@
11
# django-simple-nav
22

3+
<!-- intro-start -->
34
[![PyPI](https://img.shields.io/pypi/v/django-simple-nav)](https://pypi.org/project/django-simple-nav/)
45
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-simple-nav)
56
![Django Version](https://img.shields.io/badge/django-4.2%20%7C%205.0%20%7C%205.1-%2344B78B?labelColor=%23092E20)
67
<!-- https://shields.io/badges -->
78
<!-- django-4.2 | 5.0 | 5.1-#44B78B -->
89
<!-- labelColor=%23092E20 -->
910

11+
`django-simple-nav` is a Python/Django application designed to simplify the integration of navigation and menu bars in your Django projects. With a straightforward API and customizable options, you can easily add and manage navigational elements in your web applications. It is designed to be simple to start with, but flexible enough to handle complex navigation structures while maintaining that same simplicity.
12+
1013
## Requirements
1114

12-
- Python 3.9, 3.10, 3.11, 3.12, 3.13
15+
- Python 3.8, 3.9, 3.10, 3.11, 3.12, 3.13
1316
- Django 4.2, 5.0, 5.1
1417

1518
## Installation
1619

17-
1. Install the package from PyPI:
20+
<!-- getting-started-start -->
21+
1. **Install the package from PyPI.**
22+
23+
```bash
24+
python -m pip install django-simple-nav
25+
```
26+
27+
1. **Add `django_simple_nav` to `INSTALLED_APPS`.**
28+
29+
After installation, add `django_simple_nav` to your `INSTALLED_APPS` in your Django settings:
1830

19-
```bash
20-
python -m pip install django-simple-nav
21-
```
31+
```python
32+
INSTALLED_APPS = [
33+
# ...,
34+
"django_simple_nav",
35+
# ...,
36+
]
37+
```
2238

23-
2. Add the app to your Django project's `INSTALLED_APPS`:
39+
1. **Adjust your Django project's settings.**
2440
25-
```python
26-
INSTALLED_APPS = [
27-
...,
28-
"django_simple_nav",
29-
...,
30-
]
31-
```
41+
If you plan to use the permissions feature of `django-simple-nav` to filter your navigation items based on the `request.user`, `django.contrib.auth` and `django.contrib.contenttypes` must be added to your `INSTALLED_APPS` as well:
42+
43+
```python
44+
INSTALLED_APPS = [
45+
# ...,
46+
"django.contrib.auth",
47+
"django.contrib.contenttypes",
48+
# ...,
49+
]
50+
```
51+
52+
If you do not add `django.contrib.auth` to your `INSTALLED_APPS` and you define any permissions for your navigation items, `django-simple-nav` will simply ignore the permissions and render all items regardless of whether the permission check is `True` or `False.`
53+
<!-- getting-started-end -->
3254
3355
## Getting Started
3456
57+
<!-- usage-start -->
58+
1. **Create a navigation definition.**
59+
60+
Define your navigation structure in a Python file. This file can be located anywhere in your Django project, provided it's importable. You can also split the navigations across multiple files if desired.
61+
62+
A good starting point is to create a single `nav.py` or `navigation.py` file in your Django project's main configuration directory (where your `settings.py` file is located).
63+
64+
`django-simple-nav` provides three classes to help you define your navigation structure:
65+
66+
- `Nav`: The main container for a navigation structure. It has two required attributes:
67+
- `template_name`: The name of the template to render the navigation structure.
68+
- `items`: A list of `NavItem` or `NavGroup` objects that represent the navigation structure.
69+
- `NavGroup`: A container for a group of `NavItem` or `NavGroup` objects. It has two required and three optional attributes:
70+
- `title`: The title of the group.
71+
- `items`: A list of `NavItem` or `NavGroup`objects that represent the structure of the group.
72+
- `url` (optional): The URL of the group. If not provided, the group will not be a link but just a container for the items.
73+
- `permissions` (optional): A list of permissions that control the visibility of the group. These permissions can be `User` attributes (e.g. `is_authenticated`, `is_staff`, `is_superuser`), Django permissions (e.g. `myapp.django_perm`), or a callable that takes an `HttpRequest` and returns a `bool`.
74+
- `extra_context` (optional): A dictionary of additional context to pass to the template when rendering the navigation.
75+
- `NavItem`: A single navigation item. It has two required and three optional attributes:
76+
- `title`: The title of the item.
77+
- `url`: The URL of the item. This can be a URL string (e.g. `https://example.com/about/` or `/about/`) or a Django URL name (e.g. `about-view`).
78+
- `permissions` (optional): A list of permissions that control the visibility of the item. These permissions can be `User` attributes (e.g. `is_authenticated`, `is_staff`, `is_superuser`), Django permissions (e.g. `myapp.django_perm`), or a callable that takes an `HttpRequest` and returns a `bool`.
79+
- `extra_context` (optional): A dictionary of additional context to pass to the template when rendering the navigation.
80+
81+
Here's an example configuration:
82+
83+
```python
84+
# config/nav.py
85+
from django.http import HttpRequest
86+
87+
from django_simple_nav.nav import Nav
88+
from django_simple_nav.nav import NavGroup
89+
from django_simple_nav.nav import NavItem
90+
91+
92+
def simple_permissions_check(request: HttpRequest) -> bool:
93+
return True
94+
95+
96+
class MainNav(Nav):
97+
template_name = "main_nav.html"
98+
items = [
99+
NavItem(title="Relative URL", url="/relative-url"),
100+
NavItem(title="Absolute URL", url="https://example.com/absolute-url"),
101+
NavItem(title="Internal Django URL by Name", url="fake-view"),
102+
NavGroup(
103+
title="Group",
104+
url="/group",
105+
items=[
106+
NavItem(title="Relative URL", url="/relative-url"),
107+
NavItem(title="Absolute URL", url="https://example.com/absolute-url"),
108+
NavItem(title="Internal Django URL by Name", url="fake-view"),
109+
],
110+
),
111+
NavGroup(
112+
title="Container Group",
113+
items=[
114+
NavItem(title="Item", url="#"),
115+
],
116+
),
117+
NavItem(
118+
title="is_authenticated Item", url="#", permissions=["is_authenticated"]
119+
),
120+
NavItem(title="is_staff Item", url="#", permissions=["is_staff"]),
121+
NavItem(title="is_superuser Item", url="#", permissions=["is_superuser"]),
122+
NavItem(
123+
title="myapp.django_perm Item", url="#", permissions=["myapp.django_perm"]
124+
),
125+
NavItem(
126+
title="Item with callable permission",
127+
url="#",
128+
permissions=[simple_permissions_check],
129+
),
130+
NavGroup(
131+
title="Group with Extra Context",
132+
items=[
133+
NavItem(
134+
title="Item with Extra Context",
135+
url="#",
136+
extra_context={"foo": "bar"},
137+
),
138+
],
139+
extra_context={"baz": "qux"},
140+
),
141+
]
142+
```
143+
144+
2. **Create a template for the navigation.**
145+
146+
Create a template to render the navigation structure. This is just a standard Django template so you can use any Django template features you like.
147+
148+
The template will be passed an `items` variable in the context representing the structure of the navigation, containing the `NavItem` and `NavGroup` objects defined in your navigation.
149+
150+
Any items with permissions attached will automatically filtered out before rendering the template based on the request user's permissions, so you don't need to worry about that in your template.
151+
152+
Items with extra context will have that context passed to the template when rendering the navigation, which you can access directly.
153+
154+
For example, given the above example `MainNav`, you could create a `main_nav.html` template:
155+
156+
```htmldjango
157+
<!-- main_nav.html -->
158+
<ul>
159+
{% for item in items %}
160+
<li>
161+
<a href="{{ item.url }}"{% if item.active %} class="active"{% endif %}{% if item.baz %} data-baz="{{ item.baz }}"{% endif %}>
162+
{{ item.title }}
163+
</a>
164+
{% if item.items %}
165+
<ul>
166+
{% for subitem in item.items %}
167+
<li>
168+
<a href="{{ subitem.url }}"{% if subitem.active %} class="active"{% endif %}{% if item.foo %} data-foo="{{ item.foo }}"{% endif %}>
169+
{{ subitem.title }}
170+
</a>
171+
</li>
172+
{% endfor %}
173+
</ul>
174+
{% endif %}
175+
</li>
176+
{% endfor %}
177+
</ul>
178+
```
179+
180+
1. **Integrate navigation in templates.**:
181+
182+
Use the `django_simple_nav` template tag in your Django templates where you want to display the navigation.
183+
184+
For example:
185+
186+
```htmldjango
187+
<!-- base.html -->
188+
{% load django_simple_nav %}
189+
190+
{% block navigation %}
191+
<nav>
192+
{% django_simple_nav "path.to.MainNav" %}
193+
</nav>
194+
{% endblock navigation %}
195+
```
196+
197+
The template tag can either take a string representing the import path to your navigation definition or an instance of your navigation class:
198+
199+
```python
200+
# example_app/views.py
201+
from config.nav import MainNav
202+
203+
204+
def example_view(request):
205+
return render(request, "example_app/example_template.html", {"nav": MainNav()})
206+
```
207+
208+
```htmldjango
209+
<!-- example_app/example_template.html -->
210+
{% extends "base.html" %}
211+
{% load django_simple_nav %}
212+
213+
{% block navigation %}
214+
<nav>
215+
{% django_simple_nav nav %}
216+
</nav>
217+
{% endblock navigation %}
218+
```
219+
220+
Additionally, the template tag can take a second argument to specify the template to use for rendering the navigation. This is useful if you want to use the same navigation structure in multiple places but render it differently.
221+
222+
```htmldjango
223+
<!-- base.html -->
224+
{% load django_simple_nav %}
225+
226+
<footer>
227+
{% django_simple_nav "path.to.MainNav" "footer_nav.html" %}
228+
</footer>
229+
```
230+
231+
After configuring your navigation, you can use it across your Django project by calling the `django_simple_nav` template tag in your templates. This tag dynamically renders navigation based on your defined structure, ensuring a consistent and flexible navigation experience throughout your application.
232+
<!-- usage-end -->
233+
234+
## Examples
235+
236+
The [`example`](example/) directory contains a simple Django project that demonstrates how to use `django-simple-nav`. The example project includes a navigation definitions for a few different scenarios as well as some popular CSS frameworks.
237+
238+
You can run the example project by following these steps. These steps assume you have `git` and `python` installed on your system and are using a Unix-like shell. If you are using Windows, you may need to adjust the commands accordingly.
239+
240+
1. **Clone the repository.**
241+
242+
```bash
243+
git clone https://github.com/westerveltco/django-simple-nav
244+
cd django-simple-nav
245+
```
246+
247+
1. **Create a new virtual environment, activate it, and install `django-simple-nav`.**
248+
249+
```bash
250+
python -m venv venv
251+
source venv/bin/activate
252+
python -m pip install .
253+
```
254+
255+
1. **Run the example project.**
256+
257+
```bash
258+
python example/demo.py
259+
```
260+
261+
1. **Open your browser to `http://localhost:8000` to see the examples in action.**
262+
35263
## Documentation
36264
37265
Please refer to the [documentation](https://django-simple-nav.westervelt.dev/) for more information.

0 commit comments

Comments
 (0)