Upgrade to Bootstrap 5 (#479)

* Update Tempus Dominus to v6 (WIP)

* Re-add calendar input prepend container

* Normalize setting of default date values

* Migrate to Bootstrap 5 (WIP)

* Remove deprecated card columns implementation from dashboard

* Update BS5 data props

* Use Masonry layout for dashboard cards (for now)

This doesn't seem particularly ideal so may need a more involved refactor

* Update styles for Bootstrap 5 deprecations

* Remove resolutions crap

* Refactor deprecated BS4 classes

* Update list table styles

* Refactor deprecated jumbotron class usages

* Update close button structure

* Add `v2` branch to standard CI workflows
This commit is contained in:
Christopher C. Wells 2023-03-25 12:57:12 -07:00
parent 77d4ba1920
commit 34fe811a54
105 changed files with 19654 additions and 18521 deletions

View File

@ -3,9 +3,11 @@ on:
push: push:
branches: branches:
- master - master
- v2
pull_request: pull_request:
branches: branches:
- master - master
- v2
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -1,9 +1,13 @@
name: "CodeQL" name: "CodeQL"
on: on:
push: push:
branches: [ master ] branches:
- master
- v2
pull_request: pull_request:
branches: [ master ] branches:
- master
- v2
schedule: schedule:
- cron: '33 0 * * 3' - cron: '33 0 * * 3'
jobs: jobs:

View File

@ -23,34 +23,48 @@ var BabyBuddy = function () {
* *
* @type {{init: BabyBuddy.DatetimePicker.init}} * @type {{init: BabyBuddy.DatetimePicker.init}}
*/ */
BabyBuddy.DatetimePicker = function ($, moment) { BabyBuddy.DatetimePicker = function (moment) {
return { return {
init: function (element, options) { init: function (element, options) {
var defaultOptions = { let defaultOptions = {
buttons: { showToday: true, showClose: true }, display: {
defaultDate: 'now', buttons: {
focusOnShow: false, close: true,
format: 'L LT', today: true,
ignoreReadonly: true, },
locale: moment.locale(), components: {
useCurrent: false, calendar: true,
icons: { clock: true,
time: 'icon-clock', date: true,
date: 'icon-calendar', decades: true,
up: 'icon-arrow-up', hours: true,
down: 'icon-arrow-down', minutes: true,
previous: 'icon-angle-circled-left', month: true,
next: 'icon-angle-circled-right', seconds: false,
today: 'icon-today', useTwentyfourHour: false,
clear: 'icon-delete', year: true,
close: 'icon-cancel' },
icons: {
clear: 'icon-delete',
close: 'icon-cancel',
date: 'icon-calendar',
down: 'icon-arrow-down',
next: 'icon-angle-circled-right',
previous: 'icon-angle-circled-left',
time: 'icon-clock',
today: 'icon-today',
up: 'icon-arrow-up',
},
viewMode: 'clock',
},
localization: {
locale: moment.locale(),
}, },
viewMode: 'times',
}; };
element.datetimepicker($.extend(defaultOptions, options)); new tempusDominus.TempusDominus(element, Object.assign(defaultOptions, options));
} }
}; };
}(jQuery, moment); }(moment);
/** /**
* Pull to refresh. * Pull to refresh.

View File

@ -174,7 +174,7 @@
this.apiTagsUrl = widget.getAttribute('data-tags-url'); this.apiTagsUrl = widget.getAttribute('data-tags-url');
this.createTagInputs = widget.querySelector('.create-tag-inputs'); this.createTagInputs = widget.querySelector('.create-tag-inputs');
this.addTagInput = this.createTagInputs.querySelector('input[type="text"]'); this.addTagInput = this.createTagInputs.querySelector('input[type="text"]');
this.addTagButton = this.createTagInputs.querySelector('.btn-add-new-tag'); this.addTagButton = this.createTagInputs.querySelector('#add-tag');
this.addTagInput.value = ""; this.addTagInput.value = "";

View File

@ -1,3 +0,0 @@
@import '../../../node_modules/bootstrap/scss/functions';
// Baby Buddy site-wide custom functions.

View File

@ -1,3 +0,0 @@
@import '../../../node_modules/bootstrap/scss/mixins';
// Baby Buddy site-wide custom mixins.

View File

@ -1,5 +1,136 @@
@import 'functions'; @use 'sass:color';
@import '../../../node_modules/bootstrap/scss/variables';
@import 'themes/blueorange';
// Baby Buddy site-wide variables. // Theme variables.
// Color system
$white: #fff;
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
$gray-400: #ced4da;
$gray-500: #adb5bd;
$gray-600: #6c757d;
$gray-700: #495057;
$gray-800: #343a40;
$gray-900: #212529;
$black: #000;
$primary: #37abe9;
$danger: #a72431;
$error: $danger;
$secondary: #ff8f00;
$warning: #ffbe42;
$success: #239556;
$debug: #5abccc;
$info: #44c4dd;
$light: $gray-100;
$dark: $gray-800;
// Body
// Settings for the `<body>` element.
$body-bg: $gray-900;
$body-color: $gray-400;
// Links
// Style anchor elements.
$link-color: $info;
$link-decoration: none;
$link-hover-color: color.adjust($link-color, $lightness: -15%);
// Components
// Define common padding and border radius sizes and more.
$border-color: $gray-200;
$component-active-color: $gray-400;
$component-active-bg: $primary;
// Fonts
// Font, line-height, and color for body text, headings, and more.
$text-muted: $gray-600 !default;
$blockquote-small-color: $gray-600 !default;
$hr-border-color: rgba($black, .1) !default;
$mark-bg: #fcf8e3 !default;
// Forms
$input-bg: $white;
$input-disabled-bg: $gray-600;
$input-color: $black;
$input-border-color: rgba($gray-600, .15);
$input-group-addon-bg: $gray-500;
// Tables
$table-cell-padding-y: 0.75rem;
$table-cell-padding-x: 0.75rem;
$table-striped-bg: $dark;
// Dropdowns
// Dropdown menu container and contents.
$dropdown-bg: $gray-700;
$dropdown-divider-bg: $gray-800;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: color.adjust($body-color, $lightness: -5%);
$dropdown-link-hover-bg: $primary;
$dropdown-link-active-color: $component-active-color;
$dropdown-link-active-bg: $component-active-bg;
$dropdown-header-color: color.adjust($body-color, $lightness: -25%);
// Pagination
$pagination-color: $link-color;
$pagination-bg: $dark;
$pagination-border-color: color.adjust($dark, $lightness: 5%);
$pagination-hover-color: $link-hover-color;
$pagination-hover-bg: $gray-900;
$pagination-hover-border-color: $gray-800;
$pagination-active-color: $body-color;
$pagination-active-bg: $primary;
$pagination-active-border-color: $primary;
$pagination-disabled-color: $gray-600;
$pagination-disabled-bg: $pagination-bg;
$pagination-disabled-border-color: $pagination-border-color;
// Cards
$card-bg: $dark;
$card-cap-bg: rgba($light, .05);
// Progress bars
$progress-bg: $gray-600;
// List group
$list-group-bg: $dark;
$list-group-hover-bg: color.adjust($list-group-bg, $lightness: -5%);
$list-group-active-color: $component-active-color !default;
$list-group-active-bg: $component-active-bg !default;
$list-group-active-border-color: $list-group-active-bg !default;
$list-group-action-color: $gray-400;
$list-group-action-hover-color: $list-group-action-color;
// Breadcrumbs
$breadcrumb-active-color: $gray-600;
$breadcrumb-bg: none;
$breadcrumb-padding-y: 0.75rem;
$breadcrumb-padding-x: 1rem;

View File

@ -1,8 +1,7 @@
@import 'functions';
@import 'variables'; @import 'variables';
@import 'mixins';
@import '../../../node_modules/bootstrap/scss/bootstrap'; @import '../../../node_modules/bootstrap/scss/bootstrap';
@import '../../../node_modules/tempusdominus-bootstrap-4/src/sass/tempusdominus-bootstrap-4'; @import '../../../node_modules/@eonasdan/tempus-dominus/src/sass/variables';
@import '../../../node_modules/@eonasdan/tempus-dominus/src/sass/tempus-dominus';
@import '../../../**/static_src/scss/*'; @import '../../../**/static_src/scss/*';
@import '../fontello/css/babybuddy'; @import '../fontello/css/babybuddy';

View File

@ -1,3 +1,5 @@
@use 'sass:map';
// Baby Buddy form style customizations. // Baby Buddy form style customizations.
// BB form fields do not follow typical BS4 style that enables this display. // BB form fields do not follow typical BS4 style that enables this display.
@ -34,7 +36,7 @@
.input-group-text { .input-group-text {
background: none; background: none;
border: 0; border: 0;
color: theme-color('primary'); color: map.get($theme-colors, 'primary');
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
} }

View File

@ -1,3 +1,5 @@
@use 'sass:map';
// Baby Buddy site-wide custom styles. // Baby Buddy site-wide custom styles.
// Remove extra margin below site breadcrumb. // Remove extra margin below site breadcrumb.
@ -7,7 +9,7 @@
// Extra-small button. // Extra-small button.
.btn-xs { .btn-xs {
@include button-size(.2rem, .12rem, .75rem, 1, .2rem); @include button-size(.2rem, .12rem, .75rem, .2rem);
} }
// Right align main dropdown menu. // Right align main dropdown menu.
@ -18,33 +20,10 @@
// PullToRefresh elements. // PullToRefresh elements.
.ptr--ptr { .ptr--ptr {
background: theme-color('dark'); background: map.get($theme-colors, 'dark');
.ptr--text, .ptr--icon { .ptr--text, .ptr--icon {
// "!important" must be used to override inline styling from JS. // "!important" must be used to override inline styling from JS.
color: theme-color('light') !important; color: map.get($theme-colors, 'light') !important;
}
}
// Basic table of model instances.
.table-instances {
tr {
td, th {
vertical-align: middle;
}
&.odd {
background: $table-accent-bg;
}
&.even {
background: none;
}
&.row-details {
td {
color: $gray-500;
padding-top: 0;
border-top: 0;
}
}
} }
} }
@ -55,5 +34,5 @@
// All modals // All modals
.modal-content { .modal-content {
color: theme-color('dark'); color: map.get($theme-colors, 'dark');
} }

View File

@ -1,149 +0,0 @@
@use 'sass:color';
// Blue Orange theme variables.
// Color system
$blue: #37abe9;
$indigo: #472395;
$purple: #712395;
$pink: #952393;
$red: #a72431;
$orange: #ff8f00;
$yellow: #ffbe42;
$green: #239556;
$teal: #5abccc;
$cyan: #44c4dd;
$theme-colors: (
primary: $blue,
secondary: $orange,
success: $green,
info: $cyan,
debug: $cyan,
warning: $yellow,
danger: $red,
error: $red,
light: $gray-100,
dark: $gray-800
);
// Body
// Settings for the `<body>` element.
$body-bg: $gray-900;
$body-color: $gray-400;
// Links
// Style anchor elements.
$link-color: theme-color('info');
$link-hover-color: color.adjust($link-color, $lightness: -15%);
// Components
// Define common padding and border radius sizes and more.
$border-color: $gray-200;
$component-active-color: $gray-400;
$component-active-bg: theme-color('primary');
// Fonts
// Font, line-height, and color for body text, headings, and more.
$text-muted: $gray-600 !default;
$blockquote-small-color: $gray-600 !default;
$hr-border-color: rgba($black, .1) !default;
$mark-bg: #fcf8e3 !default;
// Tables
// Customizes the `.table` component with basic values, each used across all table variations.
$table-border-color: $gray-800;
$table-color: $body-color;
$table-head-bg: theme-color('primary');
$table-hover-color: $body-color;
$table-inverse-bg: theme-color('primary');
$table-accent-bg: rgba(theme-color('primary'), .1);
// Forms
$input-bg: $white;
$input-disabled-bg: $gray-600;
$input-color: $black;
$input-border-color: rgba($gray-600, .15);
$input-group-addon-bg: $gray-500;
// Dropdowns
// Dropdown menu container and contents.
$dropdown-bg: $gray-700;
$dropdown-divider-bg: $gray-800;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: color.adjust($body-color, $lightness: -5%);
$dropdown-link-hover-bg: theme-color('primary');
$dropdown-link-active-color: $component-active-color;
$dropdown-link-active-bg: $component-active-bg;
$dropdown-header-color: color.adjust($body-color, $lightness: -25%);
// Pagination
$pagination-color: $link-color;
$pagination-bg: theme-color('dark');
$pagination-border-color: color.adjust(theme-color('dark'), $lightness: 5%);
$pagination-hover-color: $link-hover-color;
$pagination-hover-bg: $gray-900;
$pagination-hover-border-color: $gray-800;
$pagination-active-color: $body-color;
$pagination-active-bg: theme-color('primary');
$pagination-active-border-color: theme-color('primary');
$pagination-disabled-color: $gray-600;
$pagination-disabled-bg: $pagination-bg;
$pagination-disabled-border-color: $pagination-border-color;
// Jumbotron
$jumbotron-bg: theme-color('dark');
// Cards
$card-bg: theme-color('dark');
$card-cap-bg: rgba(theme-color('light'), .05);
// Progress bars
$progress-bg: $gray-600;
// List group
$list-group-bg: theme-color('dark');
$list-group-hover-bg: color.adjust($list-group-bg, $lightness: -5%);
$list-group-active-color: $component-active-color !default;
$list-group-active-bg: $component-active-bg !default;
$list-group-active-border-color: $list-group-active-bg !default;
$list-group-action-color: $gray-400;
$list-group-action-hover-color: $list-group-action-color;
// Breadcrumbs
$breadcrumb-bg: none;
$breadcrumb-active-color: $gray-600;
// Datetimepicker library (Tempus Dominus)
$bs-datetimepicker-btn-hover-bg: $gray-800;

View File

@ -8,14 +8,14 @@
</label> </label>
<div class="col-xs-10 col-sm-auto"> <div class="col-xs-10 col-sm-auto">
{% if 'choice' or 'boolean' in field|field_type %} {% if 'choice' or 'boolean' in field|field_type %}
{{ field|add_class:"custom-select custom-select-sm" }} {{ field|add_class:"form-select form-select-sm" }}
{% else %} {% else %}
{{ field|add_class:"form-control form-control-sm" }} {{ field|add_class:"form-control form-control-sm" }}
{% endif %} {% endif %}
</div> </div>
{% endfor %} {% endfor %}
<div class="col-xs-12 col-sm-auto mt-3 mt-sm-0"> <div class="col-xs-12 col-sm-auto mt-3 mt-sm-0">
<button type="submit" class="btn btn-sm btn-primary mr-2">{% trans "Filter" %}</button> <button type="submit" class="btn btn-sm btn-primary me-2">{% trans "Filter" %}</button>
<a href="{{ request.path }}" class="btn btn-sm btn-error">{% trans "Reset" %}</a> <a href="{{ request.path }}" class="btn btn-sm btn-error">{% trans "Reset" %}</a>
</div> </div>
</div> </div>
@ -24,7 +24,7 @@
<p> <p>
<a class="btn btn-dark btn-sm" <a class="btn btn-dark btn-sm"
data-toggle="collapse" data-bs-toggle="collapse"
href="#filter_form" href="#filter_form"
role="button" role="button"
aria-expanded="false" aria-expanded="false"

View File

@ -7,7 +7,7 @@
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
{{ field.widget }} {{ field.widget }}
<div class="form-group row"> <div class="row">
{% include 'babybuddy/form_field.html' %} {% include 'babybuddy/form_field.html' %}
</div> </div>
{% endfor %} {% endfor %}

View File

@ -1,50 +1,51 @@
{% load widget_tweaks %} {% load widget_tweaks %}
<label for="id_{{ field.name }}" class="col-sm-2 col-form-label{% if field|field_type == 'booleanfield' %} boolean-label{% endif %}"> <div class="row mb-3">
{% if field|field_type != "booleanfield" %} <label for="id_{{ field.name }}" class="col-sm-2 col-form-label{% if field|field_type == 'booleanfield' %} boolean-label{% endif %}">
{{ field.label }} {{ field.label }}
{% endif %} </label>
</label> <div class="col-sm-10{% if field|widget_type == 'childradioselect' %} overflow-auto"{% endif %}">
<div class="col-sm-10{% if field|widget_type == 'childradioselect' %} overflow-auto"{% endif %}"> {% if field|field_type == "booleanfield" %}
{% if field|field_type == "booleanfield" %} {% if field.errors %}
<div class="btn-group-toggle" data-toggle="buttons"> {{ field|add_class:"btn-check is-invalid" }}
{% else %}
{{ field|add_class:"btn-check" }}
{% endif %}
<label for="id_{{ field.name }}" class="btn btn-outline-light btn-no-hover{% if field.value %} active{% endif %}"> <label for="id_{{ field.name }}" class="btn btn-outline-light btn-no-hover{% if field.value %} active{% endif %}">
{% if field.errors %}
{{ field|add_class:"is-invalid" }}
{% else %}
{{ field }}
{% endif %}
{{ field.label }} {{ field.label }}
</label> </label>
</div> {% elif field|field_type == "datetimefield" or field|field_type == "datefield" %}
{% elif field|field_type == "datetimefield" or field|field_type == "datefield" %} <div class="input-group input-group-lg datetimepicker"
<div class="input-group input-group-lg datetimepicker" id="datetimepicker_{{ field.name }}" data-target-input="nearest"> id="datetimepicker_{{ field.name }}"
<div class="input-group-prepend px-2 rounded-left bg-dark" data-target="#datetimepicker_{{ field.name }}" data-toggle="datetimepicker"> data-td-target-input="nearest"
<span class="input-group-text"><i class="icon-calendar"></i></span> data-td-target-toggle="nearest">
</div> <span class="input-group-text px-2 rounded-start bg-dark"
data-td-target="#datetimepicker_{{ field.name }}"
data-td-toggle="datetimepicker"><i class="icon-calendar"></i></span>
{% if field.errors %}
{{ field|add_class:"datetimepicker-input form-control form-control-lg is-invalid" }}
{% else %}
{{ field|add_class:"datetimepicker-input form-control form-control-lg" }}
{% endif %}
</div>
{% elif 'choice' in field|field_type %}
{% if field.errors %} {% if field.errors %}
{{ field|add_class:"datetimepicker-input form-control form-control-lg is-invalid" }} {{ field|add_class:"form-select is-invalid" }}
{% else %} {% else %}
{{ field|add_class:"datetimepicker-input form-control form-control-lg" }} {{ field|add_class:"form-select" }}
{% endif %} {% endif %}
</div>
{% elif 'choice' in field|field_type %}
{% if field.errors %}
{{ field|add_class:"custom-select is-invalid" }}
{% else %} {% else %}
{{ field|add_class:"custom-select" }} {% if field.errors %}
{{ field|add_class:"form-control is-invalid" }}
{% else %}
{{ field|add_class:"form-control" }}
{% endif %}
{% endif %}
{% if field.help_text %}
<div class="help-block"><small>{{ field.help_text }}</small></div>
{% endif %} {% endif %}
{% else %}
{% if field.errors %} {% if field.errors %}
{{ field|add_class:"form-control is-invalid" }} <div class="invalid-feedback">{% for error in field.errors %}{{ error }}{% endfor %}</div>
{% else %}
{{ field|add_class:"form-control" }}
{% endif %} {% endif %}
{% endif %} </div>
{% if field.help_text %}
<div class="help-block"><small>{{ field.help_text }}</small></div>
{% endif %}
{% if field.errors %}
<div class="invalid-feedback">{% for error in field.errors %}{{ error }}{% endfor %}</div>
{% endif %}
</div> </div>

View File

@ -5,9 +5,7 @@
{% for message in messages %} {% for message in messages %}
<div class="alert{% if message.tags %} alert-{{ message.tags }}{% endif %} alert-dismissible fade show" role="alert"> <div class="alert{% if message.tags %} alert-{{ message.tags }}{% endif %} alert-dismissible fade show" role="alert">
{{ message }} {{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
<span aria-hidden="true">&times;</span>
</button>
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@ -3,86 +3,85 @@
{% block nav %} {% block nav %}
<nav class="navbar navbar-expand-md navbar-dark bg-dark sticky-top"> <nav class="navbar navbar-expand-md navbar-dark bg-dark sticky-top">
<a class="navbar-brand mr-2" href={% url "babybuddy:root-router" %}> <div class="container-fluid">
<img src="{% static "babybuddy/logo/icon-brand.png" %}" width="30" height="30" class="d-inline-block align-top" alt=""> <a class="navbar-brand me-2" href={% url "babybuddy:root-router" %}>
<span class="d-none d-lg-inline-block"> <img src="{% static "babybuddy/logo/icon-brand.png" %}" width="30" height="30"
<span class="text-primary">Baby</span> Buddy class="d-inline-block align-top" alt="">
</span> <span class="d-none d-lg-inline-block">
</a> <span class="text-primary">Baby</span> Buddy
<div class="d-lg-none d-md-none d-flex mr-auto p-0 ml-2"> </span>
<div> </a>
<a class="text-muted" <div class="d-lg-none d-md-none d-flex me-auto p-0 ms-2">
href="{% url 'dashboard:dashboard' %}" <div>
aria-expanded="false"><i class="icon-2x icon-dashboard" aria-hidden="true"></i> <a class="text-muted"
</a> href="{% url 'dashboard:dashboard' %}"
&nbsp; aria-expanded="false"><i class="icon-2x icon-dashboard" aria-hidden="true"></i>
</div> </a>
<div> &nbsp;
<a class="text-muted" </div>
href="{% url 'core:timeline' %}" <div>
aria-expanded="false"><i class="icon-2x icon-timeline" aria-hidden="true"></i> <a class="text-muted"
</a> href="{% url 'core:timeline' %}"
&nbsp; aria-expanded="false"><i class="icon-2x icon-timeline" aria-hidden="true"></i>
</div> </a>
</div> &nbsp;
<div class="d-lg-none d-md-none d-flex ml-auto p-0 mr-2">
{% quick_timer_nav %}
<div class="dropdown show">
<a class="text-success"
href="#"
role="button"
id="nav-quick-add-link"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"><i class="icon-2x icon-add" aria-hidden="true"></i>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="nav-quick-add-link">
{% if perms.core.add_diaperchange %}
<a class="dropdown-item p-2" href="{% url 'core:diaperchange-add' %}">
<i class="icon-diaperchange" aria-hidden="true"></i>
{% trans "Diaper Change" %}
</a>
{% endif %}
{% if perms.core.add_feeding %}
<a class="dropdown-item p-2" href="{% url 'core:feeding-add' %}">
<i class="icon-feeding" aria-hidden="true"></i>
{% trans "Feeding" %}
</a>
{% endif %}
{% if perms.core.add_note %}
<a class="dropdown-item p-2" href="{% url 'core:note-add' %}">
<i class="icon-note" aria-hidden="true"></i>
{% trans "Note" %}
</a>
{% endif %}
{% if perms.core.add_sleep %}
<a class="dropdown-item p-2" href="{% url 'core:sleep-add' %}">
<i class="icon-sleep" aria-hidden="true"></i>
{% trans "Sleep" %}
</a>
{% endif %}
{% if perms.core.add_tummytime %}
<a class="dropdown-item p-2" href="{% url 'core:tummytime-add' %}">
<i class="icon-tummytime" aria-hidden="true"></i>
{% trans "Tummy Time" %}
</a>
{% endif %}
</div> </div>
</div> </div>
</div> <div class="d-lg-none d-md-none d-flex ms-auto p-0 me-2">
{% quick_timer_nav %}
<div class="dropdown show">
<a class="text-success"
href="#"
role="button"
id="nav-quick-add-link"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"><i class="icon-2x icon-add" aria-hidden="true"></i>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" <div class="dropdown-menu dropdown-menu-end" aria-labelledby="nav-quick-add-link">
{% if perms.core.add_diaperchange %}
<a class="dropdown-item p-2" href="{% url 'core:diaperchange-add' %}">
<i class="icon-diaperchange" aria-hidden="true"></i>
{% trans "Diaper Change" %}
</a>
{% endif %}
{% if perms.core.add_feeding %}
<a class="dropdown-item p-2" href="{% url 'core:feeding-add' %}">
<i class="icon-feeding" aria-hidden="true"></i>
{% trans "Feeding" %}
</a>
{% endif %}
{% if perms.core.add_note %}
<a class="dropdown-item p-2" href="{% url 'core:note-add' %}">
<i class="icon-note" aria-hidden="true"></i>
{% trans "Note" %}
</a>
{% endif %}
{% if perms.core.add_sleep %}
<a class="dropdown-item p-2" href="{% url 'core:sleep-add' %}">
<i class="icon-sleep" aria-hidden="true"></i>
{% trans "Sleep" %}
</a>
{% endif %}
{% if perms.core.add_tummytime %}
<a class="dropdown-item p-2" href="{% url 'core:tummytime-add' %}">
<i class="icon-tummytime" aria-hidden="true"></i>
{% trans "Tummy Time" %}
</a>
{% endif %}
</div>
</div>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-target="#navbar-app" aria-controls="navbar-app" data-target="#navbar-app" aria-controls="navbar-app"
aria-expanded="false" aria-label="Toggle navigation"> aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbar-app"> <div class="collapse navbar-collapse" id="navbar-app">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav me-auto">
<li class="nav-item{% if request.path == '/' %} active{% endif %}"> <li class="nav-item{% if request.path == '/' %} active{% endif %}">
<a class="nav-link" href="{% url 'dashboard:dashboard' %}"> <a class="nav-link" href="{% url 'dashboard:dashboard' %}">
<i class="icon-dashboard" aria-hidden="true"></i> <i class="icon-dashboard" aria-hidden="true"></i>
@ -101,7 +100,7 @@
<a id="nav-children-menu-link" <a id="nav-children-menu-link"
class="nav-link dropdown-toggle" class="nav-link dropdown-toggle"
href="#" href="#"
data-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"><i class="icon-child" aria-hidden="true"></i> aria-expanded="false"><i class="icon-child" aria-hidden="true"></i>
{% trans "Children" %} {% trans "Children" %}
@ -116,7 +115,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_child %} {% if perms.core.add_child %}
<a class="dropdown-item pl-5{% if request.path == '/children/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/children/add/' %} active{% endif %}"
href="{% url 'core:child-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:child-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Child" %} {% trans "Child" %}
</a> </a>
@ -130,7 +129,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_note %} {% if perms.core.add_note %}
<a class="dropdown-item pl-5{% if request.path == '/notes/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/notes/add/' %} active{% endif %}"
href="{% url 'core:note-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:note-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Note" %} {% trans "Note" %}
</a> </a>
@ -143,7 +142,7 @@
<a id="nav-measurements-menu-link" <a id="nav-measurements-menu-link"
class="nav-link dropdown-toggle" class="nav-link dropdown-toggle"
href="#" href="#"
data-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"><i class="icon-measurements" aria-hidden="true"></i> aria-expanded="false"><i class="icon-measurements" aria-hidden="true"></i>
{% trans "Measurements" %} {% trans "Measurements" %}
@ -158,7 +157,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_bmi %} {% if perms.core.add_bmi %}
<a class="dropdown-item pl-5{% if request.path == '/bmi/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/bmi/add/' %} active{% endif %}"
href="{% url 'core:bmi-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:bmi-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "BMI entry" %} {% trans "BMI entry" %}
</a> </a>
@ -172,7 +171,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_head_circumference %} {% if perms.core.add_head_circumference %}
<a class="dropdown-item pl-5{% if request.path == '/head-circumference/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/head-circumference/add/' %} active{% endif %}"
href="{% url 'core:head-circumference-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:head-circumference-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Head Circumference entry" %} {% trans "Head Circumference entry" %}
</a> </a>
@ -186,7 +185,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_height %} {% if perms.core.add_height %}
<a class="dropdown-item pl-5{% if request.path == '/height/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/height/add/' %} active{% endif %}"
href="{% url 'core:height-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:height-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Height entry" %} {% trans "Height entry" %}
</a> </a>
@ -200,8 +199,9 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_temperature %} {% if perms.core.add_temperature %}
<a class="dropdown-item pl-5{% if request.path == '/temperature/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/temperature/add/' %} active{% endif %}"
href="{% url 'core:temperature-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:temperature-add' %}"><i class="icon-add"
aria-hidden="true"></i>
{% trans "Temperature reading" %} {% trans "Temperature reading" %}
</a> </a>
{% endif %} {% endif %}
@ -222,12 +222,11 @@
</div> </div>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a id="nav-activity-menu-link" <a id="nav-activity-menu-link"
class="nav-link dropdown-toggle" class="nav-link dropdown-toggle"
href="#" href="#"
data-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"><i class="icon-activities" aria-hidden="true"></i> aria-expanded="false"><i class="icon-activities" aria-hidden="true"></i>
{% trans "Activities" %} {% trans "Activities" %}
@ -236,12 +235,13 @@
{% if perms.core.view_diaperchange %} {% if perms.core.view_diaperchange %}
<a class="dropdown-item{% if request.path == '/changes/' %} active{% endif %}" <a class="dropdown-item{% if request.path == '/changes/' %} active{% endif %}"
href="{% url 'core:diaperchange-list' %}"><i class="icon-diaperchange" aria-hidden="true"></i> href="{% url 'core:diaperchange-list' %}"><i class="icon-diaperchange"
aria-hidden="true"></i>
{% trans "Changes" %} {% trans "Changes" %}
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_diaperchange %} {% if perms.core.add_diaperchange %}
<a class="dropdown-item pl-5{% if request.path == '/changes/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/changes/add/' %} active{% endif %}"
href="{% url 'core:diaperchange-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:diaperchange-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Change" %} {% trans "Change" %}
</a> </a>
@ -254,7 +254,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_feeding %} {% if perms.core.add_feeding %}
<a class="dropdown-item pl-5{% if request.path == '/feedings/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/feedings/add/' %} active{% endif %}"
href="{% url 'core:feeding-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:feeding-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Feeding" %} {% trans "Feeding" %}
</a> </a>
@ -268,7 +268,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_pumping %} {% if perms.core.add_pumping %}
<a class="dropdown-item pl-5{% if request.path == '/pumping/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/pumping/add/' %} active{% endif %}"
href="{% url 'core:pumping-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:pumping-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Pumping entry" %} {% trans "Pumping entry" %}
</a> </a>
@ -281,7 +281,7 @@
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_sleep %} {% if perms.core.add_sleep %}
<a class="dropdown-item pl-5{% if request.path == '/sleep/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/sleep/add/' %} active{% endif %}"
href="{% url 'core:sleep-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:sleep-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Sleep entry" %} {% trans "Sleep entry" %}
</a> </a>
@ -289,12 +289,13 @@
{% if perms.core.view_tummytime %} {% if perms.core.view_tummytime %}
<a class="dropdown-item{% if request.path == '/tummy-time/' %} active{% endif %}" <a class="dropdown-item{% if request.path == '/tummy-time/' %} active{% endif %}"
href="{% url 'core:tummytime-list' %}"><i class="icon-tummytime" aria-hidden="true"></i> href="{% url 'core:tummytime-list' %}"><i class="icon-tummytime"
aria-hidden="true"></i>
{% trans "Tummy Time" %} {% trans "Tummy Time" %}
</a> </a>
{% endif %} {% endif %}
{% if perms.core.add_tummytime %} {% if perms.core.add_tummytime %}
<a class="dropdown-item pl-5{% if request.path == '/tummy-time/add/' %} active{% endif %}" <a class="dropdown-item ps-5{% if request.path == '/tummy-time/add/' %} active{% endif %}"
href="{% url 'core:tummytime-add' %}"><i class="icon-add" aria-hidden="true"></i> href="{% url 'core:tummytime-add' %}"><i class="icon-add" aria-hidden="true"></i>
{% trans "Tummy Time entry" %} {% trans "Tummy Time entry" %}
</a> </a>
@ -308,21 +309,23 @@
</ul> </ul>
{% if request.user %} {% if request.user %}
<ul class="navbar-nav ml-auto"> <ul class="navbar-nav ms-auto">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a id="nav-user-menu-link" <a id="nav-user-menu-link"
class="nav-link dropdown-toggle" class="nav-link dropdown-toggle"
href="#" href="#"
data-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
<i class="icon-user" aria-hidden="true"></i> <i class="icon-user" aria-hidden="true"></i>
{% firstof user.get_full_name user.get_username %} {% firstof user.get_full_name user.get_username %}
</a> </a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="nav-user-menu-link"> <div class="dropdown-menu dropdown-menu-end" aria-labelledby="nav-user-menu-link">
<h6 class="dropdown-header">{% trans "User" %}</h6> <h6 class="dropdown-header">{% trans "User" %}</h6>
<a href="{% url 'babybuddy:user-settings' %}" class="dropdown-item">{% trans "Settings" %}</a> <a href="{% url 'babybuddy:user-settings' %}"
<a href="{% url 'babybuddy:user-password' %}" class="dropdown-item">{% trans "Password" %}</a> class="dropdown-item">{% trans "Settings" %}</a>
<a href="{% url 'babybuddy:user-password' %}"
class="dropdown-item">{% trans "Password" %}</a>
<a href="{% url 'babybuddy:user-add-device' %}" class="dropdown-item">{% trans "Add a device" %}</a> <a href="{% url 'babybuddy:user-add-device' %}" class="dropdown-item">{% trans "Add a device" %}</a>
<form action="{% url 'babybuddy:logout' %}" role="form" method="post"> <form action="{% url 'babybuddy:logout' %}" role="form" method="post">
{% csrf_token %} {% csrf_token %}
@ -333,8 +336,10 @@
<h6 class="dropdown-header">{% trans "Site" %}</h6> <h6 class="dropdown-header">{% trans "Site" %}</h6>
<a href="{% url 'api:api-root' %}" class="dropdown-item">{% trans "API Browser" %}</a> <a href="{% url 'api:api-root' %}" class="dropdown-item">{% trans "API Browser" %}</a>
{% if request.user.is_staff %} {% if request.user.is_staff %}
<a href="{% url 'babybuddy:user-list' %}" class="dropdown-item">{% trans "Users" %}</a> <a href="{% url 'babybuddy:user-list' %}"
<a href="{% url 'admin:index' %}" class="dropdown-item">{% trans "Database Admin" %}</a> class="dropdown-item">{% trans "Users" %}</a>
<a href="{% url 'admin:index' %}"
class="dropdown-item">{% trans "Database Admin" %}</a>
{% endif %} {% endif %}
<h6 class="dropdown-header">{% trans "Support" %}</h6> <h6 class="dropdown-header">{% trans "Support" %}</h6>
<a href="https://github.com/babybuddy/babybuddy" class="dropdown-item"> <a href="https://github.com/babybuddy/babybuddy" class="dropdown-item">
@ -347,5 +352,6 @@
</ul> </ul>
{% endif %} {% endif %}
</div> </div>
</div>
</nav> </nav>
{% endblock %} {% endblock %}

View File

@ -8,7 +8,7 @@
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% relative_url 'page' page_obj.previous_page_number %}" aria-label="Previous"> <a class="page-link" href="{% relative_url 'page' page_obj.previous_page_number %}" aria-label="Previous">
<i class="icon-angle-circled-left" aria-hidden="true"></i> <i class="icon-angle-circled-left" aria-hidden="true"></i>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
</li> </li>
{% endif %} {% endif %}
@ -25,7 +25,7 @@
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% relative_url 'page' page_obj.next_page_number %}" aria-label="Next"> <a class="page-link" href="{% relative_url 'page' page_obj.next_page_number %}" aria-label="Next">
<i class="icon-angle-circled-right" aria-hidden="true"></i> <i class="icon-angle-circled-right" aria-hidden="true"></i>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
</li> </li>
{% endif %} {% endif %}

View File

@ -12,7 +12,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'babybuddy:user-list' %}">{% trans "Users" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'babybuddy:user-list' %}">{% trans "Users" %}</a></li>
{% if object %} {% if object %}
<li class="breadcrumb-item font-weight-bold">{{ object }}</li> <li class="breadcrumb-item fw-bold">{{ object }}</li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li>
{% else %} {% else %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Create User" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Create User" %}</li>

View File

@ -11,8 +11,8 @@
<h1>Users</h1> <h1>Users</h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-hover user-list"> <table class="table table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "User" %}</th> <th>{% trans "User" %}</th>
<th>{% trans "First Name" %}</th> <th>{% trans "First Name" %}</th>

View File

@ -8,66 +8,76 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="jumbotron"> <div class="px-2 py-5 bg-dark rounded-3">
<h1 class="display-3">{% trans "Welcome to Baby Buddy!" %}</h1> <div class="container-fluid">
<p class="lead"> <h1 class="display-3">{% trans "Welcome to Baby Buddy!" %}</h1>
{% blocktrans trimmed%} <p class="lead">
Learn about and predict baby's needs without (<em>as much</em>) {% blocktrans trimmed%}
guess work by using Baby Buddy to track &mdash; Learn about and predict baby's needs without (<em>as much</em>)
{% endblocktrans %} guess work by using Baby Buddy to track &mdash;
</p> {% endblocktrans %}
<hr class="my-4"> </p>
<div class="card-deck"> <hr class="my-4">
<div class="card card-diaperchange"> <div class="row gy-4">
<div class="card-header text-center"> <div class="col-12 col-md-6 col-lg-3">
<i class="icon-2x icon-diaperchange" aria-hidden="true"></i> <div class="card card-diaperchange">
<div class="card-header text-center">
<i class="icon-2x icon-diaperchange" aria-hidden="true"></i>
</div>
<div class="card-body">
<h3 class="card-title text-center">{% trans "Diaper Changes" %}</h3>
</div>
</div>
</div> </div>
<div class="card-body"> <div class="col-12 col-md-6 col-lg-3">
<h3 class="card-title text-center">{% trans "Diaper Changes" %}</h3> <div class="card card-feeding">
</div> <div class="card-header text-center">
</div> <i class="icon-2x icon-feeding" aria-hidden="true"></i>
<div class="card card-feeding"> </div>
<div class="card-header text-center"> <div class="card-body">
<i class="icon-2x icon-feeding" aria-hidden="true"></i> <h3 class="card-title text-center">{% trans "Feedings" %}</h3>
</div> </div>
<div class="card-body"> </div>
<h3 class="card-title text-center">{% trans "Feedings" %}</h3> </div>
</div> <div class="col-12 col-md-6 col-lg-3">
</div> <div class="card card-sleep">
<div class="card card-sleep"> <div class="card-header text-center">
<div class="card-header text-center"> <i class="icon-2x icon-sleep" aria-hidden="true"></i>
<i class="icon-2x icon-sleep" aria-hidden="true"></i> </div>
</div> <div class="card-body">
<div class="card-body"> <h3 class="card-title text-center">{% trans "Sleep" %}</h3>
<h3 class="card-title text-center">{% trans "Sleep" %}</h3> </div>
</div> </div>
</div> </div>
<div class="card card-tummytime"> <div class="col-12 col-md-6 col-lg-3">
<div class="card-header text-center"> <div class="card card-tummytime">
<i class="icon-2x icon-tummytime" aria-hidden="true"></i> <div class="card-header text-center">
</div> <i class="icon-2x icon-tummytime" aria-hidden="true"></i>
<div class="card-body"> </div>
<h3 class="card-title text-center">{% trans "Tummy Time" %}</h3> <div class="card-body">
<h3 class="card-title text-center">{% trans "Tummy Time" %}</h3>
</div>
</div>
</div> </div>
</div> </div>
<hr class="my-4">
<p class="lead">
{% blocktrans trimmed %}
As the amount of entries grows, Baby Buddy will help parents
and caregivers to identify small patterns in baby's habits
using the dashboard and graphs. Baby Buddy is mobile-friendly
and uses a dark theme to help weary moms and dads with 2AM
feedings and changings. To get started, just click the button
below to add your first (or second, third, etc.) child!
{% endblocktrans %}
</p>
<p class="text-center">
{% if perms.core.add_child %}
<a href="{% url 'core:child-add' %}" class="btn btn-lg btn-success">
<i class="icon-child" aria-hidden="true"></i> {% trans "Add a Child" %}
</a>
{% endif %}
</p>
</div> </div>
<hr class="my-4">
<p class="lead">
{% blocktrans trimmed %}
As the amount of entries grows, Baby Buddy will help parents
and caregivers to identify small patterns in baby's habits
using the dashboard and graphs. Baby Buddy is mobile-friendly
and uses a dark theme to help weary moms and dads with 2AM
feedings and changings. To get started, just click the button
below to add your first (or second, third, etc.) child!
{% endblocktrans %}
</p>
<p class="text-center">
{% if perms.core.add_child %}
<a href="{% url 'core:child-add' %}" class="btn btn-lg btn-success">
<i class="icon-child" aria-hidden="true"></i> {% trans "Add a Child" %}
</a>
{% endif %}
</p>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -10,12 +10,14 @@
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
{{ main }} {{ reason }} {{ main }} {{ reason }}
</div> </div>
<div class="jumbotron"> <div class="px-2 py-5 bg-dark rounded-3">
<h2>{% trans "How to Fix" %}</h2> <div class="container-fluid">
{% blocktrans trimmed with origin=origin %} <h2>{% trans "How to Fix" %}</h2>
Add <samp>{{ origin }}</samp> to the <code>CSRF_TRUSTED_ORIGINS</code> {% blocktrans trimmed with origin=origin %}
environment variable. If multiple origins are required separate Add <samp>{{ origin }}</samp> to the <code>CSRF_TRUSTED_ORIGINS</code>
with commas. environment variable. If multiple origins are required separate
{% endblocktrans %} with commas.
{% endblocktrans %}
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -8,7 +8,7 @@
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col-lg-12 mb-4"> <div class="col-lg-12 mb-4">
<div class="d-sm-flex"> <div class="d-sm-flex">
<img class="d-inline-block align-self-top mr-2 mt-2 text-center" src="{% static "babybuddy/logo/logo-sad.png" %}" width="65" height="65"> <img class="d-inline-block align-self-top me-2 mt-2 text-center" src="{% static "babybuddy/logo/logo-sad.png" %}" width="65" height="65">
<div class="p-2 flex-grow-1"> <div class="p-2 flex-grow-1">
{% block content %}{% endblock %} {% block content %}{% endblock %}
<a href="{% url "babybuddy:root-router" %}" class="btn btn-outline-primary mt-3">{% trans "Return to Baby Buddy" %}</a> <a href="{% url "babybuddy:root-router" %}" class="btn btn-outline-primary mt-3">{% trans "Return to Baby Buddy" %}</a>

View File

@ -7,7 +7,7 @@
<div id="view-{{ request.resolver_match.view_name }}" class="container"> <div id="view-{{ request.resolver_match.view_name }}" class="container">
<div class="text-center pt-3"> <div class="text-center pt-3">
<img src="{% static "babybuddy/logo/icon-brand.png" %}" width="65" height="65" class="d-inline-block align-top" alt=""> <img src="{% static "babybuddy/logo/icon-brand.png" %}" width="65" height="65" class="d-inline-block align-top" alt="">
<h1 class="d-none d-md-inline-block display-4 ml-2"> <h1 class="d-none d-md-inline-block display-4 ms-2">
<span class="text-primary">Baby</span> Buddy <span class="text-primary">Baby</span> Buddy
</h1> </h1>
</a> </a>

View File

@ -8,23 +8,19 @@
<input type="hidden" name="next" value="{{ next }}"> <input type="hidden" name="next" value="{{ next }}">
<label class="sr-only" for="username-input-group"> <label class="visually-hidden" for="username-input-group">
{{ form.username.label }} {{ form.username.label }}
</label> </label>
<div class="input-group mb-3 fade-in"> <div class="input-group mb-3 fade-in">
<div class="input-group-prepend"> <span class="input-group-text text-muted"><i class="icon-user" aria-hidden="true"></i></span>
<span class="input-group-text"><i class="icon-user" aria-hidden="true"></i></span>
</div>
{% render_field form.username name='username' class+='form-control' id='username-input-group' placeholder=form.username.label %} {% render_field form.username name='username' class+='form-control' id='username-input-group' placeholder=form.username.label %}
</div> </div>
<label class="sr-only" for="password-input-group"> <label class="visually-hidden" for="password-input-group">
{{ form.password.label }} {{ form.password.label }}
</label> </label>
<div class="input-group mb-3 fade-in"> <div class="input-group mb-3 fade-in">
<div class="input-group-prepend"> <span class="input-group-text text-muted"><i class="icon-lock" aria-hidden="true"></i></span>
<span class="input-group-text"><i class="icon-lock" aria-hidden="true"></i></span>
</div>
{% render_field form.password name='password' class+='form-control' id='password-input-group' placeholder=form.password.label %} {% render_field form.password name='password' class+='form-control' id='password-input-group' placeholder=form.password.label %}
</div> </div>

View File

@ -22,23 +22,19 @@
<p class="mb-0">{% trans "Enter your new password in each field below." %}</p> <p class="mb-0">{% trans "Enter your new password in each field below." %}</p>
</div> </div>
<label class="sr-only" for="password1-input-group"> <label class="visually-hidden" for="password1-input-group">
{{ form.new_password1.label }} {{ form.new_password1.label }}
</label> </label>
<div class="input-group mb-3 fade-in"> <div class="input-group mb-3 fade-in">
<div class="input-group-prepend"> <span class="input-group-text text-muted"><i class="icon-lock" aria-hidden="true"></i></span>
<span class="input-group-text"><i class="icon-lock" aria-hidden="true"></i></span>
</div>
{% render_field form.new_password1 name='new_password1' class+='form-control' id='password1-input-group' %} {% render_field form.new_password1 name='new_password1' class+='form-control' id='password1-input-group' %}
</div> </div>
<label class="sr-only" for="password2-input-group"> <label class="visually-hidden" for="password2-input-group">
{{ form.new_password2.label }} {{ form.new_password2.label }}
</label> </label>
<div class="input-group mb-3 fade-in"> <div class="input-group mb-3 fade-in">
<div class="input-group-prepend"> <span class="input-group-text text-muted"><i class="icon-lock" aria-hidden="true"></i></span>
<span class="input-group-text"><i class="icon-lock" aria-hidden="true"></i></span>
</div>
{% render_field form.new_password2 name='new_password2' class+='form-control' id='password2-input-group' %} {% render_field form.new_password2 name='new_password2' class+='form-control' id='password2-input-group' %}
</div> </div>

View File

@ -17,13 +17,11 @@
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
<label class="sr-only" for="email-input-group"> <label class="visually-hidden" for="email-input-group">
{{ form.email.label }} {{ form.email.label }}
</label> </label>
<div class="input-group mb-3 fade-in"> <div class="input-group mb-3 fade-in">
<div class="input-group-prepend"> <span class="input-group-text text-muted"><i class="icon-mail" aria-hidden="true"></i></span>
<span class="input-group-text"><i class="icon-mail" aria-hidden="true"></i></span>
</div>
{% render_field form.email name='email' class+='form-control' id='email-input-group' placeholder=form.email.label %} {% render_field form.email name='email' class+='form-control' id='email-input-group' placeholder=form.email.label %}
</div> </div>

View File

@ -100,7 +100,7 @@ class ChildForm(forms.ModelForm):
"birth_date": forms.DateInput( "birth_date": forms.DateInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_date", "data-td-target": "#datetimepicker_date",
} }
), ),
} }
@ -147,7 +147,7 @@ class PumpingForm(CoreModelForm, TaggableModelForm):
"time": forms.DateTimeInput( "time": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_time", "data-td-target": "#datetimepicker_time",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -163,7 +163,7 @@ class DiaperChangeForm(CoreModelForm, TaggableModelForm):
"time": forms.DateTimeInput( "time": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_time", "data-td-target": "#datetimepicker_time",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -179,13 +179,13 @@ class FeedingForm(CoreModelForm, TaggableModelForm):
"start": forms.DateTimeInput( "start": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_start", "data-td-target": "#datetimepicker_start",
} }
), ),
"end": forms.DateTimeInput( "end": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_end", "data-td-target": "#datetimepicker_end",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -201,7 +201,7 @@ class NoteForm(CoreModelForm, TaggableModelForm):
"time": forms.DateTimeInput( "time": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_time", "data-td-target": "#datetimepicker_time",
} }
), ),
} }
@ -216,13 +216,13 @@ class SleepForm(CoreModelForm, TaggableModelForm):
"start": forms.DateTimeInput( "start": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_start", "data-td-target": "#datetimepicker_start",
} }
), ),
"end": forms.DateTimeInput( "end": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_end", "data-td-target": "#datetimepicker_end",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -238,7 +238,7 @@ class TemperatureForm(CoreModelForm, TaggableModelForm):
"time": forms.DateTimeInput( "time": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_time", "data-td-target": "#datetimepicker_time",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -254,7 +254,7 @@ class TimerForm(CoreModelForm):
"start": forms.DateTimeInput( "start": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_start", "data-td-target": "#datetimepicker_start",
} }
), ),
} }
@ -279,13 +279,13 @@ class TummyTimeForm(CoreModelForm, TaggableModelForm):
"start": forms.DateTimeInput( "start": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_start", "data-td-target": "#datetimepicker_start",
} }
), ),
"end": forms.DateTimeInput( "end": forms.DateTimeInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_end", "data-td-target": "#datetimepicker_end",
} }
), ),
} }
@ -300,7 +300,7 @@ class WeightForm(CoreModelForm, TaggableModelForm):
"date": forms.DateInput( "date": forms.DateInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_date", "data-td-target": "#datetimepicker_date",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -316,7 +316,7 @@ class HeightForm(CoreModelForm, TaggableModelForm):
"date": forms.DateInput( "date": forms.DateInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_date", "data-td-target": "#datetimepicker_date",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -332,7 +332,7 @@ class HeadCircumferenceForm(CoreModelForm, TaggableModelForm):
"date": forms.DateInput( "date": forms.DateInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_date", "data-td-target": "#datetimepicker_date",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),
@ -348,7 +348,7 @@ class BMIForm(CoreModelForm, TaggableModelForm):
"date": forms.DateInput( "date": forms.DateInput(
attrs={ attrs={
"autocomplete": "off", "autocomplete": "off",
"data-target": "#datetimepicker_date", "data-td-target": "#datetimepicker_date",
} }
), ),
"notes": forms.Textarea(attrs={"rows": 5}), "notes": forms.Textarea(attrs={"rows": 5}),

View File

@ -0,0 +1,62 @@
# Generated by Django 4.0.4 on 2022-06-10 03:34
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("core", "0025_pumping_tags"),
]
operations = [
migrations.AlterField(
model_name="feeding",
name="end",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="End time"
),
),
migrations.AlterField(
model_name="feeding",
name="start",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="Start time"
),
),
migrations.AlterField(
model_name="pumping",
name="time",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="Time"
),
),
migrations.AlterField(
model_name="sleep",
name="end",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="End time"
),
),
migrations.AlterField(
model_name="sleep",
name="start",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="Start time"
),
),
migrations.AlterField(
model_name="tummytime",
name="end",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="End time"
),
),
migrations.AlterField(
model_name="tummytime",
name="start",
field=models.DateTimeField(
default=django.utils.timezone.localtime, verbose_name="Start time"
),
),
]

View File

@ -273,8 +273,15 @@ class Feeding(models.Model):
related_name="feeding", related_name="feeding",
verbose_name=_("Child"), verbose_name=_("Child"),
) )
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time")) start = models.DateTimeField(
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time")) blank=False,
default=timezone.localtime,
null=False,
verbose_name=_("Start time"),
)
end = models.DateTimeField(
blank=False, default=timezone.localtime, null=False, verbose_name=_("End time")
)
duration = models.DurationField( duration = models.DurationField(
editable=False, null=True, verbose_name=_("Duration") editable=False, null=True, verbose_name=_("Duration")
) )
@ -426,7 +433,9 @@ class Pumping(models.Model):
verbose_name=_("Child"), verbose_name=_("Child"),
) )
amount = models.FloatField(blank=False, null=False, verbose_name=_("Amount")) amount = models.FloatField(blank=False, null=False, verbose_name=_("Amount"))
time = models.DateTimeField(blank=False, null=False, verbose_name=_("Time")) time = models.DateTimeField(
blank=False, default=timezone.localtime, null=False, verbose_name=_("Time")
)
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes")) notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
tags = TaggableManager(blank=True, through=Tagged) tags = TaggableManager(blank=True, through=Tagged)
@ -451,8 +460,15 @@ class Sleep(models.Model):
"Child", on_delete=models.CASCADE, related_name="sleep", verbose_name=_("Child") "Child", on_delete=models.CASCADE, related_name="sleep", verbose_name=_("Child")
) )
napping = models.BooleanField(editable=False, null=True, verbose_name=_("Napping")) napping = models.BooleanField(editable=False, null=True, verbose_name=_("Napping"))
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time")) start = models.DateTimeField(
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time")) blank=False,
default=timezone.localtime,
null=False,
verbose_name=_("Start time"),
)
end = models.DateTimeField(
blank=False, default=timezone.localtime, null=False, verbose_name=_("End time")
)
duration = models.DurationField( duration = models.DurationField(
editable=False, null=True, verbose_name=_("Duration") editable=False, null=True, verbose_name=_("Duration")
) )
@ -630,8 +646,15 @@ class TummyTime(models.Model):
related_name="tummy_time", related_name="tummy_time",
verbose_name=_("Child"), verbose_name=_("Child"),
) )
start = models.DateTimeField(blank=False, null=False, verbose_name=_("Start time")) start = models.DateTimeField(
end = models.DateTimeField(blank=False, null=False, verbose_name=_("End time")) blank=False,
default=timezone.localtime,
null=False,
verbose_name=_("Start time"),
)
end = models.DateTimeField(
blank=False, default=timezone.localtime, null=False, verbose_name=_("End time")
)
duration = models.DurationField( duration = models.DurationField(
editable=False, null=True, verbose_name=_("Duration") editable=False, null=True, verbose_name=_("Duration")
) )

View File

@ -4,21 +4,6 @@
} }
} }
#view-core\:child-list {
.picture-column {
text-align: center;
width: 65px;
min-width: 65px;
}
.child-list {
th,
td {
vertical-align: middle;
}
}
}
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
#view-core\:child { #view-core\:child {
.child-detail-column { .child-detail-column {

View File

@ -1,3 +1,5 @@
@use 'sass:map';
// Adapted for Bootstrap 4 from https://www.bootply.com/SzXin8KDZJ. // Adapted for Bootstrap 4 from https://www.bootply.com/SzXin8KDZJ.
$card-shadow: rgba(0, 0, 0, .175); $card-shadow: rgba(0, 0, 0, .175);
@ -12,7 +14,7 @@ $card-shadow: rgba(0, 0, 0, .175);
position: absolute; position: absolute;
content: ' '; content: ' ';
width: 3px; width: 3px;
background-color: theme-color('primary'); background-color: map.get($theme-colors, 'primary');
left: 50%; left: 50%;
margin-left: -1.5px; margin-left: -1.5px;
@ -34,7 +36,7 @@ $card-shadow: rgba(0, 0, 0, .175);
} }
.card { .card {
width: 47%; width: 46%;
float: left; float: left;
position: relative; position: relative;
box-shadow: 0 1px 6px $card-shadow; box-shadow: 0 1px 6px $card-shadow;
@ -45,8 +47,8 @@ $card-shadow: rgba(0, 0, 0, .175);
right: -15px; right: -15px;
display: inline-block; display: inline-block;
border-top: 15px solid transparent; border-top: 15px solid transparent;
border-left: 15px solid theme-color('dark'); border-left: 15px solid map.get($theme-colors, 'dark');
border-right: 0 solid theme-color('dark'); border-right: 0 solid map.get($theme-colors, 'dark');
border-bottom: 15px solid transparent; border-bottom: 15px solid transparent;
content: ' '; content: ' ';
} }
@ -57,8 +59,8 @@ $card-shadow: rgba(0, 0, 0, .175);
right: -14px; right: -14px;
display: inline-block; display: inline-block;
border-top: 14px solid transparent; border-top: 14px solid transparent;
border-left: 14px solid theme-color('dark'); border-left: 14px solid map.get($theme-colors, 'dark');
border-right: 0 solid theme-color('dark'); border-right: 0 solid map.get($theme-colors, 'dark');
border-bottom: 14px solid transparent; border-bottom: 14px solid transparent;
content: ' '; content: ' ';
} }
@ -95,7 +97,7 @@ $card-shadow: rgba(0, 0, 0, .175);
top: 16px; top: 16px;
left: 50%; left: 50%;
margin-left: -25px; margin-left: -25px;
background-color: theme-color('dark'); background-color: map.get($theme-colors, 'dark');
z-index: 100; z-index: 100;
border-radius: 50%; border-radius: 50%;
@ -110,7 +112,7 @@ $card-shadow: rgba(0, 0, 0, .175);
top: 26px; top: 26px;
left: 50%; left: 50%;
margin-left: -25px; margin-left: -25px;
background-color: theme-color('dark'); background-color: map.get($theme-colors, 'dark');
z-index: 100; z-index: 100;
border-radius: 50%; border-radius: 50%;
} }

View File

@ -1,16 +1,7 @@
@use 'sass:map';
#timer-status { #timer-status {
font-size: $h1-font-size;
font-weight: $display1-weight;
&.timer-stopped { &.timer-stopped {
color: theme-color('danger'); color: map.get($theme-colors, 'dark');
}
}
@include media-breakpoint-up(sm) {
#view-core\:timer-detail {
#timer-status {
font-size: $display1-size;
}
} }
} }

View File

@ -31,9 +31,14 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_date'), { BabyBuddy.DatetimePicker.init(document.querySelector('#datetimepicker_date'), {
format: 'L', display: {
extraFormats: ['YYYY-MM-DD'] components: {
hours: false,
minutes: false,
seconds: false,
}
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for bmi in object_list %} {% for bmi in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if bmi.notes %} {% if bmi.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="5"><i class="icon-note mr-2" aria-hidden="true"></i>{{ bmi.notes }}</td> <td colspan="5"><i class="icon-note me-2" aria-hidden="true"></i>{{ bmi.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -5,7 +5,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li>
<li class="breadcrumb-item font-weight-bold"><a href="{% url 'core:child' object.slug %}">{{ object }}</a></li> <li class="breadcrumb-item fw-bold"><a href="{% url 'core:child' object.slug %}">{{ object }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Delete" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Delete" %}</li>
{% endblock %} {% endblock %}

View File

@ -5,7 +5,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li>
<li class="breadcrumb-item font-weight-bold"> <li class="breadcrumb-item fw-bold">
{% child_quick_switch object 'core:child' %} {% child_quick_switch object 'core:child' %}
</li> </li>
{% endblock %} {% endblock %}

View File

@ -12,7 +12,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li>
{% if object %} {% if object %}
<li class="breadcrumb-item font-weight-bold"><a href="{% url 'core:child' object.slug %}">{{ object }}</a></li> <li class="breadcrumb-item fw-bold"><a href="{% url 'core:child' object.slug %}">{{ object }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li>
{% else %} {% else %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Add a Child" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Add a Child" %}</li>
@ -32,10 +32,15 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_birth_date'), { BabyBuddy.DatetimePicker.init(document.querySelector('#datetimepicker_birth_date'), {
format: 'L', display: {
viewMode: 'years', components: {
extraFormats: ['YYYY-MM-DD'] hours: false,
minutes: false,
seconds: false,
},
viewMode: 'years'
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,10 +18,10 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-hover child-list"> <table class="table table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th class="picture-column"><i class="icon-camera" aria-hidden="true"></i></th> <th><i class="icon-camera" aria-hidden="true"></i></th>
<th>{% trans "First Name" %}</th> <th>{% trans "First Name" %}</th>
<th>{% trans "Last Name" %}</th> <th>{% trans "Last Name" %}</th>
<th>{% trans "Birth Date" %}</th> <th>{% trans "Birth Date" %}</th>
@ -31,8 +31,12 @@
<tbody> <tbody>
{% for child in object_list %} {% for child in object_list %}
<tr> <tr>
<td class="picture-column"> <td>
{% include "core/child_thumbnail.html" %} {% if child.picture %}
{% include "core/child_thumbnail.html" %}
{% else %}
<img src="{% static 'babybuddy/img/core/child-placeholder.png' %}" width="40" height="40" class="img-fluid rounded-circle" />
{% endif %}
</td> </td>
<th scope="row"> <th scope="row">
<a href="{% url 'core:child' child.slug %}">{{ child.first_name }}</a> <a href="{% url 'core:child' child.slug %}">{{ child.first_name }}</a>

View File

@ -31,8 +31,6 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_time'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_time'));
format: '{% datetimepicker_format %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Time" %}</th> <th>{% trans "Time" %}</th>
@ -34,8 +34,7 @@
</thead> </thead>
<tbody> <tbody>
{% for change in object_list %} {% for change in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -69,7 +68,7 @@
</tr> </tr>
{% if change.notes %} {% if change.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="7"><i class="icon-note mr-2" aria-hidden="true"></i>{{ change.notes }}</td> <td colspan="7"><i class="icon-note me-2" aria-hidden="true"></i>{{ change.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,12 +31,8 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_start'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_start'));
format: '{% datetimepicker_format %}' BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_end'));
});
BabyBuddy.DatetimePicker.init($('#datetimepicker_end'), {
format: '{% datetimepicker_format %}'
});
$('#id_type').change(function() { $('#id_type').change(function() {
var feed_type=$('#id_type').val(); var feed_type=$('#id_type').val();
if (feed_type === 'formula' || feed_type === 'fortified breast milk') { if (feed_type === 'formula' || feed_type === 'fortified breast milk') {

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
@ -36,8 +36,7 @@
</thead> </thead>
<tbody> <tbody>
{% for feeding in object_list %} {% for feeding in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -73,7 +72,7 @@
</tr> </tr>
{% if feeding.notes %} {% if feeding.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="8"><i class="icon-note mr-2" aria-hidden="true"></i>{{ feeding.notes }}</td> <td colspan="8"><i class="icon-note me-2" aria-hidden="true"></i>{{ feeding.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,9 +31,14 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_date'), { BabyBuddy.DatetimePicker.init(document.querySelector('#datetimepicker_date'), {
format: 'L', display: {
extraFormats: ['YYYY-MM-DD'] components: {
hours: false,
minutes: false,
seconds: false,
}
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for head_circumference in object_list %} {% for head_circumference in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if head_circumference.notes %} {% if head_circumference.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="5"><i class="icon-note mr-2" aria-hidden="true"></i>{{ head_circumference.notes }}</td> <td colspan="5"><i class="icon-note me-2" aria-hidden="true"></i>{{ head_circumference.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,9 +31,14 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_date'), { BabyBuddy.DatetimePicker.init(document.querySelector('#datetimepicker_date'), {
format: 'L', display: {
extraFormats: ['YYYY-MM-DD'] components: {
hours: false,
minutes: false,
seconds: false,
}
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for height in object_list %} {% for height in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if height.notes %} {% if height.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="5"><i class="icon-note mr-2" aria-hidden="true"></i>{{ height.notes }}</td> <td colspan="5"><i class="icon-note me-2" aria-hidden="true"></i>{{ height.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,8 +31,6 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_time'), { BabyBuddy.DatetimePicker.init(document.getElementById('#datetimepicker_time'));
format: '{% datetimepicker_format %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Time" %}</th> <th>{% trans "Time" %}</th>

View File

@ -31,8 +31,6 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_time'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_time'));
format: '{% datetimepicker_format %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Time" %}</th> <th>{% trans "Time" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for pumping in object_list %} {% for pumping in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if pumping.notes %} {% if pumping.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="4"><i class="icon-note mr-2" aria-hidden="true"></i>{{ pumping.notes }}</td> <td colspan="4"><i class="icon-note me-2" aria-hidden="true"></i>{{ pumping.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,12 +31,7 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_start'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_start'));
defaultDate: false, BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_end'));
format: '{% datetimepicker_format %}'
});
BabyBuddy.DatetimePicker.init($('#datetimepicker_end'), {
format: '{% datetimepicker_format %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Start" %}</th> <th>{% trans "Start" %}</th>
@ -34,8 +34,7 @@
</thead> </thead>
<tbody> <tbody>
{% for sleep in object_list %} {% for sleep in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -66,7 +65,7 @@
</tr> </tr>
{% if sleep.notes %} {% if sleep.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="7"><i class="icon-note mr-2" aria-hidden="true"></i>{{ sleep.notes }}</td> <td colspan="7"><i class="icon-note me-2" aria-hidden="true"></i>{{ sleep.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -31,8 +31,6 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_time'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_time'));
format: '{% datetimepicker_format %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Time" %}</th> <th>{% trans "Time" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for temperature in object_list %} {% for temperature in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if temperature.notes %} {% if temperature.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="5"><i class="icon-note mr-2" aria-hidden="true"></i>{{ temperature.notes }}</td> <td colspan="5"><i class="icon-note me-2" aria-hidden="true"></i>{{ temperature.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -7,7 +7,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li>
<li class="breadcrumb-item font-weight-bold"><a href="{% url 'core:timer-detail' object.id %}">{{ object }}</a></li> <li class="breadcrumb-item fw-bold"><a href="{% url 'core:timer-detail' object.id %}">{{ object }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Delete" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Delete" %}</li>
{% endblock %} {% endblock %}

View File

@ -6,86 +6,90 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li>
<li class="breadcrumb-item font-weight-bold">{{ object }}</li> <li class="breadcrumb-item fw-bold">{{ object }}</li>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="jumbotron text-center"> <div class="p-5 mb-4 bg-dark rounded-3 text-center">
<div class="container-fluid py-1">
<h1 id="timer-status"
class="display-1 {% if not object.active %} timer-stopped{% endif %}">
<span class="timer-hours">{{ object.duration|hours }}</span>h
<span class="timer-minutes">{{ object.duration|minutes }}</span>m
<span class="timer-seconds">{{ object.duration|seconds }}</span>s
</h1>
<h1 {% if not object.active %}class="timer-stopped" {% endif %}id="timer-status"> {% if timer.child and CHILD_COUNT > 1 %}
<span class="timer-hours">{{ object.duration|hours }}</span>h <h2 class="text-muted">
<span class="timer-minutes">{{ object.duration|minutes }}</span>m {{ timer.child }}
<span class="timer-seconds">{{ object.duration|seconds }}</span>s </h2>
</h1>
{% if timer.child and CHILD_COUNT > 1 %}
<h2 class="text-muted">
{{ timer.child }}
</h2>
{% endif %}
<p class="lead text-secondary">
{% trans "Started" %} {{ object.start }}
{% if not object.active %}
/ {% trans "Stopped" %} {{ object.end }}
{% endif %}
</p>
<p class="text-muted">
{% blocktrans trimmed with user=object.user_username %}
{{ timer }} created by {{ user }}
{% endblocktrans %}
</p>
{% if perms.core.add_feeding %}
<a class="btn btn-success btn-lg btn-block mb-3"
href="{% instance_add_url 'core:feeding-add' %}"
role="button"><i class="icon-feeding" aria-hidden="true"></i>
{% trans "Feeding" %}
</a>
{% endif %}
{% if perms.core.add_sleep %}
<a class="btn btn-success btn-lg btn-block mb-3"
href="{% instance_add_url 'core:sleep-add' %}"
role="button"><i class="icon-sleep" aria-hidden="true"></i>
{% trans "Sleep" %}
</a>
{% endif %}
{% if perms.core.add_tummytime %}
<a class="btn btn-success btn-lg btn-block mb-3"
href="{% instance_add_url 'core:tummytime-add' %}"
role="button"><i class="icon-tummytime" aria-hidden="true"></i>
{% trans "Tummy Time" %}
</a>
{% endif %}
<div class="center-block" role="group" aria-label="{% trans "Timer actions" %}">
{% if perms.core.delete_timer %}
<a class="btn btn-lg btn-danger"
href="{% url 'core:timer-delete' timer.id %}"
role="button"><i class="icon-delete" aria-hidden="true"></i></a>
{% endif %} {% endif %}
{% if perms.core.change_timer %} <p class="lead text-secondary">
<a class="btn btn-lg btn-primary" {% trans "Started" %} {{ object.start }}
href="{% url 'core:timer-update' timer.id %}" {% if not object.active %}
role="button"><i class="icon-update" aria-hidden="true"></i></a> / {% trans "Stopped" %} {{ object.end }}
<form action="{% url 'core:timer-restart' timer.id %}" role="form" method="post" class="d-inline">
{% csrf_token %}
<label class="sr-only">{% trans "Restart timer" %}</label>
<button type="submit" class="btn btn-lg btn-secondary"><i class="icon-refresh" aria-hidden="true"></i></button>
</form>
{% if object.active %}
<form action="{% url 'core:timer-stop' timer.id %}" role="form" method="post" class="d-inline">
{% csrf_token %}
<label class="sr-only">{% trans "Delete timer" %}</label>
<button type="submit" class="btn btn-lg btn-warning"><i class="icon-stop" aria-hidden="true"></i></button>
</form>
{% endif %} {% endif %}
{% endif %} </p>
<p class="text-muted">
{% blocktrans trimmed with user=object.user_username %}
{{ timer }} created by {{ user }}
{% endblocktrans %}
</p>
<div class="d-grid gap-4 mb-4">
{% if perms.core.add_feeding %}
<a class="btn btn-success btn-lg"
href="{% instance_add_url 'core:feeding-add' %}"
role="button"><i class="icon-feeding" aria-hidden="true"></i>
{% trans "Feeding" %}
</a>
{% endif %}
{% if perms.core.add_sleep %}
<a class="btn btn-success btn-lg"
href="{% instance_add_url 'core:sleep-add' %}"
role="button"><i class="icon-sleep" aria-hidden="true"></i>
{% trans "Sleep" %}
</a>
{% endif %}
{% if perms.core.add_tummytime %}
<a class="btn btn-success btn-lg"
href="{% instance_add_url 'core:tummytime-add' %}"
role="button"><i class="icon-tummytime" aria-hidden="true"></i>
{% trans "Tummy Time" %}
</a>
{% endif %}
</div>
<div class="center-block" role="group" aria-label="{% trans "Timer actions" %}">
{% if perms.core.delete_timer %}
<a class="btn btn-lg btn-danger"
href="{% url 'core:timer-delete' timer.id %}"
role="button"><i class="icon-delete" aria-hidden="true"></i></a>
{% endif %}
{% if perms.core.change_timer %}
<a class="btn btn-lg btn-primary"
href="{% url 'core:timer-update' timer.id %}"
role="button"><i class="icon-update" aria-hidden="true"></i></a>
<form action="{% url 'core:timer-restart' timer.id %}" role="form" method="post" class="d-inline">
{% csrf_token %}
<label class="visually-hidden">{% trans "Restart timer" %}</label>
<button type="submit" class="btn btn-lg btn-secondary"><i class="icon-refresh" aria-hidden="true"></i></button>
</form>
{% if object.active %}
<form action="{% url 'core:timer-stop' timer.id %}" role="form" method="post" class="d-inline">
{% csrf_token %}
<label class="visually-hidden">{% trans "Delete timer" %}</label>
<button type="submit" class="btn btn-lg btn-warning"><i class="icon-stop" aria-hidden="true"></i></button>
</form>
{% endif %}
{% endif %}
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,7 +6,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:timer-list' %}">{% trans "Timers" %}</a></li>
{% if object %} {% if object %}
<li class="breadcrumb-item font-weight-bold"><a href="{% url 'core:timer-detail' object.id %}">{{ object }}</a></li> <li class="breadcrumb-item fw-bold"><a href="{% url 'core:timer-detail' object.id %}">{{ object }}</a></li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Update" %}</li>
{% else %} {% else %}
<li class="breadcrumb-item active" aria-current="page">{% trans "Start" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Start" %}</li>
@ -26,8 +26,6 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_start'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_start'));
format: '{% datetimepicker_format 'L LTS' %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Start" %}</th> <th>{% trans "Start" %}</th>
<th>{% trans "Name" %}</th> <th>{% trans "Name" %}</th>

View File

@ -4,13 +4,21 @@
<a id="nav-timer-menu-link" <a id="nav-timer-menu-link"
class="nav-link dropdown-toggle" class="nav-link dropdown-toggle"
href="#" href="#"
data-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"><i class="icon-timer" aria-hidden="true"></i> aria-expanded="false"><i class="icon-timer" aria-hidden="true"></i>
{% trans "Timers" %} {% trans "Timers" %}
</a> </a>
<div class="dropdown-menu" aria-labelledby="nav-timer-menu-link"> <div class="dropdown-menu" aria-labelledby="nav-timer-menu-link">
{% if perms.core.add_timer %} {% if perms.core.add_timer %}
<div class="dropdown-item">
<form action="{% url 'core:timer-add-quick' %}" role="form" method="post" class="d-inline">
{% csrf_token %}
<button class="btn text-start p-0">
<i class="icon-timer" aria-hidden="true"></i> {% trans "Quick Start Timer" %}
</button>
</form>
</div>
<a class="dropdown-item" href="{% url 'core:timer-add' %}"> <a class="dropdown-item" href="{% url 'core:timer-add' %}">
<i class="icon-add" aria-hidden="true"></i> {% trans "Start Timer" %} <i class="icon-add" aria-hidden="true"></i> {% trans "Start Timer" %}
</a> </a>

View File

@ -31,12 +31,7 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_start'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_start'));
defaultDate: false, BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_end'));
format: '{% datetimepicker_format 'L LTS' %}'
});
BabyBuddy.DatetimePicker.init($('#datetimepicker_end'), {
format: '{% datetimepicker_format 'L LTS' %}'
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -17,8 +17,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Start" %}</th> <th>{% trans "Start" %}</th>

View File

@ -31,9 +31,14 @@
{% block javascript %} {% block javascript %}
<script type="text/javascript"> <script type="text/javascript">
BabyBuddy.DatetimePicker.init($('#datetimepicker_date'), { BabyBuddy.DatetimePicker.init(document.getElementById('datetimepicker_date'), {
format: 'L', display: {
extraFormats: ['YYYY-MM-DD'] components: {
hours: false,
minutes: false,
seconds: false,
}
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,8 +18,8 @@
</h1> </h1>
{% include 'babybuddy/filter.html' %} {% include 'babybuddy/filter.html' %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-instances table-striped table-hover"> <table class="table table-instances table-borderless table-striped table-hover align-middle">
<thead class="thead-inverse"> <thead>
<tr> <tr>
<th>{% trans "Actions" %}</th> <th>{% trans "Actions" %}</th>
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
@ -32,8 +32,7 @@
</thead> </thead>
<tbody> <tbody>
{% for weight in object_list %} {% for weight in object_list %}
{% cycle "odd" "even" as row_class silent %} <tr>
<tr class="{{ row_class }}">
<td> <td>
<div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}"> <div class="btn-group btn-group-sm" role="group" aria-label="{% trans "Actions" %}">
@ -62,7 +61,7 @@
</tr> </tr>
{% if weight.notes %} {% if weight.notes %}
<tr class="{{ row_class }} row-details"> <tr class="{{ row_class }} row-details">
<td colspan="5"><i class="icon-note mr-2" aria-hidden="true"></i>{{ weight.notes }}</td> <td colspan="5"><i class="icon-note me-2" aria-hidden="true"></i>{{ weight.notes }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% empty %} {% empty %}

View File

@ -5,39 +5,31 @@
{{ k }}="{{ v }}" {{ k }}="{{ v }}"
{% endfor %}> {% endfor %}>
{% csrf_token %} {% csrf_token %}
<span class="prototype-tag btn badge badge-pill cursor-pointer mr-1" style="display: none;"> <span class="prototype-tag btn badge badge-pill cursor-pointer me-1" style="display: none;">
UNINITIALIZED PROTOTYPE UNINITIALIZED PROTOTYPE
<span class="add-remove-icon pl-1 pr-1">+ or -</span> <span class="add-remove-icon ps-1 pe-1">+ or -</span>
</span> </span>
<div class="current_tags" style="min-height: 2em;"> <div class="current_tags" style="min-height: 2em;">
{% for t in widget.value %} {% for t in widget.value %}
<span data-value="{{ t.name }}" data-color="{{ t.color }}" class="tag btn badge badge-pill cursor-pointer mr-1" style="background-color: {{ t.color }};"> <span data-value="{{ t.name }}" data-color="{{ t.color }}" class="tag btn badge badge-pill cursor-pointer me-1" style="background-color: {{ t.color }};">
{{ t.name }} {{ t.name }}
<span class="add-remove-icon pl-1 pr-1">-</span> <span class="add-remove-icon ps-1 pe-1">-</span>
</span> </span>
{% endfor %} {% endfor %}
</div> </div>
<div class="new-tags"> <div class="new-tags">
<div class="create-tag-inputs input-group"> <div class="create-tag-inputs input-group">
<input class="form-control" type="text" name="" placeholder="{% trans "Tag name" %}"> <input class="form-control" type="text" name="" placeholder="{% trans "Tag name" %}">
<div class="input-group-append"> <button id="add-tag" class="btn btn-outline-primary bg-dark" type="button">{% trans "Add" %}</button>
<button class="btn btn-outline-primary bg-dark btn-add-new-tag" type="button">{% trans "Add" %}</button>
</div>
</div> </div>
{% if widget.tag_suggestions.quick %} {% if widget.tag_suggestions.quick %}
<span>{% trans "Recently used:" %}</span> <span>{% trans "Recently used:" %}</span>
{% for t in widget.tag_suggestions.quick %} {% for t in widget.tag_suggestions.quick %}
<span data-value="{{ t.name }}" data-color="{{ t.color }}" class="tag btn badge badge-pill cursor-pointer mr-1" style="background-color: {{ t.color }};"> <span data-value="{{ t.name }}" data-color="{{ t.color }}" class="tag btn badge badge-pill cursor-pointer me-1" style="background-color: {{ t.color }};">
{{ t.name }} {{ t.name }}
<span class="add-remove-icon pl-1 pr-1">+</span> <span class="add-remove-icon ps-1 pe-1">+</span>
</span> </span>
{% endfor %} {% endfor %}
{% else %}
<style>
.help-block{
display: none;
}
</style>
{%endif%} {%endif%}
</div> </div>
<input <input
@ -51,7 +43,7 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title">{% trans "Error" context "Error modal" %}</h4> <h4 class="modal-title">{% trans "Error" context "Error modal" %}</h4>
<button type="button" class="close" data-dismiss="modal">&times;</button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -62,7 +54,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"> <button type="button" class="btn btn-danger" data-bs-dismiss="modal">
{% trans "Close" context "Error modal" %} {% trans "Close" context "Error modal" %}
</button> </button>
</div> </div>

View File

@ -4,14 +4,14 @@
{% if date_previous %} {% if date_previous %}
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}"> <a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
<i class="icon-2x icon-angle-circled-left" aria-hidden="true"></i> <i class="icon-2x icon-angle-circled-left" aria-hidden="true"></i>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
{% endif %} {% endif %}
{{ date|date }} {{ date|date }}
{% if date_next %} {% if date_next %}
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}"> <a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
<i class="icon-2x icon-angle-circled-right" aria-hidden="true"></i> <i class="icon-2x icon-angle-circled-right" aria-hidden="true"></i>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
{% endif %} {% endif %}
</h3> </h3>
@ -22,7 +22,7 @@
<div class="timeline-badge {% if object.type == "start" %}bg-success{% elif object.type == "end" %}bg-danger{% else %}bg-info{% endif %}"> <div class="timeline-badge {% if object.type == "start" %}bg-success{% elif object.type == "end" %}bg-danger{% else %}bg-info{% endif %}">
<i class="icon-{{ object.model_name }}"></i> <i class="icon-{{ object.model_name }}"></i>
</div> </div>
<div class="card text-right"> <div class="card text-end">
<div class="card-body"> <div class="card-body">
{{ object.event }} {{ object.event }}
{% for detail in object.details %} {% for detail in object.details %}
@ -70,14 +70,14 @@
{% if date_previous %} {% if date_previous %}
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}"> <a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
<i class="icon-2x icon-angle-circled-left" aria-hidden="true"></i> <i class="icon-2x icon-angle-circled-left" aria-hidden="true"></i>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
{% endif %} {% endif %}
{{ date|date }} {{ date|date }}
{% if date_next %} {% if date_next %}
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}"> <a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
<i class="icon-2x icon-angle-circled-right" aria-hidden="true"></i> <i class="icon-2x icon-angle-circled-right" aria-hidden="true"></i>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
{% endif %} {% endif %}
</h3> </h3>

View File

@ -4,7 +4,7 @@
{% block title %}{% trans "Timeline" %}{% endblock %} {% block title %}{% trans "Timeline" %}{% endblock %}
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item font-weight-bold">{% trans "Timeline" %}</li> <li class="breadcrumb-item fw-bold">{% trans "Timeline" %}</li>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -1,3 +1,5 @@
@use 'sass:map';
%card-header-text { %card-header-text {
font-size: $h4-font-size; font-size: $h4-font-size;
font-weight: $headings-font-weight; font-weight: $headings-font-weight;
@ -29,18 +31,24 @@
padding-right: $card-spacer-x; padding-right: $card-spacer-x;
} }
} }
.list-group {
.list-group-item {
color: $white;
}
}
} }
.card-diaperchange { .card-diaperchange {
border-color: theme-color('danger'); border-color: map.get($theme-colors, 'danger');
.card-header, .card-header a { .card-header, .card-header a {
background-color: theme-color('danger'); background-color: map.get($theme-colors, 'danger');
color: theme-color('light'); color: map.get($theme-colors, 'light');
} }
.card-body { .card-body {
color: theme-color('danger'); color: map.get($theme-colors, 'danger');
} }
.progress { .progress {
@ -50,15 +58,15 @@
.card-feeding, .card-feeding,
.card-pumping { .card-pumping {
border-color: theme-color('primary'); border-color: map.get($theme-colors, 'primary');
.card-header, .card-header a { .card-header, .card-header a {
background-color: theme-color('primary'); background-color: map.get($theme-colors, 'primary');
color: theme-color('light'); color: map.get($theme-colors, 'light');
} }
.card-body { .card-body {
color: theme-color('primary'); color: map.get($theme-colors, 'primary');
// Last feeding method header in card. // Last feeding method header in card.
.last-feeding-method { .last-feeding-method {
@ -68,28 +76,28 @@
} }
.card-sleep { .card-sleep {
border-color: theme-color('secondary'); border-color: map.get($theme-colors, 'secondary');
.card-header, .card-header a { .card-header, .card-header a {
background-color: theme-color('secondary'); background-color: map.get($theme-colors, 'secondary');
color: theme-color('light'); color: map.get($theme-colors, 'light');
} }
} }
.card-statistics, .card-timer { .card-statistics, .card-timer {
border-color: theme-color('light'); border-color: map.get($theme-colors, 'light');
.card-header { .card-header {
background-color: theme-color('light'); background-color: map.get($theme-colors, 'light');
color: theme-color('dark'); color: map.get($theme-colors, 'dark');
a { a {
color: theme-color('dark'); color: map.get($theme-colors, 'dark');
} }
} }
.card-body { .card-body {
color: theme-color('light'); color: map.get($theme-colors, 'light');
.container { .container {
padding: 0; padding: 0;
@ -98,14 +106,14 @@
} }
.card-tummytime { .card-tummytime {
border-color: theme-color('success'); border-color: map.get($theme-colors, 'success');
.card-header, .card-header a { .card-header, .card-header a {
background-color: theme-color('success'); background-color: map.get($theme-colors, 'success');
color: theme-color('light'); color: map.get($theme-colors, 'light');
} }
.card-body { .card-body {
color: theme-color('success'); color: map.get($theme-colors, 'success');
} }
} }

View File

@ -1,11 +1,3 @@
.child-actions { .child-actions {
flex-wrap: wrap; flex-wrap: wrap;
} }
@include media-breakpoint-between(sm, md) {
#dashboard-child {
&.card-columns {
column-count: 2;
}
}
}

View File

@ -9,7 +9,7 @@
{% block title %} {% block title %}
{% if feedings|length > 0 %} {% if feedings|length > 0 %}
<div id="feeding-days-carousel" class="carousel slide" data-interval="false"> <div id="feeding-days-carousel" class="carousel slide" data-bs-interval="false">
<div class="carousel-inner"> <div class="carousel-inner">
{% for feeding in feedings %} {% for feeding in feedings %}
<div class="carousel-item{% if forloop.counter == 1 %} active{% endif %}"> <div class="carousel-item{% if forloop.counter == 1 %} active{% endif %}">
@ -38,13 +38,19 @@
{% endfor %} {% endfor %}
</div> </div>
{% if feedings|length > 1 %} {% if feedings|length > 1 %}
<a class="carousel-control-prev" href="#feeding-days-carousel" role="button" data-slide="prev"> <a class="carousel-control-prev"
href="#feeding-days-carousel"
role="button"
data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
<a class="carousel-control-next" href="#feeding-days-carousel" role="button" data-slide="next"> <a class="carousel-control-next"
href="#feeding-days-carousel"
role="button"
data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
{% endif %} {% endif %}
</div> </div>

View File

@ -9,7 +9,7 @@
{% block title %} {% block title %}
{% if feedings|length > 0 %} {% if feedings|length > 0 %}
<div id="feeding-methods-carousel" class="carousel slide" data-interval="false"> <div id="feeding-methods-carousel" class="carousel slide" data-bs-interval="false">
<div class="carousel-inner"> <div class="carousel-inner">
{% for feeding in feedings %} {% for feeding in feedings %}
<div class="carousel-item{% if forloop.counter == feedings|length %} active{% endif %}"> <div class="carousel-item{% if forloop.counter == feedings|length %} active{% endif %}">
@ -29,13 +29,19 @@
{% endfor %} {% endfor %}
</div> </div>
{% if feedings|length > 1 %} {% if feedings|length > 1 %}
<a class="carousel-control-prev" href="#feeding-methods-carousel" role="button" data-slide="prev"> <a class="carousel-control-prev"
href="#feeding-methods-carousel"
role="button"
data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
<a class="carousel-control-next" href="#feeding-methods-carousel" role="button" data-slide="next"> <a class="carousel-control-next"
href="#feeding-methods-carousel"
role="button"
data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
{% endif %} {% endif %}
</div> </div>

View File

@ -8,7 +8,7 @@
</div> </div>
<div class="card-body text-center"> <div class="card-body text-center">
{% if stats|length > 0 %} {% if stats|length > 0 %}
<div id="statistics-carousel" class="carousel slide" data-interval="false"> <div id="statistics-carousel" class="carousel slide" data-bs-interval="false">
<div class="carousel-inner"> <div class="carousel-inner">
{% for stat in stats %} {% for stat in stats %}
<div class="carousel-item{% if forloop.counter == 1 %} active{% endif %}"> <div class="carousel-item{% if forloop.counter == 1 %} active{% endif %}">
@ -29,13 +29,19 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<a class="carousel-control-prev" href="#statistics-carousel" role="button" data-slide="prev"> <a class="carousel-control-prev"
href="#statistics-carousel"
role="button"
data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Previous" %}</span> <span class="visually-hidden">{% trans "Previous" %}</span>
</a> </a>
<a class="carousel-control-next" href="#statistics-carousel" role="button" data-slide="next"> <a class="carousel-control-next"
href="#statistics-carousel"
role="button"
data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Next" %}</span> <span class="visually-hidden">{% trans "Next" %}</span>
</a> </a>
</div> </div>
{% else %} {% else %}

View File

@ -5,26 +5,50 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li>
<li class="breadcrumb-item font-weight-bold"> <li class="breadcrumb-item fw-bold">
{% child_quick_switch object 'dashboard:dashboard-child' %} {% child_quick_switch object 'dashboard:dashboard-child' %}
</li> </li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Dashboard" %}</li> <li class="breadcrumb-item active" aria-current="page">{% trans "Dashboard" %}</li>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="dashboard-child" class="card-columns"> <div id="dashboard-child" class="row" data-masonry='{"percentPosition": true }'>
{% card_timer_list object %} <div class="col-sm-6 col-lg-4">
{% card_feeding_last object %} {% card_timer_list object %}
{% card_pumping_last object %} </div>
{% card_diaperchange_last object %} <div class="col-sm-6 col-lg-4">
{% card_sleep_last object %} {% card_feeding_last object %}
{% card_feeding_last_method object %} </div>
{% card_feeding_day object %} <div class="col-sm-6 col-lg-4">
{% card_statistics object %} {% card_diaperchange_last object %}
{% card_sleep_recent object %} </div>
{% card_sleep_naps_day object %} <div class="col-sm-6 col-lg-4">
{% card_tummytime_day object %} {% card_pumping_last object %}
{% card_diaperchange_types object %} </div>
<div class="col-sm-6 col-lg-4">
{% card_sleep_last object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_feeding_last_method object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_feeding_day object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_statistics object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_sleep_recent object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_sleep_naps_day object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_tummytime_day object %}
</div>
<div class="col-sm-6 col-lg-4">
{% card_diaperchange_types object %}
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -4,7 +4,7 @@
{% block title %}{% trans "Dashboard" %}{% endblock %} {% block title %}{% trans "Dashboard" %}{% endblock %}
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item font-weight-bold">{% trans "Dashboard" %}</li> <li class="breadcrumb-item fw-bold">{% trans "Dashboard" %}</li>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -29,8 +29,9 @@ module.exports = {
vendor: [ vendor: [
'node_modules/pulltorefreshjs/dist/index.umd.js', 'node_modules/pulltorefreshjs/dist/index.umd.js',
'node_modules/jquery/dist/jquery.js', 'node_modules/jquery/dist/jquery.js',
'node_modules/popper.js/dist/umd/popper.js', 'node_modules/@popperjs/core/dist/umd/popper.js',
'node_modules/bootstrap/dist/js/bootstrap.js', 'node_modules/bootstrap/dist/js/bootstrap.js',
'node_modules/masonry-layout/dist/masonry.pkgd.js',
'node_modules/moment/moment.js', 'node_modules/moment/moment.js',
'node_modules/moment/locale/ca.js', 'node_modules/moment/locale/ca.js',
'node_modules/moment/locale/cs.js', 'node_modules/moment/locale/cs.js',
@ -50,7 +51,7 @@ module.exports = {
'node_modules/moment/locale/tr.js', 'node_modules/moment/locale/tr.js',
'node_modules/moment/locale/zh-cn.js', 'node_modules/moment/locale/zh-cn.js',
'node_modules/moment-timezone/builds/moment-timezone-with-data-10-year-range.js', 'node_modules/moment-timezone/builds/moment-timezone-with-data-10-year-range.js',
'node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.js' 'node_modules/@eonasdan/tempus-dominus/dist/js/tempus-dominus.js'
], ],
graph: [ graph: [
'node_modules/plotly.js/dist/plotly-cartesian.js', 'node_modules/plotly.js/dist/plotly-cartesian.js',

2774
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,10 @@
"url": "https://github.com/babybuddy/babybuddy.git" "url": "https://github.com/babybuddy/babybuddy.git"
}, },
"devDependencies": { "devDependencies": {
"@ronilaukkarinen/gulp-stylelint": "^14.1.1", "@eonasdan/tempus-dominus": "^6.0.0-beta7",
"bootstrap": "^4.6.2", "@popperjs/core": "^2.11.5",
"@ronilaukkarinen/gulp-stylelint": "^14.0.6",
"bootstrap": "^5.1.3",
"del": "^6.1.1", "del": "^6.1.1",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-all": "^1.1.0", "gulp-all": "^1.1.0",
@ -23,18 +25,17 @@
"gulp-spawn": "^2.0.0", "gulp-spawn": "^2.0.0",
"gulp-uglify": "^3.0.2", "gulp-uglify": "^3.0.2",
"jquery": "^3.6.4", "jquery": "^3.6.4",
"masonry-layout": "^4.2.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.41", "moment-timezone": "^0.5.41",
"npm-force-resolutions": "^0.0.10", "npm-force-resolutions": "^0.0.10",
"plotly.js": "^2.20.0", "plotly.js": "^2.20.0",
"popper.js": "^1.16.1",
"pulltorefreshjs": "^0.1.22", "pulltorefreshjs": "^0.1.22",
"sass": "^1.59.3", "pump": "^3.0.0",
"stylelint": "^15.3.0", "sass": "^1.52.3",
"stylelint-config-recommended-scss": "^9.0.1", "stylelint": "^14.9.0",
"stylelint-order": "^6.0.3", "stylelint-config-recommended-scss": "^6.0.0",
"stylelint-scss": "^4.5.0", "stylelint-order": "^5.0.0",
"tempusdominus-bootstrap-4": "5.39.2", "stylelint-scss": "^4.2.0"
"tempusdominus-core": "5.19.3"
} }
} }

View File

@ -0,0 +1,5 @@
.reports-list {
.list-group-item {
color: $white;
}
}

View File

@ -5,4 +5,6 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li> <li class="breadcrumb-item"><a href="{% url 'core:child-list' %}">{% trans "Children" %}</a></li>
<li class="breadcrumb-item fw-bold"><a href="{% url 'core:child' object.slug %}">{{ object }}</a></li>
<li class="breadcrumb-item"><a href="{% url 'reports:report-list' object.slug %}">{% trans "Reports" %}</a></li>
{% endblock %} {% endblock %}

View File

@ -12,10 +12,12 @@
{% if html %} {% if html %}
{{ html|safe }} {{ html|safe }}
{% else %} {% else %}
<div class="jumbotron text-center"> <div class="px-2 py-5 bg-dark rounded-3 text-center display-5">
<i class="icon-sad" aria-hidden="true"></i> <div class="container-fluid">
{% trans "There is not enough data to generate this report." %} <i class="icon-sad" aria-hidden="true"></i>
<i class="icon-sad" aria-hidden="true"></i> {% trans "There is not enough data to generate this report." %}
<i class="icon-sad" aria-hidden="true"></i>
</div>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -15,7 +15,7 @@
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<h1>Reports</h1> <h1>Reports</h1>
<div class="list-group"> <div class="reports-list list-group">
<a href="{% url 'reports:report-bmi-change-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Body Mass Index (BMI)" %}</a> <a href="{% url 'reports:report-bmi-change-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Body Mass Index (BMI)" %}</a>
<a href="{% url 'reports:report-diaperchange-amounts-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Diaper Change Amounts" %}</a> <a href="{% url 'reports:report-diaperchange-amounts-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Diaper Change Amounts" %}</a>
<a href="{% url 'reports:report-diaperchange-types-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Diaper Change Types" %}</a> <a href="{% url 'reports:report-diaperchange-types-child' object.slug %}" class="list-group-item list-group-item-action">{% trans "Diaper Change Types" %}</a>

File diff suppressed because it is too large Load Diff

Binary file not shown.

10947
static/babybuddy/css/app.c7ae9e0dd7de.css generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1 +0,0 @@
if("undefined"==typeof jQuery)throw new Error("Baby Buddy requires jQuery.");if("undefined"==typeof moment)throw new Error("Baby Buddy requires moment.js.");var BabyBuddy={};function preventDoubleSubmit(){return!1}BabyBuddy.DatetimePicker=function(e,n){return{init:function(t,i){var o={buttons:{showToday:!0,showClose:!0},defaultDate:"now",focusOnShow:!1,format:"L LT",ignoreReadonly:!0,locale:n.locale(),useCurrent:!1,icons:{time:"icon-clock",date:"icon-calendar",up:"icon-arrow-up",down:"icon-arrow-down",previous:"icon-angle-circled-left",next:"icon-angle-circled-right",today:"icon-today",clear:"icon-delete",close:"icon-cancel"},viewMode:"times"};t.datetimepicker(e.extend(o,i))}}}(jQuery,moment),BabyBuddy.PullToRefresh=function(e){return{init:function(){e.init({mainElement:"body",onRefresh:this.onRefresh})},onRefresh:function(){window.location.reload()}}}(PullToRefresh),$("form").off("submit",preventDoubleSubmit),$("form").on("submit",function(){$(this).on("submit",preventDoubleSubmit)}),BabyBuddy.Timer=function(e){var n=null,t=null,i=null,o=moment(),d=null,r={run:function(o,u){return t=o,0==(i=e("#"+u)).length?(console.error("BBTimer: Timer element not found."),!1):0==i.find(".timer-seconds").length||0==i.find(".timer-minutes").length||0==i.find(".timer-hours").length?(console.error("BBTimer: Element does not contain expected children."),!1):(n=setInterval(this.tick,1e3),void 0!==document.hidden?d="hidden":void 0!==document.msHidden?d="msHidden":void 0!==document.webkitHidden&&(d="webkitHidden"),void window.addEventListener("focus",r.handleVisibilityChange,!1))},handleVisibilityChange:function(){!document[d]&&moment().diff(o)>1e4&&r.update()},tick:function(){var e=i.find(".timer-seconds"),n=Number(e.text());if(n<59)e.text(n+1);else{e.text(0);var t=i.find(".timer-minutes"),o=Number(t.text());if(o<59)t.text(o+1);else{t.text(0);var d=i.find(".timer-hours"),r=Number(d.text());d.text(r+1)}}},update:function(){e.get("/api/timers/"+t+"/",function(e){if(e&&"duration"in e){clearInterval(n);var t=moment.duration(e.duration);i.find(".timer-hours").text(t.hours()),i.find(".timer-minutes").text(t.minutes()),i.find(".timer-seconds").text(t.seconds()),o=moment(),e.active?n=setInterval(r.tick,1e3):i.addClass("timer-stopped")}})}};return r}(jQuery),BabyBuddy.Dashboard=function(e){var n=null,t={watch:function(i,o){if(0==e("#"+i).length)return console.error("Baby Buddy: Dashboard element not found."),!1;void 0!==document.hidden?n="hidden":void 0!==document.msHidden?n="msHidden":void 0!==document.webkitHidden&&(n="webkitHidden"),void 0===window.addEventListener||void 0===document.hidden?o&&setInterval(this.update,o):(window.addEventListener("focus",t.handleVisibilityChange,!1),o&&setInterval(t.handleVisibilityChange,o))},handleVisibilityChange:function(){document[n]||t.update()},update:function(){location.reload()}};return t}(jQuery);

Binary file not shown.

1
static/babybuddy/js/app.d025d9d0940e.js generated Normal file
View File

@ -0,0 +1 @@
if("undefined"==typeof jQuery)throw new Error("Baby Buddy requires jQuery.");if("undefined"==typeof moment)throw new Error("Baby Buddy requires moment.js.");var BabyBuddy={};function preventDoubleSubmit(){return!1}BabyBuddy.DatetimePicker=function(e){return{init:function(n,t){let i={display:{buttons:{close:!0,today:!0},components:{calendar:!0,clock:!0,date:!0,decades:!0,hours:!0,minutes:!0,month:!0,seconds:!1,useTwentyfourHour:!1,year:!0},icons:{clear:"icon-delete",close:"icon-cancel",date:"icon-calendar",down:"icon-arrow-down",next:"icon-angle-circled-right",previous:"icon-angle-circled-left",time:"icon-clock",today:"icon-today",up:"icon-arrow-up"},viewMode:"clock"},localization:{locale:e.locale()}};new tempusDominus.TempusDominus(n,Object.assign(i,t))}}}(moment),BabyBuddy.PullToRefresh=function(e){return{init:function(){e.init({mainElement:"body",onRefresh:this.onRefresh})},onRefresh:function(){window.location.reload()}}}(PullToRefresh),$("form").off("submit",preventDoubleSubmit),$("form").on("submit",function(){$(this).on("submit",preventDoubleSubmit)}),BabyBuddy.Timer=function(e){var n=null,t=null,i=null,o=moment(),d=null,r={run:function(o,u){return t=o,0==(i=e("#"+u)).length?(console.error("BBTimer: Timer element not found."),!1):0==i.find(".timer-seconds").length||0==i.find(".timer-minutes").length||0==i.find(".timer-hours").length?(console.error("BBTimer: Element does not contain expected children."),!1):(n=setInterval(this.tick,1e3),void 0!==document.hidden?d="hidden":void 0!==document.msHidden?d="msHidden":void 0!==document.webkitHidden&&(d="webkitHidden"),void window.addEventListener("focus",r.handleVisibilityChange,!1))},handleVisibilityChange:function(){!document[d]&&moment().diff(o)>1e4&&r.update()},tick:function(){var e=i.find(".timer-seconds"),n=Number(e.text());if(n<59)e.text(n+1);else{e.text(0);var t=i.find(".timer-minutes"),o=Number(t.text());if(o<59)t.text(o+1);else{t.text(0);var d=i.find(".timer-hours"),r=Number(d.text());d.text(r+1)}}},update:function(){e.get("/api/timers/"+t+"/",function(e){if(e&&"duration"in e){clearInterval(n);var t=moment.duration(e.duration);i.find(".timer-hours").text(t.hours()),i.find(".timer-minutes").text(t.minutes()),i.find(".timer-seconds").text(t.seconds()),o=moment(),e.active?n=setInterval(r.tick,1e3):i.addClass("timer-stopped")}})}};return r}(jQuery),BabyBuddy.Dashboard=function(e){var n=null,t={watch:function(i,o){if(0==e("#"+i).length)return console.error("Baby Buddy: Dashboard element not found."),!1;void 0!==document.hidden?n="hidden":void 0!==document.msHidden?n="msHidden":void 0!==document.webkitHidden&&(n="webkitHidden"),void 0===window.addEventListener||void 0===document.hidden?o&&setInterval(this.update,o):(window.addEventListener("focus",t.handleVisibilityChange,!1),o&&setInterval(t.handleVisibilityChange,o))},handleVisibilityChange:function(){document[n]||t.update()},update:function(){location.reload()}};return t}(jQuery);

BIN
static/babybuddy/js/app.d025d9d0940e.js.gz generated Normal file

Binary file not shown.

View File

@ -1 +1 @@
if("undefined"==typeof jQuery)throw new Error("Baby Buddy requires jQuery.");if("undefined"==typeof moment)throw new Error("Baby Buddy requires moment.js.");var BabyBuddy={};function preventDoubleSubmit(){return!1}BabyBuddy.DatetimePicker=function(e,n){return{init:function(t,i){var o={buttons:{showToday:!0,showClose:!0},defaultDate:"now",focusOnShow:!1,format:"L LT",ignoreReadonly:!0,locale:n.locale(),useCurrent:!1,icons:{time:"icon-clock",date:"icon-calendar",up:"icon-arrow-up",down:"icon-arrow-down",previous:"icon-angle-circled-left",next:"icon-angle-circled-right",today:"icon-today",clear:"icon-delete",close:"icon-cancel"},viewMode:"times"};t.datetimepicker(e.extend(o,i))}}}(jQuery,moment),BabyBuddy.PullToRefresh=function(e){return{init:function(){e.init({mainElement:"body",onRefresh:this.onRefresh})},onRefresh:function(){window.location.reload()}}}(PullToRefresh),$("form").off("submit",preventDoubleSubmit),$("form").on("submit",function(){$(this).on("submit",preventDoubleSubmit)}),BabyBuddy.Timer=function(e){var n=null,t=null,i=null,o=moment(),d=null,r={run:function(o,u){return t=o,0==(i=e("#"+u)).length?(console.error("BBTimer: Timer element not found."),!1):0==i.find(".timer-seconds").length||0==i.find(".timer-minutes").length||0==i.find(".timer-hours").length?(console.error("BBTimer: Element does not contain expected children."),!1):(n=setInterval(this.tick,1e3),void 0!==document.hidden?d="hidden":void 0!==document.msHidden?d="msHidden":void 0!==document.webkitHidden&&(d="webkitHidden"),void window.addEventListener("focus",r.handleVisibilityChange,!1))},handleVisibilityChange:function(){!document[d]&&moment().diff(o)>1e4&&r.update()},tick:function(){var e=i.find(".timer-seconds"),n=Number(e.text());if(n<59)e.text(n+1);else{e.text(0);var t=i.find(".timer-minutes"),o=Number(t.text());if(o<59)t.text(o+1);else{t.text(0);var d=i.find(".timer-hours"),r=Number(d.text());d.text(r+1)}}},update:function(){e.get("/api/timers/"+t+"/",function(e){if(e&&"duration"in e){clearInterval(n);var t=moment.duration(e.duration);i.find(".timer-hours").text(t.hours()),i.find(".timer-minutes").text(t.minutes()),i.find(".timer-seconds").text(t.seconds()),o=moment(),e.active?n=setInterval(r.tick,1e3):i.addClass("timer-stopped")}})}};return r}(jQuery),BabyBuddy.Dashboard=function(e){var n=null,t={watch:function(i,o){if(0==e("#"+i).length)return console.error("Baby Buddy: Dashboard element not found."),!1;void 0!==document.hidden?n="hidden":void 0!==document.msHidden?n="msHidden":void 0!==document.webkitHidden&&(n="webkitHidden"),void 0===window.addEventListener||void 0===document.hidden?o&&setInterval(this.update,o):(window.addEventListener("focus",t.handleVisibilityChange,!1),o&&setInterval(t.handleVisibilityChange,o))},handleVisibilityChange:function(){document[n]||t.update()},update:function(){location.reload()}};return t}(jQuery); if("undefined"==typeof jQuery)throw new Error("Baby Buddy requires jQuery.");if("undefined"==typeof moment)throw new Error("Baby Buddy requires moment.js.");var BabyBuddy={};function preventDoubleSubmit(){return!1}BabyBuddy.DatetimePicker=function(e){return{init:function(n,t){let i={display:{buttons:{close:!0,today:!0},components:{calendar:!0,clock:!0,date:!0,decades:!0,hours:!0,minutes:!0,month:!0,seconds:!1,useTwentyfourHour:!1,year:!0},icons:{clear:"icon-delete",close:"icon-cancel",date:"icon-calendar",down:"icon-arrow-down",next:"icon-angle-circled-right",previous:"icon-angle-circled-left",time:"icon-clock",today:"icon-today",up:"icon-arrow-up"},viewMode:"clock"},localization:{locale:e.locale()}};new tempusDominus.TempusDominus(n,Object.assign(i,t))}}}(moment),BabyBuddy.PullToRefresh=function(e){return{init:function(){e.init({mainElement:"body",onRefresh:this.onRefresh})},onRefresh:function(){window.location.reload()}}}(PullToRefresh),$("form").off("submit",preventDoubleSubmit),$("form").on("submit",function(){$(this).on("submit",preventDoubleSubmit)}),BabyBuddy.Timer=function(e){var n=null,t=null,i=null,o=moment(),d=null,r={run:function(o,u){return t=o,0==(i=e("#"+u)).length?(console.error("BBTimer: Timer element not found."),!1):0==i.find(".timer-seconds").length||0==i.find(".timer-minutes").length||0==i.find(".timer-hours").length?(console.error("BBTimer: Element does not contain expected children."),!1):(n=setInterval(this.tick,1e3),void 0!==document.hidden?d="hidden":void 0!==document.msHidden?d="msHidden":void 0!==document.webkitHidden&&(d="webkitHidden"),void window.addEventListener("focus",r.handleVisibilityChange,!1))},handleVisibilityChange:function(){!document[d]&&moment().diff(o)>1e4&&r.update()},tick:function(){var e=i.find(".timer-seconds"),n=Number(e.text());if(n<59)e.text(n+1);else{e.text(0);var t=i.find(".timer-minutes"),o=Number(t.text());if(o<59)t.text(o+1);else{t.text(0);var d=i.find(".timer-hours"),r=Number(d.text());d.text(r+1)}}},update:function(){e.get("/api/timers/"+t+"/",function(e){if(e&&"duration"in e){clearInterval(n);var t=moment.duration(e.duration);i.find(".timer-hours").text(t.hours()),i.find(".timer-minutes").text(t.minutes()),i.find(".timer-seconds").text(t.seconds()),o=moment(),e.active?n=setInterval(r.tick,1e3):i.addClass("timer-stopped")}})}};return r}(jQuery),BabyBuddy.Dashboard=function(e){var n=null,t={watch:function(i,o){if(0==e("#"+i).length)return console.error("Baby Buddy: Dashboard element not found."),!1;void 0!==document.hidden?n="hidden":void 0!==document.msHidden?n="msHidden":void 0!==document.webkitHidden&&(n="webkitHidden"),void 0===window.addEventListener||void 0===document.hidden?o&&setInterval(this.update,o):(window.addEventListener("focus",t.handleVisibilityChange,!1),o&&setInterval(t.handleVisibilityChange,o))},handleVisibilityChange:function(){document[n]||t.update()},update:function(){location.reload()}};return t}(jQuery);

Binary file not shown.

View File

@ -0,0 +1 @@
!function(){const t=document.querySelector('input[name="csrfmiddlewaretoken"]').value;function e(e,s,a,i,n){const o=new XMLHttpRequest;o.addEventListener("load",()=>{o.status>=200&&o.status<300?i(o.responseText,o):n(o.responseText,o)});for(const t of["error","timeout","abort"])o.addEventListener(t,()=>{n(o.responseText,o)});o.timeout=2e4,o.open(e,s),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Accept","application/json"),o.setRequestHeader("X-CSRFTOKEN",t),o.send(a)}class s{constructor(t){this.prototype=t.querySelector(".prototype-tag"),this.listeners=[],this.modalElement=t.querySelector(".tag-editor-error-modal"),this.modalBodyNode=this.modalElement.querySelector(".modal-body");for(const t of this.modalBodyNode.childNodes)t.nodeType===Node.TEXT_NODE&&this.modalBodyNode.removeChild(t)}showModal(t){const e=this.modalBodyNode.querySelector(`span[data-message='${t}']`);e||(e=this.modalBodyNode.childNodes[0]);for(const t of this.modalBodyNode.childNodes)t.classList.add("d-none");e.classList.remove("d-none"),jQuery(this.modalElement).modal("show")}addTagListUpdatedListener(t){this.listeners.push(t)}callTagListUpdatedListeners(){for(const t of this.listeners)t()}updateTag(t,e,s,a){const i=t.querySelector(".add-remove-icon").childNodes[0];e=e||t.getAttribute("data-value"),s=s||t.getAttribute("data-color"),a=a||i.textContent,t.childNodes[0].textContent=e,t.setAttribute("data-value",e),t.setAttribute("data-color",s);const n=("#"===(o=s).slice(0,1)&&(o=o.slice(1)),3===o.length&&(o=o.split("").map(function(t){return t+t}).join("")),(299*parseInt(o.substr(0,2),16)+587*parseInt(o.substr(2,2),16)+114*parseInt(o.substr(4,2),16))/1e3>=128?"#101010":"#EFEFEF");var o;t.setAttribute("style",`background-color: ${s}; color: ${n};`),i.textContent=a}createNewTag(t,e,s){const a=this.prototype.cloneNode(!0);return a.classList.remove("prototype-tag"),a.classList.add("tag"),this.updateTag(a,t,e,s),a}insertTag(t,e){t.appendChild(e),this.callTagListUpdatedListeners()}}class a{constructor(t,e,s){this.widget=t,this.taggingBase=e,this.apiTagsUrl=t.getAttribute("data-tags-url"),this.createTagInputs=t.querySelector(".create-tag-inputs"),this.addTagInput=this.createTagInputs.querySelector('input[type="text"]'),this.addTagButton=this.createTagInputs.querySelector("#add-tag"),this.addTagInput.value="",this.onInsertNewTag=s,this.addTagButton.addEventListener("click",()=>this.onCreateTagClicked()),this.addTagInput.addEventListener("keydown",t=>{"enter"===t.key.toLowerCase()&&(t.preventDefault(),this.onCreateTagClicked())})}onCreateTagClicked(){const t=this.addTagInput.value.trim(),s=encodeURIComponent(t),a=t=>{this.addTagInput.select(),this.taggingBase.showModal(t||"generic")};if(!t)return void a("invalid-tag-name");const i=(t,e)=>{const s=this.taggingBase.createNewTag(t,e,"-");this.addTagInput.value="",this.onInsertNewTag(s)},n=JSON.stringify({name:this.addTagInput.value});e("GET",`${this.apiTagsUrl}?name=${s}`,null,t=>{const s=JSON.parse(t);if(s.count){const t=s.results[0];i(t.name,t.color)}else e("POST",this.apiTagsUrl,n,t=>{const e=JSON.parse(t);i(e.name,e.color)},()=>a("tag-creation-failed"))},()=>a("tag-checking-failed"))}}class i{constructor(t){this.widget=t,this.taggingBase=new s(this.widget),this.addTagControl=new a(this.widget,this.taggingBase,t=>this.insertNewTag(t)),this.currentTags=this.widget.querySelector(".current_tags"),this.newTags=this.widget.querySelector(".new-tags"),this.inputElement=this.widget.querySelector('input[type="hidden"]');for(const t of this.newTags.querySelectorAll(".tag"))this.configureAddTag(t);for(const t of this.currentTags.querySelectorAll(".tag"))this.configureRemoveTag(t);this.updateInputList(),this.taggingBase.addTagListUpdatedListener(()=>this.updateInputList())}insertNewTag(t){const e=t.getAttribute("data-value"),s=this.widget.querySelector(`span[data-value="${e}"]`);s&&s.parentNode.removeChild(s),this.taggingBase.insertTag(this.currentTags,t),this.configureRemoveTag(t)}registerNewCallback(t,e,s){t.addEventListener("click",function a(i){t.parentNode.removeChild(t),this.taggingBase.insertTag(e,t),t.removeEventListener("click",a),s(t)}.bind(this))}updateInputList(){const t=[];for(const e of this.currentTags.querySelectorAll(".tag")){const s=e.getAttribute("data-value");t.push(`"${s}"`)}this.inputElement.value=t.join(",")}configureAddTag(t){this.taggingBase.updateTag(t,null,null,"+"),this.registerNewCallback(t,this.currentTags,()=>this.configureRemoveTag(t)),this.updateInputList()}configureRemoveTag(t){this.taggingBase.updateTag(t,null,null,"-"),this.registerNewCallback(t,this.newTags,()=>this.configureAddTag(t)),this.updateInputList()}}window.addEventListener("load",()=>{for(const t of document.querySelectorAll(".babybuddy-tags-editor"))new i(t)})}();

Binary file not shown.

View File

@ -1 +0,0 @@
!function(){const t=document.querySelector('input[name="csrfmiddlewaretoken"]').value;function e(e,s,a,i,n){const o=new XMLHttpRequest;o.addEventListener("load",()=>{o.status>=200&&o.status<300?i(o.responseText,o):n(o.responseText,o)});for(const t of["error","timeout","abort"])o.addEventListener(t,()=>{n(o.responseText,o)});o.timeout=2e4,o.open(e,s),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Accept","application/json"),o.setRequestHeader("X-CSRFTOKEN",t),o.send(a)}class s{constructor(t){this.prototype=t.querySelector(".prototype-tag"),this.listeners=[],this.modalElement=t.querySelector(".tag-editor-error-modal"),this.modalBodyNode=this.modalElement.querySelector(".modal-body");for(const t of this.modalBodyNode.childNodes)t.nodeType===Node.TEXT_NODE&&this.modalBodyNode.removeChild(t)}showModal(t){const e=this.modalBodyNode.querySelector(`span[data-message='${t}']`);e||(e=this.modalBodyNode.childNodes[0]);for(const t of this.modalBodyNode.childNodes)t.classList.add("d-none");e.classList.remove("d-none"),jQuery(this.modalElement).modal("show")}addTagListUpdatedListener(t){this.listeners.push(t)}callTagListUpdatedListeners(){for(const t of this.listeners)t()}updateTag(t,e,s,a){const i=t.querySelector(".add-remove-icon").childNodes[0];e=e||t.getAttribute("data-value"),s=s||t.getAttribute("data-color"),a=a||i.textContent,t.childNodes[0].textContent=e,t.setAttribute("data-value",e),t.setAttribute("data-color",s);const n=("#"===(o=s).slice(0,1)&&(o=o.slice(1)),3===o.length&&(o=o.split("").map(function(t){return t+t}).join("")),(299*parseInt(o.substr(0,2),16)+587*parseInt(o.substr(2,2),16)+114*parseInt(o.substr(4,2),16))/1e3>=128?"#101010":"#EFEFEF");var o;t.setAttribute("style",`background-color: ${s}; color: ${n};`),i.textContent=a}createNewTag(t,e,s){const a=this.prototype.cloneNode(!0);return a.classList.remove("prototype-tag"),a.classList.add("tag"),this.updateTag(a,t,e,s),a}insertTag(t,e){t.appendChild(e),this.callTagListUpdatedListeners()}}class a{constructor(t,e,s){this.widget=t,this.taggingBase=e,this.apiTagsUrl=t.getAttribute("data-tags-url"),this.createTagInputs=t.querySelector(".create-tag-inputs"),this.addTagInput=this.createTagInputs.querySelector('input[type="text"]'),this.addTagButton=this.createTagInputs.querySelector(".btn-add-new-tag"),this.addTagInput.value="",this.onInsertNewTag=s,this.addTagButton.addEventListener("click",()=>this.onCreateTagClicked()),this.addTagInput.addEventListener("keydown",t=>{"enter"===t.key.toLowerCase()&&(t.preventDefault(),this.onCreateTagClicked())})}onCreateTagClicked(){const t=this.addTagInput.value.trim(),s=encodeURIComponent(t),a=t=>{this.addTagInput.select(),this.taggingBase.showModal(t||"generic")};if(!t)return void a("invalid-tag-name");const i=(t,e)=>{const s=this.taggingBase.createNewTag(t,e,"-");this.addTagInput.value="",this.onInsertNewTag(s)},n=JSON.stringify({name:this.addTagInput.value});e("GET",`${this.apiTagsUrl}?name=${s}`,null,t=>{const s=JSON.parse(t);if(s.count){const t=s.results[0];i(t.name,t.color)}else e("POST",this.apiTagsUrl,n,t=>{const e=JSON.parse(t);i(e.name,e.color)},()=>a("tag-creation-failed"))},()=>a("tag-checking-failed"))}}class i{constructor(t){this.widget=t,this.taggingBase=new s(this.widget),this.addTagControl=new a(this.widget,this.taggingBase,t=>this.insertNewTag(t)),this.currentTags=this.widget.querySelector(".current_tags"),this.newTags=this.widget.querySelector(".new-tags"),this.inputElement=this.widget.querySelector('input[type="hidden"]');for(const t of this.newTags.querySelectorAll(".tag"))this.configureAddTag(t);for(const t of this.currentTags.querySelectorAll(".tag"))this.configureRemoveTag(t);this.updateInputList(),this.taggingBase.addTagListUpdatedListener(()=>this.updateInputList())}insertNewTag(t){const e=t.getAttribute("data-value"),s=this.widget.querySelector(`span[data-value="${e}"]`);s&&s.parentNode.removeChild(s),this.taggingBase.insertTag(this.currentTags,t),this.configureRemoveTag(t)}registerNewCallback(t,e,s){t.addEventListener("click",function a(i){t.parentNode.removeChild(t),this.taggingBase.insertTag(e,t),t.removeEventListener("click",a),s(t)}.bind(this))}updateInputList(){const t=[];for(const e of this.currentTags.querySelectorAll(".tag")){const s=e.getAttribute("data-value");t.push(`"${s}"`)}this.inputElement.value=t.join(",")}configureAddTag(t){this.taggingBase.updateTag(t,null,null,"+"),this.registerNewCallback(t,this.currentTags,()=>this.configureRemoveTag(t)),this.updateInputList()}configureRemoveTag(t){this.taggingBase.updateTag(t,null,null,"-"),this.registerNewCallback(t,this.newTags,()=>this.configureAddTag(t)),this.updateInputList()}}window.addEventListener("load",()=>{for(const t of document.querySelectorAll(".babybuddy-tags-editor"))new i(t)})}();

Binary file not shown.

View File

@ -1 +1 @@
!function(){const t=document.querySelector('input[name="csrfmiddlewaretoken"]').value;function e(e,s,a,i,n){const o=new XMLHttpRequest;o.addEventListener("load",()=>{o.status>=200&&o.status<300?i(o.responseText,o):n(o.responseText,o)});for(const t of["error","timeout","abort"])o.addEventListener(t,()=>{n(o.responseText,o)});o.timeout=2e4,o.open(e,s),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Accept","application/json"),o.setRequestHeader("X-CSRFTOKEN",t),o.send(a)}class s{constructor(t){this.prototype=t.querySelector(".prototype-tag"),this.listeners=[],this.modalElement=t.querySelector(".tag-editor-error-modal"),this.modalBodyNode=this.modalElement.querySelector(".modal-body");for(const t of this.modalBodyNode.childNodes)t.nodeType===Node.TEXT_NODE&&this.modalBodyNode.removeChild(t)}showModal(t){const e=this.modalBodyNode.querySelector(`span[data-message='${t}']`);e||(e=this.modalBodyNode.childNodes[0]);for(const t of this.modalBodyNode.childNodes)t.classList.add("d-none");e.classList.remove("d-none"),jQuery(this.modalElement).modal("show")}addTagListUpdatedListener(t){this.listeners.push(t)}callTagListUpdatedListeners(){for(const t of this.listeners)t()}updateTag(t,e,s,a){const i=t.querySelector(".add-remove-icon").childNodes[0];e=e||t.getAttribute("data-value"),s=s||t.getAttribute("data-color"),a=a||i.textContent,t.childNodes[0].textContent=e,t.setAttribute("data-value",e),t.setAttribute("data-color",s);const n=("#"===(o=s).slice(0,1)&&(o=o.slice(1)),3===o.length&&(o=o.split("").map(function(t){return t+t}).join("")),(299*parseInt(o.substr(0,2),16)+587*parseInt(o.substr(2,2),16)+114*parseInt(o.substr(4,2),16))/1e3>=128?"#101010":"#EFEFEF");var o;t.setAttribute("style",`background-color: ${s}; color: ${n};`),i.textContent=a}createNewTag(t,e,s){const a=this.prototype.cloneNode(!0);return a.classList.remove("prototype-tag"),a.classList.add("tag"),this.updateTag(a,t,e,s),a}insertTag(t,e){t.appendChild(e),this.callTagListUpdatedListeners()}}class a{constructor(t,e,s){this.widget=t,this.taggingBase=e,this.apiTagsUrl=t.getAttribute("data-tags-url"),this.createTagInputs=t.querySelector(".create-tag-inputs"),this.addTagInput=this.createTagInputs.querySelector('input[type="text"]'),this.addTagButton=this.createTagInputs.querySelector(".btn-add-new-tag"),this.addTagInput.value="",this.onInsertNewTag=s,this.addTagButton.addEventListener("click",()=>this.onCreateTagClicked()),this.addTagInput.addEventListener("keydown",t=>{"enter"===t.key.toLowerCase()&&(t.preventDefault(),this.onCreateTagClicked())})}onCreateTagClicked(){const t=this.addTagInput.value.trim(),s=encodeURIComponent(t),a=t=>{this.addTagInput.select(),this.taggingBase.showModal(t||"generic")};if(!t)return void a("invalid-tag-name");const i=(t,e)=>{const s=this.taggingBase.createNewTag(t,e,"-");this.addTagInput.value="",this.onInsertNewTag(s)},n=JSON.stringify({name:this.addTagInput.value});e("GET",`${this.apiTagsUrl}?name=${s}`,null,t=>{const s=JSON.parse(t);if(s.count){const t=s.results[0];i(t.name,t.color)}else e("POST",this.apiTagsUrl,n,t=>{const e=JSON.parse(t);i(e.name,e.color)},()=>a("tag-creation-failed"))},()=>a("tag-checking-failed"))}}class i{constructor(t){this.widget=t,this.taggingBase=new s(this.widget),this.addTagControl=new a(this.widget,this.taggingBase,t=>this.insertNewTag(t)),this.currentTags=this.widget.querySelector(".current_tags"),this.newTags=this.widget.querySelector(".new-tags"),this.inputElement=this.widget.querySelector('input[type="hidden"]');for(const t of this.newTags.querySelectorAll(".tag"))this.configureAddTag(t);for(const t of this.currentTags.querySelectorAll(".tag"))this.configureRemoveTag(t);this.updateInputList(),this.taggingBase.addTagListUpdatedListener(()=>this.updateInputList())}insertNewTag(t){const e=t.getAttribute("data-value"),s=this.widget.querySelector(`span[data-value="${e}"]`);s&&s.parentNode.removeChild(s),this.taggingBase.insertTag(this.currentTags,t),this.configureRemoveTag(t)}registerNewCallback(t,e,s){t.addEventListener("click",function a(i){t.parentNode.removeChild(t),this.taggingBase.insertTag(e,t),t.removeEventListener("click",a),s(t)}.bind(this))}updateInputList(){const t=[];for(const e of this.currentTags.querySelectorAll(".tag")){const s=e.getAttribute("data-value");t.push(`"${s}"`)}this.inputElement.value=t.join(",")}configureAddTag(t){this.taggingBase.updateTag(t,null,null,"+"),this.registerNewCallback(t,this.currentTags,()=>this.configureRemoveTag(t)),this.updateInputList()}configureRemoveTag(t){this.taggingBase.updateTag(t,null,null,"-"),this.registerNewCallback(t,this.newTags,()=>this.configureAddTag(t)),this.updateInputList()}}window.addEventListener("load",()=>{for(const t of document.querySelectorAll(".babybuddy-tags-editor"))new i(t)})}(); !function(){const t=document.querySelector('input[name="csrfmiddlewaretoken"]').value;function e(e,s,a,i,n){const o=new XMLHttpRequest;o.addEventListener("load",()=>{o.status>=200&&o.status<300?i(o.responseText,o):n(o.responseText,o)});for(const t of["error","timeout","abort"])o.addEventListener(t,()=>{n(o.responseText,o)});o.timeout=2e4,o.open(e,s),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Accept","application/json"),o.setRequestHeader("X-CSRFTOKEN",t),o.send(a)}class s{constructor(t){this.prototype=t.querySelector(".prototype-tag"),this.listeners=[],this.modalElement=t.querySelector(".tag-editor-error-modal"),this.modalBodyNode=this.modalElement.querySelector(".modal-body");for(const t of this.modalBodyNode.childNodes)t.nodeType===Node.TEXT_NODE&&this.modalBodyNode.removeChild(t)}showModal(t){const e=this.modalBodyNode.querySelector(`span[data-message='${t}']`);e||(e=this.modalBodyNode.childNodes[0]);for(const t of this.modalBodyNode.childNodes)t.classList.add("d-none");e.classList.remove("d-none"),jQuery(this.modalElement).modal("show")}addTagListUpdatedListener(t){this.listeners.push(t)}callTagListUpdatedListeners(){for(const t of this.listeners)t()}updateTag(t,e,s,a){const i=t.querySelector(".add-remove-icon").childNodes[0];e=e||t.getAttribute("data-value"),s=s||t.getAttribute("data-color"),a=a||i.textContent,t.childNodes[0].textContent=e,t.setAttribute("data-value",e),t.setAttribute("data-color",s);const n=("#"===(o=s).slice(0,1)&&(o=o.slice(1)),3===o.length&&(o=o.split("").map(function(t){return t+t}).join("")),(299*parseInt(o.substr(0,2),16)+587*parseInt(o.substr(2,2),16)+114*parseInt(o.substr(4,2),16))/1e3>=128?"#101010":"#EFEFEF");var o;t.setAttribute("style",`background-color: ${s}; color: ${n};`),i.textContent=a}createNewTag(t,e,s){const a=this.prototype.cloneNode(!0);return a.classList.remove("prototype-tag"),a.classList.add("tag"),this.updateTag(a,t,e,s),a}insertTag(t,e){t.appendChild(e),this.callTagListUpdatedListeners()}}class a{constructor(t,e,s){this.widget=t,this.taggingBase=e,this.apiTagsUrl=t.getAttribute("data-tags-url"),this.createTagInputs=t.querySelector(".create-tag-inputs"),this.addTagInput=this.createTagInputs.querySelector('input[type="text"]'),this.addTagButton=this.createTagInputs.querySelector("#add-tag"),this.addTagInput.value="",this.onInsertNewTag=s,this.addTagButton.addEventListener("click",()=>this.onCreateTagClicked()),this.addTagInput.addEventListener("keydown",t=>{"enter"===t.key.toLowerCase()&&(t.preventDefault(),this.onCreateTagClicked())})}onCreateTagClicked(){const t=this.addTagInput.value.trim(),s=encodeURIComponent(t),a=t=>{this.addTagInput.select(),this.taggingBase.showModal(t||"generic")};if(!t)return void a("invalid-tag-name");const i=(t,e)=>{const s=this.taggingBase.createNewTag(t,e,"-");this.addTagInput.value="",this.onInsertNewTag(s)},n=JSON.stringify({name:this.addTagInput.value});e("GET",`${this.apiTagsUrl}?name=${s}`,null,t=>{const s=JSON.parse(t);if(s.count){const t=s.results[0];i(t.name,t.color)}else e("POST",this.apiTagsUrl,n,t=>{const e=JSON.parse(t);i(e.name,e.color)},()=>a("tag-creation-failed"))},()=>a("tag-checking-failed"))}}class i{constructor(t){this.widget=t,this.taggingBase=new s(this.widget),this.addTagControl=new a(this.widget,this.taggingBase,t=>this.insertNewTag(t)),this.currentTags=this.widget.querySelector(".current_tags"),this.newTags=this.widget.querySelector(".new-tags"),this.inputElement=this.widget.querySelector('input[type="hidden"]');for(const t of this.newTags.querySelectorAll(".tag"))this.configureAddTag(t);for(const t of this.currentTags.querySelectorAll(".tag"))this.configureRemoveTag(t);this.updateInputList(),this.taggingBase.addTagListUpdatedListener(()=>this.updateInputList())}insertNewTag(t){const e=t.getAttribute("data-value"),s=this.widget.querySelector(`span[data-value="${e}"]`);s&&s.parentNode.removeChild(s),this.taggingBase.insertTag(this.currentTags,t),this.configureRemoveTag(t)}registerNewCallback(t,e,s){t.addEventListener("click",function a(i){t.parentNode.removeChild(t),this.taggingBase.insertTag(e,t),t.removeEventListener("click",a),s(t)}.bind(this))}updateInputList(){const t=[];for(const e of this.currentTags.querySelectorAll(".tag")){const s=e.getAttribute("data-value");t.push(`"${s}"`)}this.inputElement.value=t.join(",")}configureAddTag(t){this.taggingBase.updateTag(t,null,null,"+"),this.registerNewCallback(t,this.currentTags,()=>this.configureRemoveTag(t)),this.updateInputList()}configureRemoveTag(t){this.taggingBase.updateTag(t,null,null,"-"),this.registerNewCallback(t,this.newTags,()=>this.configureAddTag(t)),this.updateInputList()}}window.addEventListener("load",()=>{for(const t of document.querySelectorAll(".babybuddy-tags-editor"))new i(t)})}();

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More