Metadata-Version: 2.4
Name: django-admin-collapse-apps
Version: 0.1.1
Summary: Add collapsible app groups to Django's built-in admin sidebar.
Project-URL: Homepage, https://github.com/kroxiksut/django-admin-collapse-apps
Project-URL: Repository, https://github.com/kroxiksut/django-admin-collapse-apps
Project-URL: Issues, https://github.com/kroxiksut/django-admin-collapse-apps/issues
Author: kroxiksut
License-Expression: MIT
License-File: LICENSE
Keywords: admin,collapsible,django,navigation,sidebar
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: django<6.1,>=4.2
Provides-Extra: playwright
Requires-Dist: playwright>=1.40; extra == 'playwright'
Requires-Dist: pytest>=8.0; extra == 'playwright'
Provides-Extra: quality
Requires-Dist: ruff<0.16,>=0.15; extra == 'quality'
Provides-Extra: test
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# django-admin-collapse-apps

[![CI](https://github.com/kroxiksut/django-admin-collapse-apps/actions/workflows/ci.yml/badge.svg)](https://github.com/kroxiksut/django-admin-collapse-apps/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/django-admin-collapse-apps.svg)](https://pypi.org/project/django-admin-collapse-apps/)
[![Python versions](https://img.shields.io/pypi/pyversions/django-admin-collapse-apps.svg)](https://pypi.org/project/django-admin-collapse-apps/)
[![Django versions](https://img.shields.io/badge/Django-4.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-092E20.svg)](https://www.djangoproject.com/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**Collapsible app groups for the built-in Django admin sidebar — no theme, no jQuery, no server-side state.**

📖 **English** · [Русский](README.ru.md)

`django-admin-collapse-apps` adds a small toggle button to each app group in
Django's standard admin sidebar (and dashboard app list) so you can collapse the
apps you rarely touch. It enhances the sidebar Django already ships — it does not
replace it — and it stays fully usable when JavaScript is disabled.

| Expanded | Collapsed |
| :---: | :---: |
| ![Admin sidebar with every app group expanded](https://raw.githubusercontent.com/kroxiksut/django-admin-collapse-apps/main/docs/assets/admin-sidebar-expanded.png) | ![Admin sidebar with Catalog and Orders collapsed](https://raw.githubusercontent.com/kroxiksut/django-admin-collapse-apps/main/docs/assets/admin-sidebar-collapsed.png) |

## Features

- **Zero-config.** Install the app and every eligible app group gets a collapse toggle.
- **Non-invasive.** Keeps Django's sidebar structure, permissions, ordering, and search intact.
- **Remembers your choice.** Collapsed state is stored in one browser cookie per user agent.
- **Progressive enhancement.** Without JavaScript the sidebar stays fully expanded and usable.
- **Accessible.** Real `<button>` controls with synced `aria-expanded` / `aria-controls`, keyboard support, and a visible focus ring.
- **Search-friendly.** Sidebar search still reveals models inside collapsed groups, then your collapsed state is restored.
- **Themeable.** Works with Django's light and dark admin themes; a few namespaced CSS variables let you restyle the toggle.

### What it deliberately does not do

- Does not replace the full admin sidebar template.
- Does not add jQuery, icon fonts, CDN assets, or any frontend dependency.
- Does not persist state on the server (one cookie only, in the MVP).
- Does not touch admin permissions, model ordering, or your project branding.

## Requirements

- Python 3.10 – 3.14
- Django 4.2, 5.0, 5.1, 5.2, or 6.0

## Installation

```console
python -m pip install django-admin-collapse-apps
```

Add the app to `INSTALLED_APPS` **before** `django.contrib.admin` so Django can
discover the package's `admin/base_site.html` extension:

```python
INSTALLED_APPS = [
    "django_admin_collapse_apps",
    "django.contrib.admin",
    # ...
]
```

That's it. Open any admin page and each app group in the sidebar now has a
toggle. No further configuration is required.

## Configuration

By default every app group is collapsible. To restrict toggles to specific apps,
set `ADMIN_COLLAPSE_APPS` to a list of Django **app labels**:

```python
ADMIN_COLLAPSE_APPS = ["auth", "orders", "catalog"]
```

Normalization rules:

| Value | Result |
| --- | --- |
| unset / `None` / `[]` / `()` | all sidebar apps are collapsible |
| `list` / `tuple` of app labels | only those apps are collapsible |
| a plain string like `"auth"` | **invalid** — never split into characters |
| empty or whitespace-only entries | **invalid** |

App labels are stripped of surrounding whitespace and deduplicated (first
occurrence wins). Invalid values degrade safely to the "all apps" behavior, and
Django's system check framework reports the problem as
`django_admin_collapse_apps.E001` when you run `manage.py check`.

> **Tip:** an app label is the segment in the admin URL — `/admin/auth/user/`
> belongs to the `auth` app, `/admin/support/ticket/` to the `support` app. Use
> app labels, not verbose names or import paths.

If you list an app label that is not installed, Django's system check reports it
as a warning (`django_admin_collapse_apps.W001`) — the entry simply never
matches a sidebar group.

### Multiple admin sites on one domain

Collapsed state is stored in a single cookie named `django_admin_collapsed_apps`.
If you run more than one admin instance on the same domain (for example under
different path prefixes) and want each to keep independent state, set a cookie
namespace:

```python
ADMIN_COLLAPSE_APPS_COOKIE_NAMESPACE = "backoffice"
```

The cookie is then named `django_admin_collapsed_apps_backoffice`. The namespace
must be a short token of ASCII letters, digits, hyphen, or underscore (1–64
characters); an invalid value is reported as
`django_admin_collapse_apps.W002` and safely falls back to the default cookie
name.

## How it works

1. The setting is normalized once on the server into a small JSON payload
   (`{mode, allApps, appLabels}`) rendered into a `<script type="application/json">`
   element by the package's `admin/base_site.html`.
2. A vanilla-JS runtime reads that payload and scopes itself to Django's standard
   app-list containers only: `#nav-sidebar` on model pages and
   `#content-main` on the dashboard (detected via the `dashboard` body class, so
   it works on Django 4.2 through 6.0). On any other page it exits quietly.
3. It inserts one accessible toggle per eligible group, restores collapsed state
   from the `django_admin_collapsed_apps` cookie, and keeps that cookie in sync as
   you collapse and expand groups.

The cookie stores only comma-separated app labels, uses `SameSite=Lax` (and adds
`Secure` on HTTPS), and is deleted entirely once nothing is collapsed.

## Customizing the toggle

The stylesheet exposes namespaced CSS variables. Override them in your own admin
CSS (loaded after the package stylesheet):

```css
:root {
    --django-admin-collapse-apps-toggle-color: currentColor;
    --django-admin-collapse-apps-toggle-expanded-symbol: "▾";
    --django-admin-collapse-apps-toggle-collapsed-symbol: "▸";
    --django-admin-collapse-apps-toggle-focus-ring: currentColor;
    --django-admin-collapse-apps-toggle-focus-ring-width: 2px;
    --django-admin-collapse-apps-toggle-focus-ring-offset: 2px;
    --django-admin-collapse-apps-toggle-float: right;
    --django-admin-collapse-apps-toggle-margin-inline-start: 0.5rem;
    --django-admin-collapse-apps-toggle-margin-inline-end: 0;
}
```

For example, to use ASCII symbols or move the toggle before the app name:

```css
:root {
    --django-admin-collapse-apps-toggle-expanded-symbol: "v";
    --django-admin-collapse-apps-toggle-collapsed-symbol: ">";
    --django-admin-collapse-apps-toggle-float: left;
    --django-admin-collapse-apps-toggle-margin-inline-start: 0;
    --django-admin-collapse-apps-toggle-margin-inline-end: 0.35rem;
}
```

The stylesheet is scoped to `#nav-sidebar`, `body.dashboard #content-main`, and
package-owned classes, and it honors `prefers-reduced-motion` and
`forced-colors`.

## Custom `admin/base_site.html`

If your project already overrides `admin/base_site.html` and preserves Django's
`extrahead`/`extrastyle` blocks with `{{ block.super }}`, the package assets are
still discovered automatically. If your template fully owns those blocks, load
the assets explicitly:

```django
{% extends "admin/base_site.html" %}
{% load django_admin_collapse_apps %}

{% block extrahead %}
{{ block.super }}
{% collapse_apps_assets %}
{% endblock %}
```

`collapse_apps_assets` renders the stylesheet, the JSON config, and the script
together. The lower-level tags `collapse_apps_stylesheet`,
`collapse_apps_config_script`, and `collapse_apps_javascript` are available when
you need finer placement. Don't copy Django's full sidebar template just to
enable this package.

## Third-party admin themes

This package enhances Django's **built-in** admin sidebar; it does not replace
it. Whether it works with a third-party theme depends on how that theme renders
navigation:

- **Themes that keep the stock sidebar markup** (a `#nav-sidebar` nav with
  `app-<label>` groups, and/or a `body.dashboard #content-main` app list) work
  as-is — for example projects that only restyle the standard admin with CSS.
- **Themes that replace the sidebar** with their own navigation component
  (e.g. Jazzmin, django-admin-interface's custom nav, Grappelli, Unfold) render
  a different DOM, so the runtime finds no eligible groups and exits quietly. It
  will not break the theme, but it also has nothing to collapse. Those themes
  usually ship their own menu-collapsing feature — use that instead.

If a theme only overrides `admin/base_site.html`, keep Django's
`extrahead`/`extrastyle` blocks (or load the assets explicitly as shown above)
and the standard sidebar continues to work. The runtime is idempotent and scoped
to package-owned DOM hooks, so it is safe to leave enabled even when a page has
no collapsible groups.

## Troubleshooting

### Toggles do not appear

Make sure `django_admin_collapse_apps` is listed **before**
`django.contrib.admin` in `INSTALLED_APPS`. The package provides its admin
templates and static assets through that ordering.

### I use a custom `admin/base_site.html`

Keep `{{ block.super }}` in both the `extrahead` and `extrastyle` blocks, or
load the assets explicitly with `{% collapse_apps_assets %}` (see
[Custom `admin/base_site.html`](#custom-adminbase_sitehtml)).

### Static files are missing in production

Run `python manage.py collectstatic` and confirm your static-files setup serves
`django_admin_collapse_apps/css/collapse_apps.css` and
`django_admin_collapse_apps/js/collapse_apps.js`.
`python manage.py findstatic django_admin_collapse_apps/js/collapse_apps.js`
should print a path.

### The aria-label / tooltip text is in English

The toggle's accessible label and tooltip are currently English-only
("Expand …" / "Collapse …"); the visible control is a language-neutral symbol.
Full localization is planned for a future release.

## Demo project

The repository ships a small demo project (`catalog`, `orders`, `support`,
`reports`, plus the standard `auth` app) for manual validation and screenshots:

```console
python demo/manage.py migrate --run-syncdb
python demo/bootstrap_demo.py
python demo/manage.py runserver
```

Sign in at http://127.0.0.1:8000/admin/ with `admin` / `admin`. The default
mode (`demo_project.settings.all_apps`) makes every app collapsible;
`demo_project.settings.selected_apps` restricts toggles to `catalog` and
`orders`.

## Development

```console
python -m pip install -e ".[quality]"
python -m ruff check .        # lint
npm run check:js              # JavaScript syntax check (Node's --check)
python -m pytest              # test suite (self-configures Django; no plugin)
python -m build               # build wheel + sdist
```

The test suite is behavior-focused: configuration normalization, template-tag
rendering, end-to-end admin integration, the demo project, packaging metadata,
and a small set of static-asset guards.

## AI integration guides

Wiring this package in with an AI coding agent? Point it at [`docs/ai/`](docs/ai/README.md)
— concise, English-only integration/presentation/runtime guides written for AI
tooling.

## License

MIT — see [LICENSE](LICENSE).
