Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTMX loading styles and related documentation in styleguide #35419

Merged
merged 5 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
@import "commcarehq/form_steps";
@import "commcarehq/helpbubble";
@import "commcarehq/hubspot";
@import "commcarehq/htmx";
@import "commcarehq/icons";
@import "commcarehq/inline_edit";
@import "commcarehq/label";
Expand Down
72 changes: 72 additions & 0 deletions corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_htmx.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@mixin htmx-spinner($width) {
position: absolute;
height: $width;
width: $width;
$offset: $width / 2;
left: calc(50% - $offset);
top: calc(50% - $offset);
}

form.htmx-request {
button[type="submit"] {
position: relative;
&::before {
content: " ";
@extend .spinner-border;
@extend .spinner-border-sm;
@include htmx-spinner(22px);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the various px sizing is this going to look right if it gets used on alternate sized inputs e.g. btn-sm or btn-lg? Not that we do it often, just wondering out loud.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Evan, we asked Biyeun in group review, there is htmx-spinner(18px) for btn-sm. Otherwise, it will always be htmx-spinner(22px). The way the mixin is constructed only accept px, due to the usage of calc.

}
&.btn-sm::before {
@include htmx-spinner(18px);
}
}
.input-group button[type="submit"]::before {
vertical-align: -0.28em;
}
}

.htmx-request.page-link {
background-color: $blue-300;
color: $white;
position: relative;

&::after {
content: " ";
@extend .spinner-border;
@extend .spinner-border-sm;
@include htmx-spinner(22px);
}
}

.htmx-request[type="checkbox"] {
position: relative;

&::after {
content: " ";
color: $blue-400;
@extend .spinner-border;
@extend .spinner-border-sm;
@include htmx-spinner(22px);
}
}

.htmx-request.form-check-input {
&::after {
@include htmx-spinner(30px);
}
}

button.htmx-request {
position: relative;
&::before {
content: " ";
@extend .spinner-border;
@extend .spinner-border-sm;
@include htmx-spinner(22px);
opacity: .5;
}

&.btn-sm::before {
@include htmx-spinner(18px);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
+++
@@ -1,44 +1,95 @@
@@ -1,44 +1,96 @@
-@import "_hq/includes/variables.less";
-@import "_hq/includes/mixins.less";

Expand Down Expand Up @@ -123,6 +123,7 @@
+@import "commcarehq/form_steps";
+@import "commcarehq/helpbubble";
+@import "commcarehq/hubspot";
+@import "commcarehq/htmx";
+@import "commcarehq/icons";
+@import "commcarehq/inline_edit";
+@import "commcarehq/label";
Expand Down
1 change: 1 addition & 0 deletions corehq/apps/styleguide/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
CrispyFormsDemo = namedtuple('CrispyFormsDemo', 'form code')
CrispyFormsWithJsDemo = namedtuple('CrispyFormsWithJsDemo', 'form code_python code_js')
CodeForDisplay = namedtuple('CodeForDisplay', 'code language')
CodeForDisplayWithPartial = namedtuple('CodeForDisplayWithPartial', 'code language partial')
ThemeColor = namedtuple('ThemeColor', 'slug hex theme_equivalent')


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def __init__(self, *args, **kwargs):
twbscrispy.StrictButton(
_("Add Filter"),
type="submit",
css_class="btn-primary htmx-loading",
css_class="btn btn-primary",
),
# The Alpine data model is easily bound to the form
# to control hiding/showing the value field:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
<script src="{% static '@eonasdan/tempus-dominus/dist/js/tempus-dominus.min.js' %}"></script>
{% endcompress %}

{% block head %}
{% endblock head %}

<script src="{% statici18n LANGUAGE_CODE %}"></script>
</head>
<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{% if content.partial %}
<div>
{% include content.partial %}
</div>
{% endif %}
<div class="pb-3">
{% include 'styleguide/bootstrap5/partials/readable_code_block.html' with content=content.code language=content.language %}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<button
class="btn btn-primary" type="button"
hx-get="{% url 'styleguide_a_hanging_view' %}"
hx-disabled-elt="this"
hx-swap="none" {# example view returns nothing to display #}
>
Click Me
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="form-check">
<input
class="form-check-input" type="checkbox" value="" id="flexCheckDefault"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should this be flex-check-default for an HTML styled ID?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javascript standard is to use CamelCase, and this id is primarily used with javascript, not css

hx-get="{% url 'styleguide_a_hanging_view' %}"
hx-disabled-elt="this"
hx-swap="none" {# example view returns nothing to display #}
/>
<label class="form-check-label" for="flexCheckDefault">
Try to check me
</label>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<form
hx-get="{% url 'styleguide_a_hanging_view' %}"
hx-disabled-elt="find button"
hx-swap="none" {# example view returns nothing to display #}
>
<div class="mb-3">
<label for="id_value" class="form-label">Value</label>
<input type="text" name="value" class="textinput form-control" id="id_value"/>
Comment on lines +7 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should this be id-value for an HTML styled id?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is copied from crispy form, the id doesn't matter. ( still in group review )

</div>
<button class="btn btn-primary" type="submit">
Submit Me!
</button>
</form>
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{% extends 'styleguide/bootstrap5/base.html' %}
{% load hq_shared_tags %}

{% block head %}
<script src="{% static 'htmx.org/dist/htmx.min.js' %}"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this loaded somewhere else prior to this change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styleguide is not using webpack, so we need to import the library here, we might migrate styleguide to webpack in the future.

{% endblock head %}

{% block intro %}
<h1 class="sg-title mb-0" id="content">HTMX and Alpine</h1>
Expand Down Expand Up @@ -31,6 +36,14 @@ <h5 class="my-2 ms-3">On this page</h5>
</ul>
</li>
<li><a href="#debugging">Debugging During Development</a></li>
<li>
<a href="#loading-indicators">Loading Indicators</a>
<ul>
<a href="#button-loading">Buttons</a></li>
<a href="#checkbox-loading">Checkboxes</a></li>
<a href="#form-loading">Forms</a></li>
</ul>
</li>
</ul>
</nav>
{% endblock toc %}
Expand Down Expand Up @@ -241,4 +254,49 @@ <h2 id="debugging" class="pt-4">
You can check out the <code>HqHtmxDebugMixin</code> directly for additional documentation and usage
guidance.
</p>

<h2 id="loading-indicators" class="pt-4">
Loading Indicators
</h2>
<p>
You can use the <code>hx-indicator</code> attribute
(<a href="https://htmx.org/attributes/hx-indicator/" target="_blank">see docs here</a>)
to mark which element gets the <code>htmx-request</code> class appended to it during a request.
We've added custom styling to <code>_htmx.scss</code> to support the common states outlined
later in this section.
</p>
<p>
By default, if an element triggers an HTMX request, it will automatically get the <code>htmx-request</code>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emphasize the default behavior

CSS class applied to it. No extra usage of the <code>hx-indicator</code> attribute is necessary. The
example submitting elements below showcase this default behavior <strong>without</strong> the need for
specific <code>hx-indicator</code> usage.
</p>
<p>
It's often a great idea to pair button requests with <code>hx-disabled-elt="this"</code>
(<a href="https://htmx.org/attributes/hx-disabled-elt/" target="_blank`">see docs for hx-disabled-elt</a>),
like the examples below, so that the requesting element or related element is disabled during the request.
</p>
<h3 id="button-loading" class="pt-4">
Buttons
</h3>
{% include 'styleguide/bootstrap5/code_display.html' with content=examples.loading_button %}

<h3 id="checkbox-loading" class="pt-4">
Checkboxes
</h3>
{% include 'styleguide/bootstrap5/code_display.html' with content=examples.loading_checkbox %}

<h3 id="form-loading" class="pt-4">
Forms
</h3>
<p>
In the example below, note that the <code>form</code> is the triggering element, so the
<code>hx-disabled-elt</code> value is set to <code>find button</code> to disable all button children
of that form during an HTMX request. Since <code>form</code> is the submitting element, by default
it has the <code>htmx-request</code> class applied. Our styles ensure that
<code>button type="submit"</code> elements of a submitting form show the loading indicator during
an HTMX request.
</p>
{% include 'styleguide/bootstrap5/code_display.html' with content=examples.loading_form %}

{% endblock content %}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
x-model="itemValue"
>
<button
class="btn btn-primary htmx-loading"
class="btn btn-primary"
type="submit"
@click="isSubmitting = true"
>
Expand Down
2 changes: 2 additions & 0 deletions corehq/apps/styleguide/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
name="styleguide_datatables_data"),
url(r'^b5/data/paginated_table_data$', bootstrap5_data.paginated_table_data,
name="styleguide_paginated_table_data"),
url(r'^b5/data/a_hanging_view$', bootstrap5_data.a_hanging_view,
name="styleguide_a_hanging_view"),
url(r'^b5/example/', include(example_urlpatterns)),
url(r'^b5/guidelines/$', bootstrap5.styleguide_code_guidelines,
name="styleguide_code_guidelines_b5"),
Expand Down
16 changes: 16 additions & 0 deletions corehq/apps/styleguide/views/bootstrap5.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
get_js_example_context,
get_gradient_colors,
CodeForDisplay,
CodeForDisplayWithPartial,
)
from corehq.apps.styleguide.examples.bootstrap5.checkbox_form import CheckboxDemoForm
from corehq.apps.styleguide.examples.bootstrap5.crispy_forms_basic import BasicCrispyExampleForm
Expand Down Expand Up @@ -102,6 +103,21 @@ def styleguide_htmx_and_alpine(request):
code=get_example_context('styleguide/htmx_todo/item_done.html'),
language="Django",
),
'loading_button': CodeForDisplayWithPartial(
code=get_example_context('styleguide/bootstrap5/examples/htmx_loading_button.html'),
partial="styleguide/bootstrap5/examples/htmx_loading_button.html",
language="Django",
),
'loading_checkbox': CodeForDisplayWithPartial(
code=get_example_context('styleguide/bootstrap5/examples/htmx_loading_checkbox.html'),
partial="styleguide/bootstrap5/examples/htmx_loading_checkbox.html",
language="Django",
),
'loading_form': CodeForDisplayWithPartial(
code=get_example_context('styleguide/bootstrap5/examples/htmx_loading_form.html'),
partial="styleguide/bootstrap5/examples/htmx_loading_form.html",
language="Django",
),
}
})
return render(request, 'styleguide/bootstrap5/htmx_and_alpine.html', context)
Expand Down
7 changes: 6 additions & 1 deletion corehq/apps/styleguide/views/bootstrap5_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from collections import namedtuple
from gettext import gettext

from django.http import JsonResponse
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render

from corehq.apps.styleguide.utils import get_fake_tabular_data
Expand Down Expand Up @@ -111,3 +111,8 @@ def paginated_table_data(request):
"total": len(fake_data),
"rows": fake_data[start:end],
})


def a_hanging_view(request):
time.sleep(10)
return HttpResponse("Done")
Loading