#6797: Improve toast styles
This commit is contained in:
parent
189e733f81
commit
0479d5a02a
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -34,16 +34,16 @@ export function createToast(
|
|||
message: string,
|
||||
extra?: string,
|
||||
): Toast {
|
||||
let iconName = 'bi-exclamation-triangle-fill';
|
||||
let iconName = 'mdi-alert';
|
||||
switch (level) {
|
||||
case 'warning':
|
||||
iconName = 'bi-exclamation-triangle-fill';
|
||||
iconName = 'mdi-alert';
|
||||
case 'success':
|
||||
iconName = 'bi-check-circle-fill';
|
||||
iconName = 'mdi-check-circle';
|
||||
case 'info':
|
||||
iconName = 'bi-info-circle-fill';
|
||||
iconName = 'mdi-information';
|
||||
case 'danger':
|
||||
iconName = 'bi-exclamation-triangle-fill';
|
||||
iconName = 'mdi-alert';
|
||||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
|
|
@ -59,7 +59,7 @@ export function createToast(
|
|||
header.setAttribute('class', `toast-header bg-${level} text-body`);
|
||||
|
||||
const icon = document.createElement('i');
|
||||
icon.setAttribute('class', `bi ${iconName}`);
|
||||
icon.setAttribute('class', `mdi ${iconName}`);
|
||||
|
||||
const titleElement = document.createElement('strong');
|
||||
titleElement.setAttribute('class', 'me-auto ms-1');
|
||||
|
|
|
|||
|
|
@ -94,12 +94,37 @@
|
|||
margin-bottom: $spacer;
|
||||
}
|
||||
|
||||
// Ensure elements with data-href set show the correct cursor.
|
||||
// data-href is set on non non-anchor elements that need to redirect the user to a URL when
|
||||
// clicked, but where an anchor element does not suffice or is not supported.
|
||||
*[data-href] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Use proper contrasting color foreground color for special components.
|
||||
@each $color, $value in $theme-colors {
|
||||
// Override CSS values on each theme color.
|
||||
|
||||
// Use Bootstrap's method of coloring alert links to appropriately color close buttons within
|
||||
// another colored element.
|
||||
// See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52
|
||||
// See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_close.scss#L12
|
||||
$shaded-color: shade-color(mix($value, color-contrast($value), abs($alert-color-scale)), 5%);
|
||||
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$shaded-color}'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
|
||||
.bg-#{$color} button.btn-close {
|
||||
background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat;
|
||||
}
|
||||
|
||||
// Use Bootstrap's method of coloring the .alert-link class automatically.
|
||||
// See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52
|
||||
.toast.bg-#{$color},
|
||||
.alert.alert-#{$color} {
|
||||
a {
|
||||
color: $shaded-color;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
|
||||
// Use proper contrasting color foreground color for special components.
|
||||
.badge,
|
||||
.toast,
|
||||
.progress-bar {
|
||||
|
|
@ -107,11 +132,11 @@
|
|||
color: color-contrast($value);
|
||||
}
|
||||
}
|
||||
// Use proper foreground color in the alert body. Note: this is applied to a, p, & small because
|
||||
|
||||
// Use proper foreground color in the alert body. Note: this is applied to p, & small because
|
||||
// we *don't* want to override the h1-h6 colors for alerts, since those are set to a color
|
||||
// similar to the alert color.
|
||||
.alert.alert-#{$color} {
|
||||
a,
|
||||
p,
|
||||
small {
|
||||
color: color-contrast($value);
|
||||
|
|
@ -926,8 +951,9 @@ div.card > div.card-header > div.table-controls {
|
|||
border-bottom: 1px solid $nav-tabs-border-color;
|
||||
}
|
||||
|
||||
// Shade the home page content background-color.
|
||||
body {
|
||||
// Page-specific styles.
|
||||
html {
|
||||
// Shade the home page content background-color.
|
||||
&[data-netbox-path='/'] {
|
||||
.content-container,
|
||||
.search {
|
||||
|
|
@ -940,4 +966,11 @@ body {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't show the django-messages toasts on the login screen in favor of the alert component.
|
||||
&[data-netbox-path*='/login'] {
|
||||
#django-messages {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,10 @@ $font-family-sans-serif: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMa
|
|||
$font-family-monospace: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
|
||||
'Courier New', monospace;
|
||||
|
||||
// This is the same value as the default from Bootstrap, but it needs to be in scope prior to
|
||||
// importing _variables.scss from Bootstrap.
|
||||
$btn-close-width: 1em;
|
||||
|
||||
$accordion-padding-y: 0.8125rem;
|
||||
$accordion-padding-x: 0.8125rem;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ $link-hover-color: $blue-100;
|
|||
// Alerts
|
||||
$alert-bg-scale: -5%;
|
||||
$alert-border-scale: -20%;
|
||||
$alert-color-scale: 20%;
|
||||
|
||||
// Tables
|
||||
$table-color: $gray-100;
|
||||
|
|
@ -261,15 +262,8 @@ $carousel-dark-control-icon-filter: invert(1) grayscale(100);
|
|||
// Close
|
||||
$btn-close-color: $white;
|
||||
$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);
|
||||
|
||||
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
|
||||
|
||||
@each $color, $value in $theme-colors {
|
||||
.bg-#{$color} button.btn-close {
|
||||
background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{color-contrast($value)}'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
|
||||
}
|
||||
}
|
||||
|
||||
// Code
|
||||
$code-color: $gray-200;
|
||||
$kbd-color: $white;
|
||||
|
|
|
|||
|
|
@ -1,39 +1,59 @@
|
|||
{% load helpers %}
|
||||
|
||||
<div id="django-messages" class="toast-container position-fixed bottom-0 end-0 m-3">
|
||||
{# Django Messages #}
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="django-message toast align-items-center border-0 bg-{% if message.tags %}{{ message.tags }}{% else %}info{% endif %}" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="10000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
{{ message }}
|
||||
{% with message.level_tag|status_from_tag as status %}
|
||||
{% with status|icon_from_status as icon %}
|
||||
<div class="django-message toast align-items-center border-0 bg-{{ status }}" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="10000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
<i class="mdi mdi-{{ icon }} me-1"></i>
|
||||
{{ message }}
|
||||
</div>
|
||||
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
||||
{% elif form and form.non_field_errors %}
|
||||
{# Non-Field Form Errors #}
|
||||
|
||||
{% for error in form.non_field_errors.get_json_data %}
|
||||
<div class="django-message toast align-items-center border-0 bg-danger" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="10000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
{{ error.message }}
|
||||
</div>
|
||||
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% elif form and form.errors %}
|
||||
{% for field in form %}
|
||||
{% for error in field.errors %}
|
||||
<div class="django-message toast align-items-center border-0 bg-danger" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="60000">
|
||||
<div class="toast-header bg-danger">
|
||||
<strong class="me-auto">{{ field.label }}</strong>
|
||||
<div class="django-message toast align-items-center border-0 bg-danger" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="10000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
<i class="mdi mdi-{{ "danger"|icon_from_status }} me-1"></i>
|
||||
{{ error.message }}
|
||||
</div>
|
||||
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ error|escape }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% elif form and form.errors %}
|
||||
{# Form Field Errors #}
|
||||
|
||||
{% for field in form %}
|
||||
{% for error in field.errors %}
|
||||
<div class="django-message toast align-items-center border-0 bg-danger" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="60000">
|
||||
<div class="toast-header bg-danger">
|
||||
<strong class="me-auto">
|
||||
<i class="mdi mdi-{{ "danger"|icon_from_status }} me-1"></i>
|
||||
{{ field.label }}
|
||||
</strong>
|
||||
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ error|escape }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -326,6 +326,35 @@ def querystring(request, **kwargs):
|
|||
return ''
|
||||
|
||||
|
||||
@register.filter
|
||||
def status_from_tag(tag: str = "info") -> str:
|
||||
"""
|
||||
Determine Bootstrap theme status/level from Django's Message.level_tag.
|
||||
"""
|
||||
status_map = {
|
||||
'warning': 'warning',
|
||||
'success': 'success',
|
||||
'error': 'danger',
|
||||
'debug': 'info',
|
||||
'info': 'info',
|
||||
}
|
||||
return status_map.get(tag.lower(), 'info')
|
||||
|
||||
|
||||
@register.filter
|
||||
def icon_from_status(status: str = "info") -> str:
|
||||
"""
|
||||
Determine icon class name from Bootstrap theme status/level.
|
||||
"""
|
||||
icon_map = {
|
||||
'warning': 'alert',
|
||||
'success': 'check-circle',
|
||||
'danger': 'alert',
|
||||
'info': 'information',
|
||||
}
|
||||
return icon_map.get(status.lower(), 'information')
|
||||
|
||||
|
||||
@register.inclusion_tag('utilities/templatetags/utilization_graph.html')
|
||||
def utilization_graph(utilization, warning_threshold=75, danger_threshold=90):
|
||||
"""
|
||||
|
|
@ -338,7 +367,7 @@ def utilization_graph(utilization, warning_threshold=75, danger_threshold=90):
|
|||
elif warning_threshold or danger_threshold:
|
||||
bar_class = 'bg-success'
|
||||
else:
|
||||
bar_class = 'bg-default'
|
||||
bar_class = 'bg-gray'
|
||||
return {
|
||||
'utilization': utilization,
|
||||
'bar_class': bar_class,
|
||||
|
|
|
|||
Loading…
Reference in New Issue