Compare commits

...

3 commits

Author SHA1 Message Date
Casper V. Kristensen 74d3b3d3e9
Update raid response formset with custom template, based on Crispy's default one, for better styling. 2019-10-27 16:52:08 +01:00
Casper V. Kristensen 80d109efc0
Small update to aria labels. 2019-10-27 16:51:21 +01:00
Casper V. Kristensen d8c972ac4b
Improve class-coloured buttons and signup-coloured badges. 2019-10-27 13:41:23 +01:00
5 changed files with 212 additions and 47 deletions

View file

@ -1,16 +1,4 @@
/* https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html#change-required-fields */ /* WoW class-coloured text */
.asteriskField {
display: none;
}
.w-14 {
width: 14.285% !important; /* Like Bootstrap's .w-{25,50,75,100}, but for 1/7th of the width */
}
.o-50 {
opacity: 0.5;
}
.class-druid {color: #ff7d0a;} .class-druid {color: #ff7d0a;}
.class-hunter {color: #abd473;} .class-hunter {color: #abd473;}
.class-mage {color: #69ccf0;} .class-mage {color: #69ccf0;}
@ -21,75 +9,179 @@
.class-warlock {color: #9482c9;} .class-warlock {color: #9482c9;}
.class-warrior {color: #c79c6e;} .class-warrior {color: #c79c6e;}
.class-druid-bg {
/* WoW class-coloured buttons */
.btn-druid, .btn-class-1 {
color: #fff; color: #fff;
background-color: #ff7d0a; background-color: #ff7d0a;
border-color: #ff7d0a;
} }
.class-hunter-bg { .btn-druid:hover, .btn-class-1:hover {
color: #fff; color: #fff;
background-color: #abd473; background-color: #eb7c0a;
border-color: #eb7c0a;
} }
.class-mage-bg {
.btn-hunter, .btn-class-2 {
color: #212529;
background-color: #abd473;
border-color: #abd473;
}
.btn-hunter:hover, .btn-class-2:hover {
color: #212529;
background-color: #98c062;
border-color: #98c062;
}
.btn-mage, .btn-class-3 {
color: #fff; color: #fff;
background-color: #69ccf0; background-color: #69ccf0;
border-color: #69ccf0;
} }
.class-paladin-bg { .btn-mage:hover, .btn-class-3:hover {
color: #fff;
background-color: #67b8dc;
border-color: #67b8dc;
}
.btn-paladin, .btn-class-4 {
color: #fff; color: #fff;
background-color: #f58cba; background-color: #f58cba;
border-color: #f58cba;
} }
.class-priest-bg { .btn-paladin:hover, .btn-class-4:hover {
color: #343a40; color: #fff;
background-color: #e17aa7;
border-color: #e17aa7;
}
.btn-priest, .btn-class-5 {
color: #212529;
background-color: #ffffff; background-color: #ffffff;
border-color: #ced4da;
} }
.class-rogue-bg { .btn-priest:hover, .btn-class-5:hover {
color: #343a40; color: #212529;
background-color: #ebebeb;
border-color: #ced2d6;
}
.btn-rogue, .btn-class-6 {
color: #212529;
background-color: #fff569; background-color: #fff569;
border-color: #f5eb63;
} }
.class-shaman-bg { .btn-rogue:hover, .btn-class-6:hover {
color: #212529;
background-color: #ebe168;
border-color: #e1d761;
}
.btn-shaman, .btn-class-7 {
color: #fff; color: #fff;
background-color: #0070de; background-color: #0070de;
border-color: #0070de;
} }
.class-warlock-bg { .btn-shaman:hover, .btn-class-7:hover {
color: #fff;
background-color: #0065ca;
border-color: #0065ca;
}
.btn-warlock, .btn-class-8 {
color: #fff; color: #fff;
background-color: #9482c9; background-color: #9482c9;
border-color: #9482c9;
} }
.class-warrior-bg { .btn-warlock:hover, .btn-class-8:hover {
color: #fff;
background-color: #816fb5;
border-color: #816fb5;
}
.btn-warrior, .btn-class-9 {
color: #fff; color: #fff;
background-color: #c79c6e; background-color: #c79c6e;
border-color: #c79c6e;
}
.btn-warrior:hover, .btn-class-9:hover {
color: #fff;
background-color: #b3895c;
border-color: #b3895c;
} }
/* Response bg and text colors from https://getbootstrap.com/docs/4.3/utilities/colors/ */ /* Response bg and text colors from https://getbootstrap.com/docs/4.3/utilities/colors/ */
.response-status-signed-off-bg, .response-status-1-bg { .response-status-signed-off-bg, .response-status-1-bg { /* danger */
color: #fff; color: #fff;
background-color: #dc3545; background-color: #dc3545;
} }
.response-status-signed-up-bg, .response-status-2-bg { a.response-status-signed-off-bg:focus, a.response-status-1-bg:focus,
a.response-status-signed-off-bg:hover, a.response-status-1-bg:hover {
color: #fff;
background-color: #bd2130;
}
.response-status-signed-up-bg, .response-status-2-bg { /* info */
color: #fff; color: #fff;
background-color: #17a2b8; background-color: #17a2b8;
} }
.response-status-stand-by-bg, .response-status-3-bg { a.response-status-signed-up-bg:focus, a.response-status-2-bg:focus,
color: #343a40; a.response-status-signed-up-bg:hover, a.response-status-2-bg:hover {
color: #fff;
background-color: #117a8b;
}
.response-status-stand-by-bg, .response-status-3-bg { /* warning */
color: #212529;
background-color: #ffc107; background-color: #ffc107;
} }
.response-status-confirmed-bg, .response-status-4-bg { a.response-status-stand-by-bg:focus, a.response-status-3-bg:focus,
a.response-status-stand-by-bg:hover, a.response-status-3-bg:hover {
color: #212529;
background-color: #d39e00;
}
.response-status-confirmed-bg, .response-status-4-bg { /* success */
color: #fff; color: #fff;
background-color: #28a745; background-color: #28a745;
} }
.response-status-no-response-bg, .response-status-0-bg { a.response-status-confirmed-bg:focus, a.response-status-4-bg:focus,
a.response-status-confirmed-bg:hover, a.response-status-4-bg:hover {
color: #fff;
background-color: #1e7e34;
}
.response-status-no-response-bg, .response-status-0-bg { /* secondary */
color: #fff; color: #fff;
background-color: #6c757d; background-color: #6c757d;
} }
a.response-status-no-response-bg:focus, a.response-status-0-bg:focus,
.response-character-button { a.response-status-no-response-bg:hover, a.response-status-0-bg:hover {
width: 16ch; color: #545b62;
background-color: #545b62;
} }
.raid-response-form .form-group {
margin-bottom: 0; /* https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html#change-required-fields */
.asteriskField {
display: none;
} }
.raid-calendar td { .raid-calendar td {
height: 8rem; /* height works like min-height for td's */ height: 8rem; /* height works like min-height for td's */
padding: .5rem; padding: .5rem;
} }
.w-14 {
width: 14.285% !important; /* Like Bootstrap's .w-{25,50,75,100}, but for 1/7th of the width - used for calendar */
}
.o-50 {
opacity: 0.5;
}
.response-character-button {
width: 16ch;
}

View file

@ -103,16 +103,16 @@ RaidResponseFormSet = inlineformset_factory(
Raid, # parent model Raid, # parent model
RaidResponse, RaidResponse,
fields=["character", "role", "status", "note", "attendance"], fields=["character", "role", "status", "note", "attendance"],
can_delete=False,
extra=1 extra=1
) )
class RaidResponseFormSetHelper(FormHelper): class RaidResponseFormSetHelper(FormHelper):
template = "bootstrap4/table_inline_formset.html" template = "raids/raid_response_table_inline_formset.html"
def __init__(self, form=None): def __init__(self, form=None):
super().__init__(form) super().__init__(form)
self.form_class = "responses_form"
self.layout = Layout( self.layout = Layout(
Field("character", css_class="character-select"), Field("character", css_class="character-select"),
Field("role", css_class="role-select"), Field("role", css_class="role-select"),
@ -121,4 +121,3 @@ class RaidResponseFormSetHelper(FormHelper):
Field("attendance", css_class="attendance-input"), Field("attendance", css_class="attendance-input"),
) )
self.form_tag = False self.form_tag = False

View file

@ -6,7 +6,7 @@
{% block content %} {% block content %}
<h2>Raids</h2> <h2>Raids</h2>
<div class="d-flex justify-content-center mb-1"> <div class="d-flex justify-content-center mb-1">
<div class="btn-group" role="group" aria-label="Basic example"> <div class="btn-group" role="group" aria-label="Calendar navigation controls">
<a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' previous_month.year previous_month.month %}">&lt;</a> <a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' previous_month.year previous_month.month %}">&lt;</a>
<a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' %}">{{ month | date:"YEAR_MONTH_FORMAT" }}</a> <a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' %}">{{ month | date:"YEAR_MONTH_FORMAT" }}</a>
<a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' next_month.year next_month.month %}">&gt;</a> <a class="btn btn-secondary" role="button" href="{% url 'raid_calendar' next_month.year next_month.month %}">&gt;</a>

View file

@ -20,7 +20,7 @@
</div> </div>
{% if response_form %} {% if response_form %}
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body mb-n3">
<form class="raid-response-form" method="post" action="{% url 'raid_detail' raid.id %}"> <form class="raid-response-form" method="post" action="{% url 'raid_detail' raid.id %}">
{% crispy response_form %} {% crispy response_form %}
</form> </form>
@ -34,19 +34,18 @@
{% with status=status|default_if_none:"No Response" %} {% with status=status|default_if_none:"No Response" %}
<div class="card mb-2"> <div class="card mb-2">
<h6 class="card-header response-status-{{ status | slugify }}-bg">{{ status }} ({{ status_responses | length }})</h6> <h6 class="card-header response-status-{{ status | slugify }}-bg">{{ status }} ({{ status_responses | length }})</h6>
<div class="card-body"> <div class="card-body mb-n4">
{% regroup status_responses by get_role_display as role_responses_list %} {% regroup status_responses by get_role_display as role_responses_list %}
{% for role, role_responses in role_responses_list %} {% for role, role_responses in role_responses_list %}
{% if role is not None %} {% if role is not None %}
<h6 class="card-title">{{ role }} ({{ role_responses | length }})</h6> <h6 class="card-title border-bottom pb-2">{{ role }} ({{ role_responses | length }})</h6>
<hr>
{% endif %} {% endif %}
<div class="d-flex flex-wrap"> <div class="d-flex flex-wrap">
{% regroup role_responses by character.klass as class_responses_list %} {% regroup role_responses by character.klass as class_responses_list %}
{% for class, class_responses in class_responses_list %} {% for class, class_responses in class_responses_list %}
<div class="d-flex flex-column mr-3 mb-3"> <div class="d-flex flex-column mr-2 mb-4">
{% for response in class_responses %} {% for response in class_responses %}
<a class="btn btn-secondary response-character-button mb-1 class-{{ response.character.get_klass_display | lower }}-bg" role="button" href="#"> <a class="btn response-character-button mb-1 btn-class-{{ response.character.klass }}" role="button" href="#">
{{ response.character.name }} {{ response.character.name }}
{% if response.note is not None %}&#128489;{% endif %} {% if response.note is not None %}&#128489;{% endif %}
</a> </a>

View file

@ -0,0 +1,75 @@
{% comment %}
Based on Crispy's default bootstrap4/table_inline_formset.html
https://github.com/django-crispy-forms/django-crispy-forms/blob/master/crispy_forms/templates/bootstrap4/table_inline_formset.html
{% endcomment %}
{% load crispy_forms_tags %}
{% load crispy_forms_utils %}
{% load crispy_forms_field %}
{% specialspaceless %}
{% if formset_tag %}
<form {{ flat_attrs|safe }} method="{{ form_method }}" {% if formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
{% endif %}
{% if formset_method|lower == 'post' and not disable_csrf %}
{% csrf_token %}
{% endif %}
<div>
{{ formset.management_form|crispy }}
</div>
<table{% if form_id %} id="{{ form_id }}_table"{% endif%} class="table table-sm">
<thead>
{% if formset.readonly and not formset.queryset.exists %}
{% else %}
<tr>
{% for field in formset.forms.0 %}
{% if field.label and not field.is_hidden %}
<th for="{{ field.auto_id }}" class="col-form-label {% if field.field.required %}requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required and not field|is_checkbox %}<span class="asteriskField">*</span>{% endif %}
</th>
{% endif %}
{% endfor %}
</tr>
{% endif %}
</thead>
<tbody>
<tr class="d-none empty-form">
{% for field in formset.empty_form %}
{% include 'bootstrap4/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr>
{% regroup formset by status.value as status_forms_list %}
{% for status, status_forms in status_forms_list %}
{% regroup status_forms by role.value as role_forms_list %}
{% for role, role_forms in role_forms_list %}
{% for form in role_forms %}
{% if form_show_errors and not form.is_extra %}
{% include "bootstrap4/errors.html" %}
{% endif %}
<tr>
{% for field in form %}
{% include 'bootstrap4/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr>
{% endfor %}
{% if not forloop.last %}
<tr><td class="p-2"></td></tr>
{% endif %}
{% endfor %}
{% if not forloop.last %}
<tr><td class="pt-3"></td></tr>
<tr class="border-bottom"></tr>
<tr><td class="pb-3"></td></tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% include "bootstrap4/inputs.html" %}
{% if formset_tag %}</form>{% endif %}
{% endspecialspaceless %}