django-newadmin 0.1.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_newadmin-0.1.0a1/.github/workflows/ci.yml +101 -0
- django_newadmin-0.1.0a1/.github/workflows/django-main.yml +22 -0
- django_newadmin-0.1.0a1/.github/workflows/docs.yml +52 -0
- django_newadmin-0.1.0a1/.github/workflows/publish-pypi.yml +65 -0
- django_newadmin-0.1.0a1/.github/workflows/publish-testpypi.yml +46 -0
- django_newadmin-0.1.0a1/.gitignore +20 -0
- django_newadmin-0.1.0a1/.readthedocs.yaml +14 -0
- django_newadmin-0.1.0a1/CHANGELOG.md +24 -0
- django_newadmin-0.1.0a1/DESIGN.md +225 -0
- django_newadmin-0.1.0a1/LICENSE +29 -0
- django_newadmin-0.1.0a1/PKG-INFO +139 -0
- django_newadmin-0.1.0a1/README.md +105 -0
- django_newadmin-0.1.0a1/SPEC.md +299 -0
- django_newadmin-0.1.0a1/assets/scss/components/_accessibility.scss +15 -0
- django_newadmin-0.1.0a1/assets/scss/components/_actions.scss +54 -0
- django_newadmin-0.1.0a1/assets/scss/components/_auxiliary.scss +123 -0
- django_newadmin-0.1.0a1/assets/scss/components/_changelist.scss +46 -0
- django_newadmin-0.1.0a1/assets/scss/components/_dashboard.scss +301 -0
- django_newadmin-0.1.0a1/assets/scss/components/_filters.scss +114 -0
- django_newadmin-0.1.0a1/assets/scss/components/_forms.scss +223 -0
- django_newadmin-0.1.0a1/assets/scss/components/_glass.scss +79 -0
- django_newadmin-0.1.0a1/assets/scss/components/_inlines.scss +160 -0
- django_newadmin-0.1.0a1/assets/scss/components/_navigation.scss +35 -0
- django_newadmin-0.1.0a1/assets/scss/components/_relations.scss +246 -0
- django_newadmin-0.1.0a1/assets/scss/components/_responsive.scss +53 -0
- django_newadmin-0.1.0a1/assets/scss/components/_shell.scss +259 -0
- django_newadmin-0.1.0a1/assets/scss/components/_widgets.scss +226 -0
- django_newadmin-0.1.0a1/assets/scss/newadmin.scss +27 -0
- django_newadmin-0.1.0a1/assets/scss/theme.scss +686 -0
- django_newadmin-0.1.0a1/demo/__init__.py +1 -0
- django_newadmin-0.1.0a1/demo/catalog/__init__.py +1 -0
- django_newadmin-0.1.0a1/demo/catalog/admin.py +48 -0
- django_newadmin-0.1.0a1/demo/catalog/apps.py +8 -0
- django_newadmin-0.1.0a1/demo/catalog/dashboard.py +146 -0
- django_newadmin-0.1.0a1/demo/catalog/management/__init__.py +1 -0
- django_newadmin-0.1.0a1/demo/catalog/management/commands/__init__.py +1 -0
- django_newadmin-0.1.0a1/demo/catalog/management/commands/seed_demo.py +29 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/0001_initial.py +77 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/0002_alter_article_body.py +18 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/0003_articlelink_articlesection.py +65 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/0004_article_topics_articlelink_category.py +31 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/0005_article_attachment.py +27 -0
- django_newadmin-0.1.0a1/demo/catalog/migrations/__init__.py +0 -0
- django_newadmin-0.1.0a1/demo/catalog/models.py +85 -0
- django_newadmin-0.1.0a1/demo/config/__init__.py +1 -0
- django_newadmin-0.1.0a1/demo/config/settings.py +72 -0
- django_newadmin-0.1.0a1/demo/config/urls.py +6 -0
- django_newadmin-0.1.0a1/demo/manage.py +12 -0
- django_newadmin-0.1.0a1/docs/accessibility.md +49 -0
- django_newadmin-0.1.0a1/docs/changelog.md +5 -0
- django_newadmin-0.1.0a1/docs/conf.py +16 -0
- django_newadmin-0.1.0a1/docs/configuration.md +186 -0
- django_newadmin-0.1.0a1/docs/dashboard.md +200 -0
- django_newadmin-0.1.0a1/docs/extensions.md +34 -0
- django_newadmin-0.1.0a1/docs/index.md +32 -0
- django_newadmin-0.1.0a1/docs/installation.md +129 -0
- django_newadmin-0.1.0a1/docs/proposals/dashboard-v2.md +252 -0
- django_newadmin-0.1.0a1/docs/releasing.md +152 -0
- django_newadmin-0.1.0a1/docs/superpowers/plans/2026-10-17-dashboard-echarts.md +91 -0
- django_newadmin-0.1.0a1/docs/troubleshooting.md +45 -0
- django_newadmin-0.1.0a1/package-lock.json +538 -0
- django_newadmin-0.1.0a1/package.json +19 -0
- django_newadmin-0.1.0a1/pyproject.toml +60 -0
- django_newadmin-0.1.0a1/scripts/build-charts.mjs +17 -0
- django_newadmin-0.1.0a1/scripts/build-css-license.mjs +6 -0
- django_newadmin-0.1.0a1/scripts/build-icons.mjs +20 -0
- django_newadmin-0.1.0a1/scripts/smoke_wheel.py +93 -0
- django_newadmin-0.1.0a1/src/newadmin/__init__.py +3 -0
- django_newadmin-0.1.0a1/src/newadmin/apps.py +13 -0
- django_newadmin-0.1.0a1/src/newadmin/checks.py +28 -0
- django_newadmin-0.1.0a1/src/newadmin/conf.py +168 -0
- django_newadmin-0.1.0a1/src/newadmin/dashboard.py +72 -0
- django_newadmin-0.1.0a1/src/newadmin/navigation.py +37 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/css/bootstrap.min.css +1 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/css/newadmin.css +2492 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/icons.svg +44 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/js/accessibility.js +42 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/js/appearance.js +51 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/js/dashboard-charts.js +95 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/js/navigation.js +38 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/bootstrap/LICENSE +21 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/bootstrap-icons/LICENSE +21 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/django/LICENSE +27 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/LICENSE +222 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/NOTICE +5 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/echarts.min.js +45 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/licenses/LICENSE-d3 +27 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/licenses/LICENSE-tslib +12 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/licenses/LICENSE-zrender +29 -0
- django_newadmin-0.1.0a1/src/newadmin/static/newadmin/vendor/echarts/licenses/NOTICE-tslib +15 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/app_list.html +52 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/auth/user/change_password.html +3 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/base.html +19 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/base_site.html +43 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/change_form.html +3 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/change_list.html +15 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/filter.html +12 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/index.html +108 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/nav_sidebar.html +20 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/admin/object_history.html +3 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/newadmin/dashboard/chart.html +29 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/newadmin/dashboard/editorial.html +48 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/newadmin/dashboard/layout.html +23 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/newadmin/dashboard/metric.html +9 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/registration/password_change_done.html +3 -0
- django_newadmin-0.1.0a1/src/newadmin/templates/registration/password_change_form.html +3 -0
- django_newadmin-0.1.0a1/src/newadmin/templatetags/__init__.py +1 -0
- django_newadmin-0.1.0a1/src/newadmin/templatetags/newadmin.py +74 -0
- django_newadmin-0.1.0a1/tasks/alpha-readiness.md +38 -0
- django_newadmin-0.1.0a1/tasks/plan.md +176 -0
- django_newadmin-0.1.0a1/tasks/rename-newadmin.md +27 -0
- django_newadmin-0.1.0a1/tasks/todo.md +299 -0
- django_newadmin-0.1.0a1/tests/browser/__init__.py +1 -0
- django_newadmin-0.1.0a1/tests/browser/conftest.py +13 -0
- django_newadmin-0.1.0a1/tests/browser/test_accessibility.py +79 -0
- django_newadmin-0.1.0a1/tests/browser/test_actions.py +79 -0
- django_newadmin-0.1.0a1/tests/browser/test_auxiliary.py +137 -0
- django_newadmin-0.1.0a1/tests/browser/test_changelist.py +63 -0
- django_newadmin-0.1.0a1/tests/browser/test_charts.py +103 -0
- django_newadmin-0.1.0a1/tests/browser/test_dashboard.py +52 -0
- django_newadmin-0.1.0a1/tests/browser/test_editorial_dashboard.py +84 -0
- django_newadmin-0.1.0a1/tests/browser/test_extensions.py +56 -0
- django_newadmin-0.1.0a1/tests/browser/test_forms.py +82 -0
- django_newadmin-0.1.0a1/tests/browser/test_glass.py +69 -0
- django_newadmin-0.1.0a1/tests/browser/test_inlines.py +110 -0
- django_newadmin-0.1.0a1/tests/browser/test_relations.py +91 -0
- django_newadmin-0.1.0a1/tests/browser/test_responsive.py +63 -0
- django_newadmin-0.1.0a1/tests/browser/test_shared_theme.py +149 -0
- django_newadmin-0.1.0a1/tests/browser/test_widgets.py +92 -0
- django_newadmin-0.1.0a1/tests/dashboard_fixtures.py +51 -0
- django_newadmin-0.1.0a1/tests/dashboard_urls.py +9 -0
- django_newadmin-0.1.0a1/tests/js/appearance.test.mjs +92 -0
- django_newadmin-0.1.0a1/tests/settings.py +46 -0
- django_newadmin-0.1.0a1/tests/templates/dashboard_charts_probe.html +7 -0
- django_newadmin-0.1.0a1/tests/test_appearance.py +16 -0
- django_newadmin-0.1.0a1/tests/test_authentication.py +45 -0
- django_newadmin-0.1.0a1/tests/test_auxiliary.py +65 -0
- django_newadmin-0.1.0a1/tests/test_changelist.py +127 -0
- django_newadmin-0.1.0a1/tests/test_configuration.py +98 -0
- django_newadmin-0.1.0a1/tests/test_dashboard.py +44 -0
- django_newadmin-0.1.0a1/tests/test_dashboard_provider.py +128 -0
- django_newadmin-0.1.0a1/tests/test_demo_admin.py +69 -0
- django_newadmin-0.1.0a1/tests/test_editorial_dashboard.py +54 -0
- django_newadmin-0.1.0a1/tests/test_extensions.py +177 -0
- django_newadmin-0.1.0a1/tests/test_identity.py +25 -0
- django_newadmin-0.1.0a1/tests/test_navigation.py +43 -0
- django_newadmin-0.1.0a1/tests/test_packaging.py +61 -0
- django_newadmin-0.1.0a1/tests/test_sites.py +39 -0
- django_newadmin-0.1.0a1/tests/test_widgets.py +39 -0
- django_newadmin-0.1.0a1/tests/urls.py +24 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 20
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
python: ['3.13', '3.14']
|
|
19
|
+
django: ['~=6.0.0', '~=6.1.0']
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python }}
|
|
27
|
+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
|
|
28
|
+
with:
|
|
29
|
+
node-version: '24'
|
|
30
|
+
cache: npm
|
|
31
|
+
- run: python -m pip install -e '.[dev]' 'Django${{ matrix.django }}'
|
|
32
|
+
- run: npm ci
|
|
33
|
+
- run: python -m playwright install --with-deps chromium
|
|
34
|
+
- run: python -m ruff check .
|
|
35
|
+
- run: npm run test:js
|
|
36
|
+
- run: python -m pytest -q --junitxml=test-results.xml
|
|
37
|
+
- name: Annotate test failures
|
|
38
|
+
if: ${{ !cancelled() }}
|
|
39
|
+
run: |
|
|
40
|
+
python - <<'PY'
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
from xml.etree import ElementTree
|
|
43
|
+
report = Path('test-results.xml')
|
|
44
|
+
if report.exists():
|
|
45
|
+
for case in ElementTree.parse(report).iter('testcase'):
|
|
46
|
+
for issue in case:
|
|
47
|
+
if issue.tag in ('failure', 'error'):
|
|
48
|
+
message = f"{case.get('classname')}.{case.get('name')}: {(issue.text or '')[-3500:]}"
|
|
49
|
+
message = message.replace('%', '%25').replace('\r', '%0D').replace('\n', '%0A')
|
|
50
|
+
print(f'::error title=pytest::{message}')
|
|
51
|
+
PY
|
|
52
|
+
- run: python demo/manage.py check
|
|
53
|
+
- run: python demo/manage.py makemigrations --check --dry-run
|
|
54
|
+
distribution:
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
timeout-minutes: 15
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
59
|
+
with:
|
|
60
|
+
persist-credentials: false
|
|
61
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
62
|
+
with:
|
|
63
|
+
python-version: '3.14'
|
|
64
|
+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
|
|
65
|
+
with:
|
|
66
|
+
node-version: '24'
|
|
67
|
+
cache: npm
|
|
68
|
+
- run: python -m pip install -e '.[dev,docs]'
|
|
69
|
+
- run: npm ci
|
|
70
|
+
- run: npm audit --audit-level=high
|
|
71
|
+
- name: Rebuild committed assets
|
|
72
|
+
run: |
|
|
73
|
+
npm run build:css
|
|
74
|
+
npm run build:icons
|
|
75
|
+
npm run build:charts
|
|
76
|
+
git diff --exit-code -- src/newadmin/static/
|
|
77
|
+
- run: python -m sphinx -n -W --keep-going -b html docs docs/_build/html
|
|
78
|
+
- run: python -m build
|
|
79
|
+
- run: python -m twine check --strict dist/*
|
|
80
|
+
- name: Install and smoke test the wheel outside the checkout
|
|
81
|
+
run: |
|
|
82
|
+
python -m venv "$RUNNER_TEMP/newadmin-wheel"
|
|
83
|
+
"$RUNNER_TEMP/newadmin-wheel/bin/python" -m pip install dist/*.whl
|
|
84
|
+
"$RUNNER_TEMP/newadmin-wheel/bin/python" scripts/smoke_wheel.py
|
|
85
|
+
- name: Rebuild wheel from sdist
|
|
86
|
+
run: |
|
|
87
|
+
mkdir "$RUNNER_TEMP/newadmin-source"
|
|
88
|
+
tar -xzf dist/*.tar.gz -C "$RUNNER_TEMP/newadmin-source"
|
|
89
|
+
python -m build --wheel "$RUNNER_TEMP/newadmin-source/"* --outdir "$RUNNER_TEMP/newadmin-rebuilt"
|
|
90
|
+
"$RUNNER_TEMP/newadmin-wheel/bin/python" -m pip install --force-reinstall --no-deps "$RUNNER_TEMP/newadmin-rebuilt/"*.whl
|
|
91
|
+
"$RUNNER_TEMP/newadmin-wheel/bin/python" scripts/smoke_wheel.py
|
|
92
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
93
|
+
with:
|
|
94
|
+
name: alpha-distributions
|
|
95
|
+
path: dist/
|
|
96
|
+
if-no-files-found: error
|
|
97
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
98
|
+
with:
|
|
99
|
+
name: sphinx-html
|
|
100
|
+
path: docs/_build/html/
|
|
101
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Django main (informational)
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 8 * * 1'
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
jobs:
|
|
9
|
+
compatibility:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 15
|
|
12
|
+
continue-on-error: true
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
18
|
+
with:
|
|
19
|
+
python-version: '3.14'
|
|
20
|
+
- run: python -m pip install -e '.[dev]'
|
|
21
|
+
- run: python -m pip install --upgrade 'Django @ git+https://github.com/django/django.git@main'
|
|
22
|
+
- run: python -m pytest --ignore=tests/browser -q
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "docs/**"
|
|
8
|
+
- "pyproject.toml"
|
|
9
|
+
- ".github/workflows/docs.yml"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: github-pages
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pages: read
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
27
|
+
with:
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.14"
|
|
32
|
+
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
|
|
33
|
+
- run: python -m pip install '.[docs]'
|
|
34
|
+
- run: python -m sphinx -n -W --keep-going -b html docs docs/_build/html
|
|
35
|
+
- run: touch docs/_build/html/.nojekyll
|
|
36
|
+
- uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
|
|
37
|
+
with:
|
|
38
|
+
path: docs/_build/html
|
|
39
|
+
|
|
40
|
+
deploy:
|
|
41
|
+
environment:
|
|
42
|
+
name: github-pages
|
|
43
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
needs: build
|
|
46
|
+
permissions:
|
|
47
|
+
pages: write
|
|
48
|
+
id-token: write
|
|
49
|
+
steps:
|
|
50
|
+
- name: Deploy to GitHub Pages
|
|
51
|
+
id: deployment
|
|
52
|
+
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.14"
|
|
20
|
+
- run: python -m pip install build twine
|
|
21
|
+
- name: Check release tag matches package version
|
|
22
|
+
env:
|
|
23
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
24
|
+
run: |
|
|
25
|
+
python - <<'PY'
|
|
26
|
+
import ast
|
|
27
|
+
import os
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
module = ast.parse(Path("src/newadmin/__init__.py").read_text())
|
|
31
|
+
version = next(
|
|
32
|
+
ast.literal_eval(node.value)
|
|
33
|
+
for node in module.body
|
|
34
|
+
if isinstance(node, ast.Assign)
|
|
35
|
+
and any(isinstance(target, ast.Name) and target.id == "__version__" for target in node.targets)
|
|
36
|
+
)
|
|
37
|
+
expected_tag = f"v{version}"
|
|
38
|
+
if os.environ["RELEASE_TAG"] != expected_tag:
|
|
39
|
+
raise SystemExit(f"Release tag must be {expected_tag}")
|
|
40
|
+
PY
|
|
41
|
+
- run: python -m build
|
|
42
|
+
- run: python -m twine check --strict dist/*
|
|
43
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
44
|
+
with:
|
|
45
|
+
name: distributions
|
|
46
|
+
path: dist/
|
|
47
|
+
if-no-files-found: error
|
|
48
|
+
|
|
49
|
+
publish:
|
|
50
|
+
needs: build
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
environment:
|
|
53
|
+
name: pypi
|
|
54
|
+
url: https://pypi.org/project/django-newadmin/
|
|
55
|
+
permissions:
|
|
56
|
+
id-token: write
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
59
|
+
with:
|
|
60
|
+
name: distributions
|
|
61
|
+
path: dist/
|
|
62
|
+
- name: Publish to PyPI with Trusted Publishing
|
|
63
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
64
|
+
with:
|
|
65
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Publish to TestPyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
if: github.ref == 'refs/heads/main'
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.14"
|
|
20
|
+
- run: python -m pip install build twine
|
|
21
|
+
- run: python -m build
|
|
22
|
+
- run: python -m twine check --strict dist/*
|
|
23
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
24
|
+
with:
|
|
25
|
+
name: distributions
|
|
26
|
+
path: dist/
|
|
27
|
+
if-no-files-found: error
|
|
28
|
+
|
|
29
|
+
publish:
|
|
30
|
+
needs: build
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
environment:
|
|
33
|
+
name: testpypi
|
|
34
|
+
url: https://test.pypi.org/project/django-newadmin/
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
39
|
+
with:
|
|
40
|
+
name: distributions
|
|
41
|
+
path: dist/
|
|
42
|
+
- name: Publish to TestPyPI with Trusted Publishing
|
|
43
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
44
|
+
with:
|
|
45
|
+
repository-url: https://test.pypi.org/legacy/
|
|
46
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
.pytest_cache/
|
|
3
|
+
.ruff_cache/
|
|
4
|
+
.coverage
|
|
5
|
+
coverage.xml
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
node_modules/
|
|
10
|
+
demo/db.sqlite3
|
|
11
|
+
demo/media/
|
|
12
|
+
*.sqlite3
|
|
13
|
+
staticfiles/
|
|
14
|
+
.env
|
|
15
|
+
.env.*
|
|
16
|
+
*.pem
|
|
17
|
+
.DS_Store
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[cod]
|
|
20
|
+
docs/_build/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0a1 — 2026-10-17 (candidato local)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Tema Bootstrap para el admin nativo: login, navegación, listados, formularios,
|
|
8
|
+
inlines, widgets de relaciones, historial, borrado y páginas de cuenta.
|
|
9
|
+
- Modos claro, oscuro y automático, con acabado de vidrio discreto.
|
|
10
|
+
- Dashboards extensibles en Python y Apache ECharts local, con datos tabulares.
|
|
11
|
+
- Marca, iconos, enlaces con permisos, CSS y configuración por AdminSite.
|
|
12
|
+
- Documentación Sphinx de instalación, configuración y extensiones.
|
|
13
|
+
- Matriz de pruebas Django 6.0/6.1 y Python 3.13/3.14; recursos incluidos en el wheel.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- El encabezado del dashboard se adapta a pantallas estrechas y texto ampliado.
|
|
18
|
+
- Los enlaces de navegación con iconos conservan un nombre accesible explícito.
|
|
19
|
+
|
|
20
|
+
### Limitations
|
|
21
|
+
|
|
22
|
+
- Primera alfa: API y presentación sujetas a cambios; probar antes de producción.
|
|
23
|
+
- Las personalizaciones del consumidor y widgets de terceros requieren validación propia.
|
|
24
|
+
- Las comprobaciones automáticas de accesibilidad no equivalen a certificación WCAG.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Diseño de django-newadmin
|
|
2
|
+
|
|
3
|
+
Fecha: 2026-10-16. Estado: contrato visual propuesto para T01.
|
|
4
|
+
Especificación funcional: [SPEC.md](SPEC.md).
|
|
5
|
+
|
|
6
|
+
Revisión del 2026-10-17: el índice principal adopta la
|
|
7
|
+
[referencia de dashboard](docs/proposals/dashboard-v2.md) y la integración de
|
|
8
|
+
[Apache ECharts](docs/dashboard.md). El marco, la paleta y las acciones se comparten en
|
|
9
|
+
la portada y en los flujos CRUD. Login y popups conservan su disposición compacta.
|
|
10
|
+
|
|
11
|
+
## Dirección
|
|
12
|
+
|
|
13
|
+
Navegación clara, controles del admin nativo y superficies sobrias inspiradas
|
|
14
|
+
en la referencia Apple. La calidad debe apreciarse en listados, errores e inlines,
|
|
15
|
+
no solo en el dashboard. Dar espacio a la tarea y mantener información útil visible.
|
|
16
|
+
|
|
17
|
+
Sin tipografía remota obligatoria, galerías de marketing ni animación decorativa.
|
|
18
|
+
Una paleta inicial, sapphire, con variantes completas light y dark. Otras paletas
|
|
19
|
+
serán adiciones posteriores y deberán cumplir los mismos estados y contrastes.
|
|
20
|
+
|
|
21
|
+
## Tokens de color
|
|
22
|
+
|
|
23
|
+
Todos se publican con prefijo `--newadmin-`. Los valores son colores sólidos;
|
|
24
|
+
los contrastes de texto se miden sobre los fondos indicados.
|
|
25
|
+
|
|
26
|
+
| Token | Light | Dark |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| canvas | #F8F9FF | #11161D |
|
|
29
|
+
| surface | #FFFFFF | #1D2734 |
|
|
30
|
+
| surface-raised | #EFF4FF | #243244 |
|
|
31
|
+
| text | #0B1C30 | #EAF0F8 |
|
|
32
|
+
| text-muted | #536172 | #B2C0D2 |
|
|
33
|
+
| border | #DFE6F0 | #354359 |
|
|
34
|
+
| control-border | #858B93 | #7C8795 |
|
|
35
|
+
| primary | #141A23 | #EAF0F8 |
|
|
36
|
+
| primary-hover | #334259 | #FFFFFF |
|
|
37
|
+
| on-primary | #FFFFFF | #152032 |
|
|
38
|
+
| link | #141A23 | #EAF0F8 |
|
|
39
|
+
| focus | #141A23 | #EAF0F8 |
|
|
40
|
+
| sidebar | #EFF4FF | #161E29 |
|
|
41
|
+
| sidebar-text | #26364B | #DBE6F5 |
|
|
42
|
+
| sidebar-muted | #536172 | #A1B2CA |
|
|
43
|
+
| sidebar-active | #344760 | #A8BCE0 |
|
|
44
|
+
| sidebar-on-active | #FFFFFF | #152032 |
|
|
45
|
+
| success | #166534 | #8FDAA2 |
|
|
46
|
+
| success-bg | #EDF8F0 | #193322 |
|
|
47
|
+
| warning | #7A4B00 | #F4D18C |
|
|
48
|
+
| warning-bg | #FFF8E6 | #362D1E |
|
|
49
|
+
| danger | #B42318 | #FFB4A8 |
|
|
50
|
+
| danger-bg | #FFF2F0 | #3A1F21 |
|
|
51
|
+
| info | #075EA8 | #9ACBFF |
|
|
52
|
+
| info-bg | #EDF6FF | #1B2D40 |
|
|
53
|
+
|
|
54
|
+
Texto normal y texto de controles habilitados: mínimo 4.5:1. Bordes que permiten
|
|
55
|
+
identificar un control y foco respecto a la superficie adyacente: mínimo 3:1.
|
|
56
|
+
El token border es un separador decorativo, no el único límite de un input.
|
|
57
|
+
En navegación oscura, usar un anillo de foco claro que contraste con el fondo;
|
|
58
|
+
sobre una selección primaria, usar un anillo doble con separación.
|
|
59
|
+
Los estados no dependen solo de color: incluir texto, icono o indicación estructural.
|
|
60
|
+
|
|
61
|
+
Mapear estos tokens tanto a variables del admin nativo como a las de Bootstrap.
|
|
62
|
+
No cambiar solamente --bs-primary: botones, enlaces, hover, seleccionado y foco
|
|
63
|
+
deben estar vinculados al mismo sistema y tener sus propios estados.
|
|
64
|
+
|
|
65
|
+
## Tipografía y ritmo
|
|
66
|
+
|
|
67
|
+
- Fuente: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif.
|
|
68
|
+
- Raíz 16 px; contenido administrativo 0.875 rem con line-height 1.5.
|
|
69
|
+
- Formularios móviles: inputs de al menos 1 rem; no deshabilitar zoom.
|
|
70
|
+
- Títulos de página: 1.75 rem/1.2, peso 600; secciones: 1.125 rem/1.4, peso 600.
|
|
71
|
+
- Ayuda: 0.8125 rem/1.5, con contraste de texto normal; no usar gris ilegible.
|
|
72
|
+
- Escala de espacio: 4, 8, 12, 16, 24, 32 y 48 px, expresada en rem.
|
|
73
|
+
- Radios: controles y paneles principales 4 px; widgets auxiliares 6–8 px. Evitar píldoras
|
|
74
|
+
indiscriminadas que hagan botones y estados difíciles de distinguir.
|
|
75
|
+
- Sombra: reservada para menús flotantes y navegación superpuesta; las superficies
|
|
76
|
+
principales se separan con fondo, espacio y bordes.
|
|
77
|
+
|
|
78
|
+
## Estructura y adaptación
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Barra superior: marca / acceso al sitio / usuario / apariencia
|
|
82
|
+
├─ Navegación: inicio, aplicaciones y modelos, enlaces adicionales
|
|
83
|
+
└─ Área de trabajo
|
|
84
|
+
├─ Breadcrumbs y título
|
|
85
|
+
├─ Mensajes y acciones de la página
|
|
86
|
+
├─ Listado, formulario o contenido nativo
|
|
87
|
+
└─ Pie discreto
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- Desde 768 px: lateral de 256 px incluyendo el botón de plegado de 23 px.
|
|
91
|
+
Cabecera de 64 px; se conserva el plegado nativo.
|
|
92
|
+
- Bajo 768 px: se conserva la ocultación nativa del lateral. La navegación móvil
|
|
93
|
+
superpuesta y su gestión de foco siguen pendientes de T15.
|
|
94
|
+
- Bajo 768 px: apilar herramientas y formularios cuando el marcado nativo lo permite.
|
|
95
|
+
- Contenido con padding 32 px en escritorio y 16 px en móvil; ancho fluido.
|
|
96
|
+
- Un scroll vertical principal; el menú puede desplazarse independientemente si
|
|
97
|
+
excede la pantalla. Los popups no incluyen el marco de navegación completo.
|
|
98
|
+
- El documento no se desborda horizontalmente a 320 px. Tablas y widgets anchos
|
|
99
|
+
usan un contenedor de desplazamiento propio con nombre accesible cuando haga falta.
|
|
100
|
+
- Mantener hasta 200% de zoom y comprobar reflow equivalente a 320 CSS px.
|
|
101
|
+
- RTL mediante propiedades lógicas; invertir disposición, no el significado de iconos.
|
|
102
|
+
|
|
103
|
+
### Detalles de vidrio
|
|
104
|
+
|
|
105
|
+
La cabecera y la barra de guardado usan una superficie al 90% con blur de 12 px
|
|
106
|
+
(8 px en móvil), borde fino y reflejo superior. El lienzo incorpora dos variaciones
|
|
107
|
+
estáticas muy suaves de color; tarjetas y métricas añaden sombra discreta. Los
|
|
108
|
+
campos, tablas, paneles y gráficos conservan su fondo sólido y no reciben blur.
|
|
109
|
+
|
|
110
|
+
La base es opaca: `@supports` activa la transparencia y el desenfoque cuando están
|
|
111
|
+
disponibles. `prefers-reduced-transparency: reduce` y colores forzados eliminan
|
|
112
|
+
blur, sombras decorativas y variaciones de fondo. Login y popups conservan su
|
|
113
|
+
presentación compacta. No se añaden dependencias, animaciones ni imágenes remotas.
|
|
114
|
+
|
|
115
|
+
### Marco compartido y portada
|
|
116
|
+
|
|
117
|
+
La plantilla base añade `newadmin-theme` a todas las páginas. El marco compartido
|
|
118
|
+
usa los tokens globales de la tabla anterior; ningún modo depende de una clase
|
|
119
|
+
exclusiva del dashboard. Las variables de Django y Bootstrap se resuelven en el
|
|
120
|
+
mismo ámbito para evitar que botones y widgets hereden la paleta anterior.
|
|
121
|
+
|
|
122
|
+
La cabecera usa la superficie principal, la marca y el lateral usan sidebar.
|
|
123
|
+
El título de la pantalla aparece en la cabecera cuando hay espacio. Login y
|
|
124
|
+
popups reciben los colores globales pero conservan su disposición compacta.
|
|
125
|
+
Las tipografías siguen siendo de sistema y no se solicitan fuentes remotas.
|
|
126
|
+
|
|
127
|
+
Sin proveedor, la portada muestra modelos autorizados y actividad reciente.
|
|
128
|
+
`NEWADMIN.DASHBOARD` permite seleccionar un proveedor Python, su plantilla y Media,
|
|
129
|
+
con permisos verificados antes de preparar datos. La composición de referencia
|
|
130
|
+
expone un grid Bootstrap 8/4 desde 1200 px, con tabla posterior de ancho completo,
|
|
131
|
+
gutters de 32 px y gráfico principal de altura objetivo de 480 px.
|
|
132
|
+
|
|
133
|
+
La demo editorial cuenta entradas por categoría y estado, presenta minigráficos
|
|
134
|
+
con datos de los últimos siete días y ocho entradas recientes. Usa ECharts 6.1.0
|
|
135
|
+
local con su licencia Apache 2.0 y avisos de dependencias. Una instalación genérica
|
|
136
|
+
no hace consultas de negocio ni carga gráficos por omisión. Las tablas alternativas
|
|
137
|
+
son accesibles sin JavaScript. El alcance y uso están en [dashboard.md](docs/dashboard.md).
|
|
138
|
+
|
|
139
|
+
Objetivo pendiente de T15: el panel móvil moverá el foco a su interior y lo mantendrá mientras esté abierto,
|
|
140
|
+
cierra con Escape y devuelve el foco al botón de apertura. Sin JavaScript, el menú
|
|
141
|
+
permanece disponible en el flujo; los enlaces no dependen de hover.
|
|
142
|
+
|
|
143
|
+
## Componentes
|
|
144
|
+
|
|
145
|
+
### Navegación
|
|
146
|
+
|
|
147
|
+
Inicio seguido de aplicaciones con sus modelos y enlaces adicionales. Aplicación
|
|
148
|
+
actual abierta por defecto. Selección con fondo, texto y aria-current=page.
|
|
149
|
+
El botón de plegado informa su función y estado; en modo estrecho los iconos tienen
|
|
150
|
+
nombre accesible y una etiqueta que también aparece al recibir foco.
|
|
151
|
+
|
|
152
|
+
### Listados
|
|
153
|
+
|
|
154
|
+
Tablas reales con encabezados, selección reconocible y ordenación nativa. Filas
|
|
155
|
+
con altura objetivo de 44 px, permitiendo crecer con contenido multilínea.
|
|
156
|
+
Números alineados de forma coherente; URLs y textos largos no estiran el documento.
|
|
157
|
+
Filtros y herramientas mantienen sus valores y parámetros al navegar.
|
|
158
|
+
Un listado vacío explica el estado y muestra alta solo cuando existe permiso.
|
|
159
|
+
|
|
160
|
+
### Formularios
|
|
161
|
+
|
|
162
|
+
Preservar el orden semántico que entrega cada serie de Django. No reordenar con
|
|
163
|
+
CSS el contenido de ayuda y error. Campos relacionados visualmente juntos;
|
|
164
|
+
readonly claramente legible y sin apariencia de input editable.
|
|
165
|
+
Fieldsets plegables conservan details/summary nativos. Botones de guardado en flujo
|
|
166
|
+
normal, con acción principal clara y borrado separado. No usar un footer fijo que
|
|
167
|
+
oculte campos o errores.
|
|
168
|
+
|
|
169
|
+
### Inlines y widgets
|
|
170
|
+
|
|
171
|
+
Presentación consistente para tabulares y apilados. Las nuevas filas heredan los
|
|
172
|
+
estilos sin reinicializar toda la página. Los selectores múltiples, calendarios,
|
|
173
|
+
relojes y Select2 conservan controles, textos e IDs que esperan los scripts de Django.
|
|
174
|
+
Probar superposición y z-index dentro de navegación móvil y ventanas popup.
|
|
175
|
+
|
|
176
|
+
### Mensajes, errores y confirmaciones
|
|
177
|
+
|
|
178
|
+
Mensajes con icono, texto y estilo por nivel, incluyendo info y debug. Errores de
|
|
179
|
+
formulario visibles junto al campo y en el resumen nativo; enlaces/etiquetas
|
|
180
|
+
conservan relaciones accesibles. Confirmaciones de borrado muestran consecuencias,
|
|
181
|
+
objetos protegidos y cancelación con la misma claridad que la acción principal.
|
|
182
|
+
|
|
183
|
+
### Botones y controles
|
|
184
|
+
|
|
185
|
+
Hover, active, focus-visible y disabled definidos en ambos modos. Altura habitual
|
|
186
|
+
36 px para botones y 40 px para inputs; áreas táctiles de 44 px cuando corresponda.
|
|
187
|
+
Controles de icono de al menos 32 × 32 px y nombre accesible. Un control deshabilitado
|
|
188
|
+
no se representa como enlace operativo ni usa solo opacidad para explicar su estado.
|
|
189
|
+
|
|
190
|
+
## Integración CSS y recursos
|
|
191
|
+
|
|
192
|
+
- Conservar base.css y los estilos/widgets nativos necesarios.
|
|
193
|
+
- Extender las plantillas por bloques; overrides completos solo con una razón
|
|
194
|
+
verificable y pruebas para las dos series de Django.
|
|
195
|
+
- No importar Reboot ni utilidades que colisionen con clases nativas sin revisión
|
|
196
|
+
específica; incorporar grid/componentes Bootstrap a los componentes propios.
|
|
197
|
+
- Nunca redefinir globalmente todas las etiquetas input/select/button para imitar
|
|
198
|
+
Bootstrap. Adaptar los selectores del admin dentro de su ámbito.
|
|
199
|
+
- Mantener CUSTOM_CSS al final, incluyendo después de estilos específicos de página;
|
|
200
|
+
probar la cascada real de login, listado y formulario.
|
|
201
|
+
- Preferir los iconos SVG locales del admin donde ya existan. Los iconos de menú
|
|
202
|
+
añadidos usan un subconjunto local de Bootstrap Icons con sus avisos de licencia.
|
|
203
|
+
- Transiciones de 120–180 ms para foco visual, plegado y panel; reducirlas a cero
|
|
204
|
+
con prefers-reduced-motion. No animar cada fila ni la carga del formulario.
|
|
205
|
+
|
|
206
|
+
## Validación del diseño
|
|
207
|
+
|
|
208
|
+
Antes de declarar una pantalla terminada: verificar datos reales extensos, vacío,
|
|
209
|
+
errores, permisos restringidos, foco y los dos modos. Capturas comparables a
|
|
210
|
+
320, 768, 1024 y 1440 px; revisión manual de teclado, RTL y zoom. Los contrastes
|
|
211
|
+
calculados de tokens son evidencia parcial: estados y elementos renderizados
|
|
212
|
+
necesitan validación adicional en navegador.
|
|
213
|
+
|
|
214
|
+
## Verificación documental realizada
|
|
215
|
+
|
|
216
|
+
La auditoría documental de T01 se hizo con la paleta anterior. Sus resultados
|
|
217
|
+
numéricos no certifican los tokens actuales. La comprobación de contraste y foco
|
|
218
|
+
sobre las pantallas renderizadas sigue siendo parte de T15. La regresión del marco
|
|
219
|
+
compartido verifica paleta y geometría entre pantallas, tres modos y reflow a 320 px.
|
|
220
|
+
|
|
221
|
+
## Referencias de intención
|
|
222
|
+
|
|
223
|
+
- [Referencia Apple](https://github.com/VoltAgent/awesome-design-md/blob/main/design-md/apple/DESIGN.md):
|
|
224
|
+
sobriedad del color, tipografía y superficies, adaptadas a trabajo administrativo.
|
|
225
|
+
- [Modos de Bootstrap](https://getbootstrap.com/docs/5.3/customize/color-modes/).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, CARocha and contributors
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
17
|
+
may be used to endorse or promote products derived from this software without
|
|
18
|
+
specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|