mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 03:27:21 -06:00
#6797: Improve toast styles
This commit is contained in:
parent
189e733f81
commit
0479d5a02a
BIN
netbox/project-static/dist/config.js
vendored
BIN
netbox/project-static/dist/config.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/config.js.map
vendored
BIN
netbox/project-static/dist/config.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js
vendored
BIN
netbox/project-static/dist/jobs.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js.map
vendored
BIN
netbox/project-static/dist/jobs.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js
vendored
BIN
netbox/project-static/dist/lldp.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js.map
vendored
BIN
netbox/project-static/dist/lldp.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox-dark.css
vendored
BIN
netbox/project-static/dist/netbox-dark.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox-light.css
vendored
BIN
netbox/project-static/dist/netbox-light.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js
vendored
BIN
netbox/project-static/dist/status.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js.map
vendored
BIN
netbox/project-static/dist/status.js.map
vendored
Binary file not shown.
@ -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
Block a user