diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml new file mode 100644 index 00000000..967f7c8c --- /dev/null +++ b/.github/workflows/test-docs.yml @@ -0,0 +1,22 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + - cron: "0 0 * * *" + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.x + - run: pip install -r requirements/build-docs.txt + - run: mkdocs build --verbose diff --git a/.github/workflows/test.yml b/.github/workflows/test-src.yml similarity index 97% rename from .github/workflows/test.yml rename to .github/workflows/test-src.yml index 2675c040..f5320f35 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test-src.yml @@ -11,7 +11,7 @@ on: - cron: "0 0 * * *" jobs: - test-python-versions: + source: runs-on: ubuntu-latest strategy: matrix: diff --git a/README.md b/README.md index 58f86611..dfee8134 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Any Python web framework with Websockets can support IDOM. See below for what fr -You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out. Within this file, we will create a simple `HelloWorld` component. +You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out. Within this file, we will create a simple `hello_world` component. @@ -34,7 +34,7 @@ You'll need a file to define your [IDOM](https://github.com/idom-team/idom) comp from idom import component, html @component -def HelloWorld(recipient: str): +def hello_world(recipient: str): return html.h1(f"Hello {recipient}!") ``` @@ -46,7 +46,7 @@ def HelloWorld(recipient: str): In your **Django app**'s HTML template, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloWorld` (_in the previous example_) accepts a `recipient` argument. +Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `hello_world` (_in the previous example_) accepts a `recipient` argument. @@ -56,7 +56,7 @@ Additonally, you can pass in keyword arguments into your component function. For - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} ``` diff --git a/docs/features/components.md b/docs/features/components.md index 947a4431..dc697162 100644 --- a/docs/features/components.md +++ b/docs/features/components.md @@ -7,7 +7,7 @@ from idom import component, html from django_idom.components import django_css @component -def MyComponent(): +def my_component(): return html.div( django_css("css/buttons.css"), html.button("My Button!"), @@ -29,7 +29,7 @@ def MyComponent(): from django.templatetags.static import static @component - def MyComponent(): + def my_component(): return html.div( html.link({"rel": "stylesheet", "href": static("css/buttons.css")}), html.button("My Button!"), @@ -46,7 +46,7 @@ def MyComponent(): from idom import component, html @component - def MyComponent(): + def my_component(): return html.div( html.link({"rel": "stylesheet", "href": "https://example.com/external-styles.css"}), html.button("My Button!"), @@ -68,7 +68,7 @@ from idom import component, html from django_idom.components import django_js @component -def MyComponent(): +def my_component(): return html.div( html.button("My Button!"), django_js("js/scripts.js"), @@ -90,7 +90,7 @@ def MyComponent(): from django.templatetags.static import static @component - def MyComponent(): + def my_component(): return html.div( html.script({"src": static("js/scripts.js")}), html.button("My Button!"), @@ -107,7 +107,7 @@ def MyComponent(): from idom import component, html @component - def MyComponent(): + def my_component(): return html.div( html.script({"src": static("https://example.com/external-scripts.js")}), html.button("My Button!"), diff --git a/docs/features/hooks.md b/docs/features/hooks.md index e1cc4d04..7a0d8a99 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -1,5 +1,3 @@ -# Django Hooks - ???+ tip "Looking for more hooks?" Check out the [IDOM Core docs](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html?highlight=hooks) on hooks! @@ -13,13 +11,11 @@ from idom import component, html from django_idom.hooks import use_websocket @component -def MyComponent(): +def my_component(): my_websocket = use_websocket() return html.div(my_websocket) ``` - - ## Use Scope This is a shortcut that returns the Websocket's `scope`. @@ -29,17 +25,16 @@ from idom import component, html from django_idom.hooks import use_scope @component -def MyComponent(): +def my_component(): my_scope = use_scope() return html.div(my_scope) ``` - ## Use Location ??? info "This hook's behavior will be changed in a future update" - This hook will be updated to return the browser's current URL. This will come in alongside our built-in [Single Page Application (SPA) support](https://github.com/idom-team/idom/issues/569). + This hook will be updated to return the browser's current URL. This change will come in alongside [IDOM URL routing support](https://github.com/idom-team/idom/issues/569). This is a shortcut that returns the Websocket's `path`. @@ -48,7 +43,7 @@ from idom import component, html from django_idom.hooks import use_location @component -def MyComponent(): +def my_component(): my_location = use_location() return html.div(my_location) ``` diff --git a/docs/features/settings.md b/docs/features/settings.md new file mode 100644 index 00000000..b003ae3c --- /dev/null +++ b/docs/features/settings.md @@ -0,0 +1,27 @@ +Django IDOM uses your **Django project's** `settings.py` file to modify some behaviors of IDOM. + +Here are the configurable variables that are available. + + + +```python title="settings.py" +# If "idom" cache is not configured, then we'll use "default" instead +CACHES = { +"idom": {"BACKEND": ...}, +} + +# Maximum seconds between two reconnection attempts that would cause the client give up. +# 0 will disable reconnection. +IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 + +# The URL for IDOM to serve websockets +IDOM_WEBSOCKET_URL = "idom/" +``` + + + +??? question "Do I need to modify my settings?" + + The default configuration of IDOM is adequate for the majority of use cases. + + You should only consider changing settings when the necessity arises. diff --git a/docs/features/templatetag.md b/docs/features/templatetag.md index 26a2f4ad..5f917f92 100644 --- a/docs/features/templatetag.md +++ b/docs/features/templatetag.md @@ -14,16 +14,16 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ```python title="views.py" def example_view(): - context_vars = {"DontDoThis": "example_project.my_app.components.HelloWorld"} + context_vars = {"dont_do_this": "example_project.my_app.components.hello_world"} return render(request, "my-template.html", context_vars) ``` ```jinja title="my-template.html" - {% component DontDoThis recipient="World" %} + {% component dont_do_this recipient="World" %} - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} ``` @@ -38,7 +38,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ```jinja title="my-template.html" ... - {% component "example.components.MyComponent" class="my-html-class" key=123 %} + {% component "example.components.my_component" class="my-html-class" key=123 %} ... ``` @@ -54,15 +54,17 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} - {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %} -
{% component "example_project.my_app_3.components.SimpleComponent" %}
+ {% component "example_project.my_app.components.hello_world" recipient="World" %} + {% component "example_project.my_app_2.components.class_component" class="bold small-font" %} +
{% component "example_project.my_app_3.components.simple_component" %}
``` But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your `#!html ` tag. + Additionally, the components in the example above will not be able to interact with each other, except through database queries. + diff --git a/docs/installation/index.md b/docs/installation/index.md index a2a6e391..e0cdfc1e 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -43,19 +43,7 @@ INSTALLED_APPS = [ Below are a handful of values you can change within `settings.py` to modify the behavior of IDOM. - ```python title="settings.py" - # If "idom" cache is not configured, then we'll use "default" instead - CACHES = { - "idom": {"BACKEND": ...}, - } - - # Maximum seconds between two reconnection attempts that would cause the client give up. - # 0 will disable reconnection. - IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 - - # The URL for IDOM to serve websockets - IDOM_WEBSOCKET_URL = "idom/" - ``` + {% include-markdown "../features/settings.md" start="" end="" %} --- diff --git a/mkdocs.yml b/mkdocs.yml index 50cef329..9cf9d38b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,7 @@ nav: - Components: features/components.md - Hooks: features/hooks.md - Template Tag: features/templatetag.md + - Settings: features/settings.md - Contribute: - Code: contribute/django-idom.md - Docs: contribute/docs.md @@ -24,14 +25,14 @@ theme: - media: "(prefers-color-scheme: dark)" scheme: slate toggle: - icon: material/toggle-switch + icon: material/white-balance-sunny name: Switch to light mode primary: deep-orange accent: orange - media: "(prefers-color-scheme: light)" scheme: default toggle: - icon: material/toggle-switch-off-outline + icon: material/weather-night name: Switch to dark mode primary: black features: diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index 7b8f3610..5e6b7ced 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -26,7 +26,7 @@ def component(_component_id_, **kwargs): - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} """ diff --git a/tests/test_app/components.py b/tests/test_app/components.py index 687bfea2..a2491c17 100644 --- a/tests/test_app/components.py +++ b/tests/test_app/components.py @@ -4,12 +4,12 @@ @idom.component -def HelloWorld(): +def hello_world(): return idom.html.h1({"id": "hello-world"}, "Hello World!") @idom.component -def Button(): +def button(): count, set_count = idom.hooks.use_state(0) return idom.html.div( idom.html.button( @@ -24,7 +24,7 @@ def Button(): @idom.component -def ParametrizedComponent(x, y): +def parameterized_component(x, y): total = x + y return idom.html.h1({"id": "parametrized-component", "data-value": total}, total) @@ -34,64 +34,64 @@ def ParametrizedComponent(x, y): @idom.component -def SimpleBarChart(): +def simple_bar_chart(): return VictoryBar() @idom.component -def UseWebsocket(): +def use_websocket(): ws = django_idom.hooks.use_websocket() ws.scope = "..." success = bool(ws.scope and ws.close and ws.disconnect and ws.view_id) return idom.html.div( {"id": "use-websocket", "data-success": success}, idom.html.hr(), - f"UseWebsocket: {ws}", + f"use_websocket: {ws}", idom.html.hr(), ) @idom.component -def UseScope(): +def use_scope(): scope = django_idom.hooks.use_scope() success = len(scope) >= 10 and scope["type"] == "websocket" return idom.html.div( {"id": "use-scope", "data-success": success}, - f"UseScope: {scope}", + f"use_scope: {scope}", idom.html.hr(), ) @idom.component -def UseLocation(): +def use_location(): location = django_idom.hooks.use_location() success = bool(location) return idom.html.div( {"id": "use-location", "data-success": success}, - f"UseLocation: {location}", + f"use_location: {location}", idom.html.hr(), ) @idom.component -def StaticCSS(): +def django_css(): return idom.html.div( - {"id": "static-css"}, - django_idom.components.django_css("static-css-test.css"), - idom.html.div({"style": {"display": "inline"}}, "StaticCSS: "), + {"id": "django-css"}, + django_idom.components.django_css("django-css-test.css"), + idom.html.div({"style": {"display": "inline"}}, "django_css: "), idom.html.button("This text should be blue."), idom.html.hr(), ) @idom.component -def StaticJS(): +def django_js(): success = False return idom.html._( idom.html.div( - {"id": "static-js", "data-success": success}, - f"StaticJS: {success}", - django_idom.components.django_js("static-js-test.js"), + {"id": "django-js", "data-success": success}, + f"django_js: {success}", + django_idom.components.django_js("django-js-test.js"), ), idom.html.hr(), ) diff --git a/tests/test_app/static/static-css-test.css b/tests/test_app/static/django-css-test.css similarity index 61% rename from tests/test_app/static/static-css-test.css rename to tests/test_app/static/django-css-test.css index d5565d70..af68e6ed 100644 --- a/tests/test_app/static/static-css-test.css +++ b/tests/test_app/static/django-css-test.css @@ -1,3 +1,3 @@ -#static-css button { +#django-css button { color: rgba(0, 0, 255, 1); } diff --git a/tests/test_app/static/django-js-test.js b/tests/test_app/static/django-js-test.js new file mode 100644 index 00000000..1d59eb31 --- /dev/null +++ b/tests/test_app/static/django-js-test.js @@ -0,0 +1,3 @@ +let el = document.body.querySelector("#django-js"); +el.textContent = "django_js: True"; +el.dataset.success = "true"; diff --git a/tests/test_app/static/static-js-test.js b/tests/test_app/static/static-js-test.js deleted file mode 100644 index b4423acf..00000000 --- a/tests/test_app/static/static-js-test.js +++ /dev/null @@ -1,3 +0,0 @@ -let el = document.body.querySelector("#static-js"); -el.textContent = "StaticJS: True"; -el.dataset.success = "true"; diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index c597cdf9..e6960c14 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -12,15 +12,15 @@

IDOM Test Page

-
{% component "test_app.components.HelloWorld" class="hello-world" %}
-
{% component "test_app.components.Button" class="button" %}
-
{% component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}
-
{% component "test_app.components.SimpleBarChart" %}
-
{% component "test_app.components.UseWebsocket" %}
-
{% component "test_app.components.UseScope" %}
-
{% component "test_app.components.UseLocation" %}
-
{% component "test_app.components.StaticCSS" %}
-
{% component "test_app.components.StaticJS" %}
+
{% component "test_app.components.hello_world" class="hello-world" %}
+
{% component "test_app.components.button" class="button" %}
+
{% component "test_app.components.parameterized_component" class="parametarized-component" x=123 y=456 %}
+
{% component "test_app.components.simple_bar_chart" %}
+
{% component "test_app.components.use_websocket" %}
+
{% component "test_app.components.use_scope" %}
+
{% component "test_app.components.use_location" %}
+
{% component "test_app.components.django_css" %}
+
{% component "test_app.components.django_js" %}
diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py index 33a8c6e8..8ed89efa 100644 --- a/tests/test_app/tests/test_components.py +++ b/tests/test_app/tests/test_components.py @@ -60,13 +60,13 @@ def test_use_location(self): self.assertEqual(element.get_attribute("data-success"), "true") def test_static_css(self): - element = self.driver.find_element_by_css_selector("#static-css button") + element = self.driver.find_element_by_css_selector("#django-css button") self.assertEqual( element.value_of_css_property("color"), "rgba(0, 0, 255, 1)" ) def test_static_js(self): - element = self.driver.find_element_by_id("static-js") + element = self.driver.find_element_by_id("django-js") self.assertEqual(element.get_attribute("data-success"), "true")