Merge pull request #420 from GabDug/docs/init

docs: add mkdocs
This commit is contained in:
Emil Stenström 2024-08-24 11:37:06 +02:00 committed by GitHub
commit a8a3828076
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 626 additions and 20 deletions

70
.github/workflows/docs.yml vendored Normal file
View file

@ -0,0 +1,70 @@
---
name: Test and Deploy Docs
on:
push:
# XXX Commented-out for testing
# branches: [master]
workflow_dispatch:
inputs:
ref:
description: "The commit SHA, tag, or branch to publish. Uses the default branch if not specified."
default: ""
type: string
release:
types: [published]
jobs:
docs:
runs-on: ubuntu-latest
# XXX Enable to avoid forks deploying
# if: github.ref == 'refs/heads/main' && github.repository_owner == 'EmilStenstrom'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Hatch
run: |
python -m pip install --upgrade pip wheel
python -m pip install -q hatch pre-commit
hatch --version
- name: Create Virtual Environment
run: hatch env create docs
- name: "Check for mkdocs build --strict"
# XXX Enable strict mode once docs are clean
run: |
hatch run docs:build # --strict
# If pull request or not master branch and not a tag
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.event_name == 'workflow_dispatch'
- name: Configure git
run: |
git config user.name github-actions
git config user.email github-actions@github.com
- name: Deploy docs (dev)
if: github.event_name == 'push' && github.ref_type == 'branch'
# XXX Set to master only after testing
# if: github.event_name == 'push' && github.ref_name == 'master' && github.ref_type == 'branch'
run: |
export SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
hatch run docs:mike deploy dev --update-aliases --title "dev (${SHORT_SHA})" --push
- name: Deploy docs (tag)
if: github.ref_type == 'tag' && github.event_name == 'push'
run: |
hatch run docs:mike deploy ${{ github.ref_name }} latest --push --update-aliases
hatch run docs:mike set-default latest --push
- name: Deploy docs (Released published)
if: github.event_name == 'release' && github.event.action == 'published' && github.ref_type == 'tag'
run: |
# Version from tag, keep leading v, from github.ref workflow variable
hatch run docs:mike deploy ${{ github.ref_name }} latest --push --update-aliases
hatch run docs:mike set-default latest --push

2
.gitignore vendored
View file

@ -72,3 +72,5 @@ poetry.lock
.venv/
.DS_Store
.python-version
site
docs/reference

View file

@ -1,11 +1,26 @@
# <img src="logo/logo-black-on-white.svg" alt="django-components" style="max-width: 100%; background: white; color: black;">
# <img src="https://raw.githubusercontent.com/EmilStenstrom/django-components/master/logo/logo-black-on-white.svg" alt="django-components" style="max-width: 100%; background: white; color: black;">
<a href="https://github.com/EmilStenstrom/django-components/actions?query=workflow%3A%22Run+tests%22"><img align="right" src="https://github.com/EmilStenstrom/django-components/workflows/Run%20tests/badge.svg" alt="Show test status"></a>
<a href="https://pepy.tech/project/django-components"><img align="right" src="https://pepy.tech/badge/django-components" alt="Show download stats"></a>
[![PyPI - Version](https://img.shields.io/pypi/v/django-components)](https://pypi.org/project/django-components/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-components)](https://pypi.org/project/django-components/) [![PyPI - License](https://img.shields.io/pypi/l/django-components)](https://EmilStenstrom.github.io/django-components/latest/license/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/django-components)](https://pypistats.org/packages/django-components) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/EmilStenstrom/django-components/tests.yml)](https://github.com/EmilStenstrom/django-components/actions/workflows/tests.yml)
A way to create simple reusable template components in Django.
[**Docs (Work in progress)**](https://EmilStenstrom.github.io/django-components/latest/)
It lets you create "template components", that contains both the template, the Javascript and the CSS needed to generate the front end code you need for a modern app. Components look like this:
Create simple reusable template components in Django
## Features
<!-- FIXME Links -->
- ✨ **Reusable components**: Create components that can be reused in different parts of your project, or even in different projects.
- 📁 **Single file components**: Keep your Python, CSS, Javascript and HTML in one place (if you wish)
- 🎰 **Slots**: Define slots in your components to make them more flexible.
- 💻 **CLI**: A command line interface to help you create new components.
- 🚀 **Wide compatibility**: Works with [modern and LTS versions of Django](https://emilstenstrom.github.io/django-components/latest/user_guide/requirements_compatibility).
- **Load assets**: Automatically load the right CSS and Javascript files for your components, with [our middleware](https://emilstenstrom.github.io/django-components/latest/user_guide/creating_using_components/middleware).
## Summary
It lets you create "template components", that contains both the template, the Javascript and the CSS needed to generate the front end code you need for a modern app. Use components like this:
```htmldjango
{% component "calendar" date="2015-06-19" %}{% endcomponent %}
@ -24,7 +39,7 @@ And this is what gets rendered (plus the CSS and Javascript you've specified):
- [Release notes](#release-notes)
- [Security notes 🚨](#security-notes-)
- [Installation](#installation)
- [Compatiblity](#compatiblity)
- [Compatibility](#compatibility)
- [Create your first component](#create-your-first-component)
- [Using single-file components](#using-single-file-components)
- [Use components in templates](#use-components-in-templates)
@ -49,7 +64,7 @@ And this is what gets rendered (plus the CSS and Javascript you've specified):
## Release notes
🚨📢 **Version 0.92**
🚨📢 **Version 0.92**
- BREAKING CHANGE: `Component` class is no longer a subclass of `View`. To configure the `View` class, set the `Component.View` nested class. HTTP methods like `get` or `post` can still be defined directly on `Component` class, and `Component.as_view()` internally calls `Component.View.as_view()`. (See [Modifying the View class](#modifying-the-view-class))
- The inputs (args, kwargs, slots, context, ...) that you pass to `Component.render()` can be accessed from within `get_context_data`, `get_template_string` and `get_template_name` via `self.input`. (See [Accessing data passed to the component](#accessing-data-passed-to-the-component))
@ -262,7 +277,7 @@ TEMPLATES = [
Read on to find out how to build your first component!
## Compatiblity
## Compatibility
Django-components supports all supported combinations versions of [Django](https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django) and [Python](https://devguide.python.org/versions/#versions).
@ -294,9 +309,9 @@ A component in django-components is the combination of four things: CSS, Javascr
Start by creating empty files in the structure above.
First you need a CSS file. Be sure to prefix all rules with a unique class so they don't clash with other rules.
First, you need a CSS file. Be sure to prefix all rules with a unique class so they don't clash with other rules.
```css
```css title="[project root]/components/calendar/style.css"
/* In a file called [project root]/components/calendar/style.css */
.calendar-component {
width: 200px;
@ -309,7 +324,7 @@ First you need a CSS file. Be sure to prefix all rules with a unique class so th
Then you need a javascript file that specifies how you interact with this component. You are free to use any javascript framework you want. A good way to make sure this component doesn't clash with other components is to define all code inside an anonymous function that calls itself. This makes all variables defined only be defined inside this component and not affect other components.
```js
```js title="[project root]/components/calendar/script.js"
/* In a file called [project root]/components/calendar/script.js */
(function () {
if (document.querySelector(".calendar-component")) {
@ -322,7 +337,7 @@ Then you need a javascript file that specifies how you interact with this compon
Now you need a Django template for your component. Feel free to define more variables like `date` in this example. When creating an instance of this component we will send in the values for these variables. The template will be rendered with whatever template backend you've specified in your Django settings file.
```htmldjango
```htmldjango title="[project root]/components/calendar/calendar.html"
{# In a file called [project root]/components/calendar/template.html #}
<div class="calendar-component">Today's date is <span>{{ date }}</span></div>
```
@ -331,7 +346,7 @@ Finally, we use django-components to tie this together. Start by creating a file
Inside this file we create a Component by inheriting from the Component class and specifying the context method. We also register the global component registry so that we easily can render it anywhere in our templates.
```python
```python title="[project root]/components/calendar/calendar.py"
# In a file called [project root]/components/calendar/calendar.py
from django_components import Component, register
@ -362,7 +377,7 @@ And voilá!! We've created our first component.
Components can also be defined in a single file, which is useful for small components. To do this, you can use the `template`, `js`, and `css` class attributes instead of the `template_name` and `Media`. For example, here's the calendar component from above, defined in a single file:
```python
```python title="[project root]/components/calendar.py"
# In a file called [project root]/components/calendar.py
from django_components import Component, register, types
@ -598,7 +613,7 @@ MyComponent.render_to_response(
### Adding type hints with Generics
The `Component` class optionally accepts type parameters
that allow you to specify the types of args, kwargs, slots, and
that allow you to specify the types of args, kwargs, slots, and
data.
```py
@ -786,7 +801,7 @@ class ComponentView(View):
def post(self, request, *args, **kwargs):
return self.component.post(request, *args, **kwargs)
...
```
@ -2842,4 +2857,4 @@ To display individual components, add them to the `urls.py`, like in the case of
## Development guides
- [Slot rendering flot](https://github.com/EmilStenstrom/django-components/blob/master/docs/slot_rendering.md)
- [Slot rendering flot](https://github.com/EmilStenstrom/django-components/blob/master/docs/slot_rendering.md)

13
docs/CHANGELOG.md Normal file
View file

@ -0,0 +1,13 @@
---
hide:
- toc
---
# Release notes
{!
include-markdown "../README.md"
start="## Release notes"
end='## '
heading-offset=1
!}

1
docs/CODE_OF_CONDUCT.md Normal file
View file

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

1
docs/README.md Normal file
View file

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

6
docs/SUMMARY.md Normal file
View file

@ -0,0 +1,6 @@
* [README](README.md)
* [Changelog](CHANGELOG.md)
* [Code of Conduct](CODE_OF_CONDUCT.md)
* [License](license.md)
* Reference
* [API Reference](reference/)

3
docs/license.md Normal file
View file

@ -0,0 +1,3 @@
# License
--8<-- "LICENSE"

5
docs/overrides/main.html Normal file
View file

@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block announce %}
🚨The documentation is still a work in progress. 🚨
{% endblock %}

186
mkdocs.yml Normal file
View file

@ -0,0 +1,186 @@
---
site_name: Django-Components
site_description: A way to create simple reusable template components in Django.
site_url: https://emilstenstrom.github.io/django-components/
repo_url: https://github.com/EmilStenstrom/django-components
repo_name: EmilStenstrom/django-components
edit_uri: https://github.com/EmilStenstrom/django-components/edit/master/docs/
dev_addr: "127.0.0.1:9000"
site_dir: site
docs_dir: docs
watch:
- src
- docs
- mkdocs.yml
- README.md
- scripts
validation:
# We get warnings as we use literate-nav
omitted_files: ignore
absolute_links: warn
unrecognized_links: info
theme:
name: "material"
custom_dir: docs/overrides
features:
- content.action.edit
- content.action.view
- content.code.annotate
- content.code.copy
- content.tabs.link
- navigation.expand
- navigation.footer
- navigation.instant
- navigation.instant.progress
- navigation.indexes
- navigation.sections
- navigation.tracking
- navigation.top
- search.highlight
- search.share
- search.suggest
- toc.follow
icon:
repo: fontawesome/brands/github
palette:
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
toggle:
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: teal
toggle:
icon: material/weather-sunny
name: Switch to light mode
extra:
version:
provider: mike
default:
- latest
- dev
social:
- icon: fontawesome/brands/github
link: https://github.com/EmilStenstrom/django-components
- icon: fontawesome/brands/python
link: https://pypi.org/project/django-components/
markdown_extensions:
abbr: {}
admonition: {}
attr_list: {}
codehilite: {}
def_list: {}
tables: {}
md_in_html: {}
# mdx_truly_sane_lists: {}
pymdownx.magiclink:
repo_url_shorthand: true
user: EmilStenstrom
repo: django-components
pymdownx.details: {}
pymdownx.highlight:
anchor_linenums: true
pymdownx.inlinehilite: {}
pymdownx.snippets:
check_paths: true
base_path: .
pymdownx.tabbed:
alternate_style: true
pymdownx.superfences:
pymdownx.tasklist:
custom_checkbox: true
pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
toc:
permalink: "¤"
plugins:
- autorefs
- include-markdown:
# Default is django style...
opening_tag: "{!"
closing_tag: "!}"
- gen-files:
scripts:
- scripts/gen_ref_nav.py
- literate-nav:
nav_file: SUMMARY.md
tab_length: 2
- git-revision-date-localized:
enabled: !ENV [CI, false]
type: timeago
exclude:
- reference/*
- changelog.md
- code_of_conduct.md
- license.md
- git-authors:
enabled: !ENV [CI, false]
exclude:
- reference/*
- changelog.md
- code_of_conduct.md
- license.md
- markdown-exec
# - toc-md:
- search
- social:
enabled: !ENV [CI, false]
- mike:
canonical_version: "latest"
version_selector: true
- redirects:
redirect_maps:
- minify:
minify_html: true
- mkdocstrings:
handlers:
python:
import:
- https://docs.python.org/3.12/objects.inv
- url: https://docs.djangoproject.com/en/5.0/_objects/
base_url: https://docs.djangoproject.com/en/5.0/
domains: [std, py]
paths: [src] # search packages in the src folder
options:
docstring_options:
ignore_init_summary: true
docstring_section_style: list
filters: ["!^_"]
heading_level: 1
inherited_members: true
merge_init_into_class: true
preload_modules: [mkdocstrings]
separate_signature: true
show_root_heading: true
show_root_full_path: false
show_signature_annotations: true
show_symbol_type_heading: true
show_symbol_type_toc: true
signature_crossrefs: true
summary: true
unwrap_annotated: true
# show_root_heading: true
# show_signature_annotations: true
show_if_no_docstring: false
# separate_signature: true
line_length: 140
# merge_init_into_class: true
show_submodules: true
docstring_style: google
# docstring_options:
# ignore_init_summary: true

View file

@ -97,3 +97,37 @@ disallow_untyped_defs = true
testpaths = [
"tests"
]
[tool.hatch.env]
requires = [
"hatch-mkdocs",
"hatch-pip-compile"
]
[tool.hatch.envs.default]
dependencies = [
"django",
"tox",
"pytest",
"flake8",
"flake8-pyproject",
"isort",
"pre-commit",
"black",
"mypy",
]
type = "pip-compile"
lock-filename = "requirements-dev.txt"
[tool.hatch.envs.docs]
type = "pip-compile"
lock-filename = "requirements-docs.txt"
detached = false
# Dependencies are fetched automatically from the mkdocs.yml file with hatch-mkdocs
# We only add black for formatting code in the docs
dependencies = [
"black",
]
[tool.hatch.env.collectors.mkdocs.docs]
path = "mkdocs.yml"

219
requirements-docs.txt Normal file
View file

@ -0,0 +1,219 @@
#
# This file is autogenerated by hatch-pip-compile with Python 3.12
#
# - markdown-exec
# - mike
# - mkdocs
# - mkdocs-autorefs
# - mkdocs-gen-files
# - mkdocs-git-authors-plugin
# - mkdocs-git-revision-date-localized-plugin
# - mkdocs-include-markdown-plugin
# - mkdocs-literate-nav
# - mkdocs-material
# - mkdocs-material[imaging]
# - mkdocs-minify-plugin
# - mkdocs-redirects
# - mkdocstrings
# - mkdocstrings-python
# - pymdown-extensions
# - black
# - django>=4.2
#
asgiref==3.8.1
# via django
babel==2.14.0
# via
# mkdocs-git-revision-date-localized-plugin
# mkdocs-material
black==24.3.0
# via hatch.envs.docs
bracex==2.4
# via wcmatch
cairocffi==1.6.1
# via cairosvg
cairosvg==2.7.1
# via mkdocs-material
certifi==2024.2.2
# via requests
cffi==1.16.0
# via cairocffi
charset-normalizer==3.3.2
# via requests
click==8.1.7
# via
# black
# mkdocs
# mkdocstrings
colorama==0.4.6
# via
# griffe
# mkdocs-material
csscompressor==0.9.5
# via mkdocs-minify-plugin
cssselect2==0.7.0
# via cairosvg
defusedxml==0.7.1
# via cairosvg
django==5.0.3
# via hatch.envs.docs
ghp-import==2.1.0
# via mkdocs
gitdb==4.0.11
# via gitpython
gitpython==3.1.43
# via mkdocs-git-revision-date-localized-plugin
griffe==0.42.1
# via mkdocstrings-python
htmlmin2==0.1.13
# via mkdocs-minify-plugin
idna==3.6
# via requests
importlib-metadata==7.1.0
# via mike
importlib-resources==6.4.0
# via mike
jinja2==3.1.3
# via
# mike
# mkdocs
# mkdocs-material
# mkdocstrings
jsmin==3.0.1
# via mkdocs-minify-plugin
markdown==3.5.2
# via
# mkdocs
# mkdocs-autorefs
# mkdocs-material
# mkdocstrings
# mkdocstrings-python
# pymdown-extensions
markdown-exec==1.8.0
# via hatch.envs.docs
markupsafe==2.1.5
# via
# jinja2
# mkdocs
# mkdocs-autorefs
# mkdocstrings
mergedeep==1.3.4
# via mkdocs
mike==2.0.0
# via hatch.envs.docs
mkdocs==1.5.3
# via
# hatch.envs.docs
# mike
# mkdocs-autorefs
# mkdocs-gen-files
# mkdocs-git-authors-plugin
# mkdocs-git-revision-date-localized-plugin
# mkdocs-include-markdown-plugin
# mkdocs-literate-nav
# mkdocs-material
# mkdocs-minify-plugin
# mkdocs-redirects
# mkdocstrings
mkdocs-autorefs==1.0.1
# via
# hatch.envs.docs
# mkdocstrings
mkdocs-gen-files==0.5.0
# via hatch.envs.docs
mkdocs-git-authors-plugin==0.8.0
# via hatch.envs.docs
mkdocs-git-revision-date-localized-plugin==1.2.4
# via hatch.envs.docs
mkdocs-include-markdown-plugin==6.0.5
# via hatch.envs.docs
mkdocs-literate-nav==0.6.1
# via hatch.envs.docs
mkdocs-material==9.5.16
# via hatch.envs.docs
mkdocs-material-extensions==1.3.1
# via mkdocs-material
mkdocs-minify-plugin==0.8.0
# via hatch.envs.docs
mkdocs-redirects==1.2.1
# via hatch.envs.docs
mkdocstrings==0.24.1
# via
# hatch.envs.docs
# mkdocstrings-python
mkdocstrings-python==1.9.0
# via hatch.envs.docs
mypy-extensions==1.0.0
# via black
packaging==24.0
# via
# black
# mkdocs
paginate==0.5.6
# via mkdocs-material
pathspec==0.12.1
# via
# black
# mkdocs
pillow==10.3.0
# via
# cairosvg
# mkdocs-material
platformdirs==4.2.0
# via
# black
# mkdocs
# mkdocstrings
pycparser==2.22
# via cffi
pygments==2.17.2
# via mkdocs-material
pymdown-extensions==10.7.1
# via
# hatch.envs.docs
# markdown-exec
# mkdocs-material
# mkdocstrings
pyparsing==3.1.2
# via mike
python-dateutil==2.9.0.post0
# via ghp-import
pytz==2024.1
# via mkdocs-git-revision-date-localized-plugin
pyyaml==6.0.1
# via
# mike
# mkdocs
# pymdown-extensions
# pyyaml-env-tag
pyyaml-env-tag==0.1
# via mkdocs
regex==2022.10.31
# via mkdocs-material
requests==2.31.0
# via mkdocs-material
six==1.16.0
# via python-dateutil
smmap==5.0.1
# via gitdb
sqlparse==0.4.4
# via django
tinycss2==1.2.1
# via
# cairosvg
# cssselect2
urllib3==2.2.1
# via requests
verspec==0.1.0
# via mike
watchdog==4.0.0
# via mkdocs
wcmatch==8.5.1
# via mkdocs-include-markdown-plugin
webencodings==0.5.1
# via
# cssselect2
# tinycss2
zipp==3.18.1
# via importlib-metadata

47
scripts/gen_ref_nav.py Normal file
View file

@ -0,0 +1,47 @@
# Adapted from https://github.com/mkdocstrings/python/blob/main/scripts/gen_ref_nav.py
# License: ISC License - Copyright (c) 2021, Timothée Mazzucotelli
"""Generate the code reference pages and navigation.
No need to run this script manually, it is called by mkdocs-material during the build process.
You can run it manually to test the output.
"""
from pathlib import Path
import mkdocs_gen_files
nav = mkdocs_gen_files.Nav()
mod_symbol = '<code class="doc-symbol doc-symbol-nav doc-symbol-module"></code>'
root = Path(__file__).parent.parent
src = root / "src"
for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
if module_path.parts[-1] == "__init__":
module_path = module_path.parent
doc_path = path.relative_to(src).with_suffix("")
if doc_path.parts[-1] == "__init__":
doc_path = doc_path.parent
full_doc_path = Path("reference", doc_path)
parts = tuple(module_path.parts)
doc_path = doc_path / "index.md"
full_doc_path = full_doc_path / "index.md"
nav_parts = [f"{mod_symbol} {part}" for part in parts]
nav[tuple(nav_parts)] = doc_path.as_posix()
if parts[-1] == "__init__":
parts = parts[:-1]
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
fd.write(f"::: {ident}")
mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path.relative_to(root))
with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file:
nav_file.writelines([line.replace(" ", " ").removeprefix(" ") for line in nav.build_literate_nav(indentation=2)])

View file

@ -1,4 +1,6 @@
# flake8: noqa F401
"""Main package for Django Components."""
import django
# Public API

View file

@ -195,10 +195,10 @@ def fill(parser: Parser, token: Token) -> FillNode:
def component(parser: Parser, token: Token, tag_name: str) -> ComponentNode:
"""
To give the component access to the template context:
{% component "name" positional_arg keyword_arg=value ... %}
```#!htmldjango {% component "name" positional_arg keyword_arg=value ... %}```
To render the component in an isolated context:
{% component "name" positional_arg keyword_arg=value ... only %}
```#!htmldjango {% component "name" positional_arg keyword_arg=value ... only %}```
Positional and keyword arguments can be literals or template variables.
The component name must be a single- or double-quotes string and must
@ -306,7 +306,7 @@ def html_attrs(parser: Parser, token: Token) -> HtmlAttrsNode:
will result in `class="my-class extra-class".
Example:
```django
```htmldjango
{% html_attrs attrs defaults:class="default-class" class="extra-class" data-id="123" %}
```
"""

View file

@ -1,3 +1,5 @@
"""Helper types for IDEs."""
import typing
from typing import Any