Fix left padding of login button in top menu

Clean up spacing for nav pills

Markdown fields should default to using monospace font

Wrap action buttons in object page header

Fix page link style for non-HTMX paginators

Clean up styling of Markdown preview widget

Fix spacing around placeholder text for empty panel tables

Remove obsolete templates

Tweak checkbox input spacing

Fix toggling of clear button for quick search

Fix positioning of quick search filter dropdown

Fix positioning of 'highlight device' button

Fix styling for custom field group names

Widen buttons on nav menu items

Restyle the login page

Fix active nav-pill background color in dark mode

Fix spacing around 'map' button for sites
This commit is contained in:
Jeremy Stretch 2024-01-23 10:30:23 -05:00
parent 780ce77aed
commit d302982a88
34 changed files with 150 additions and 151 deletions

View File

@ -2956,7 +2956,6 @@ class InventoryItemBulkDeleteView(generic.BulkDeleteView):
queryset = InventoryItem.objects.all()
filterset = filtersets.InventoryItemFilterSet
table = tables.InventoryItemTable
template_name = 'dcim/inventoryitem_bulk_delete.html'
@register_model_view(InventoryItem, 'children')

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,12 +7,12 @@ import { isTruthy } from './util';
*/
function quickSearchEventHandler(event: Event): void {
const quicksearch = event.currentTarget as HTMLInputElement;
const inputgroup = quicksearch.parentElement as HTMLDivElement;
if (isTruthy(inputgroup)) {
const clearbtn = document.getElementById("quicksearch_clear") as HTMLAnchorElement;
if (isTruthy(clearbtn)) {
if (quicksearch.value === "") {
inputgroup.classList.add("hide-last-child");
clearbtn.classList.add("d-none");
} else {
inputgroup.classList.remove("hide-last-child");
clearbtn.classList.remove("d-none");
}
}
}
@ -22,7 +22,7 @@ function quickSearchEventHandler(event: Event): void {
*/
export function initQuickSearch(): void {
const quicksearch = document.getElementById("quicksearch") as HTMLInputElement;
const clearbtn = document.getElementById("quicksearch_clear") as HTMLButtonElement;
const clearbtn = document.getElementById("quicksearch_clear") as HTMLAnchorElement;
if (isTruthy(quicksearch)) {
quicksearch.addEventListener("keyup", quickSearchEventHandler, {
passive: true

View File

@ -18,3 +18,6 @@ $table-cell-padding-y: 0.5rem;
// Fix Tabler bug #1694 in 1.0.0-beta20
$hover-bg: rgba(var(--tblr-secondary-rgb), 0.08);
// Ensure active nav-pill has a background color in dark mode
$nav-pills-link-active-bg: rgba(var(--tblr-secondary-rgb), 0.15);

View File

@ -0,0 +1,38 @@
// Rendered Markdown
.rendered-markdown {
table {
width: 100%;
// Apply a border
th {
border-bottom: 2px solid #dddddd;
padding: 8px;
}
td {
border-top: 1px solid #dddddd;
padding: 8px;
}
// Map "align" attr of column headings
th[align="left"] {
text-align: left;
}
th[align="center"] {
text-align: center;
}
th[align="right"] {
text-align: right;
}
}
}
// Markdown preview
.markdown-widget {
.preview {
border: 1px solid $border-color;
border-radius: $border-radius;
min-height: 200px;
}
}

View File

@ -10,36 +10,6 @@ span.color-label {
border-radius: $border-radius;
}
// Rendered Markdown
.rendered-markdown {
table {
width: 100%;
// Apply a border
th {
border-bottom: 2px solid #dddddd;
padding: 8px;
}
td {
border-top: 1px solid #dddddd;
padding: 8px;
}
// Map "align" attr of column headings
th[align="left"] {
text-align: left;
}
th[align="center"] {
text-align: center;
}
th[align="right"] {
text-align: right;
}
}
}
// Object hierarchy depth indicators
.record-depth {
display: inline;

View File

@ -19,4 +19,5 @@
// Custom styling
@import 'custom/code';
@import 'custom/markdown';
@import 'custom/misc';

View File

@ -15,7 +15,7 @@
{% with providernetwork_tab_active=form.initial.provider_network %}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link{% if not providernetwork_tab_active %} active{% endif %}" role="tab" type="button" data-bs-target="#site" data-bs-toggle="tab">{% trans "Site" %}</button>
</li>

View File

@ -1,9 +0,0 @@
{% extends 'generic/object_edit.html' %}
{% load form_helpers %}
{% block form %}
{% block replication_fields %}
{% render_form replication_form %}
{% endblock replication_fields %}
{{ block.super }}
{% endblock form %}

View File

@ -27,14 +27,12 @@
</tr>
<tr>
<th scope="row">{% trans "Rack" %}</th>
<td class="position-relative">
<td class="d-flex justify-content-between">
{% if object.rack %}
{{ object.rack|linkify }}
<div class="position-absolute top-50 end-0 translate-middle-y d-print-none">
<a href="{{ object.rack.get_absolute_url }}?device={{ object.pk }}" class="btn btn-primary" title="{% trans "Highlight device" %}">
<i class="mdi mdi-view-day-outline"></i>
</a>
</div>
<a href="{{ object.rack.get_absolute_url }}?device={{ object.pk }}" class="btn btn-primary btn-sm d-print-none" title="{% trans "Highlight device in rack" %}">
<i class="mdi mdi-view-day-outline"></i>
</a>
{% else %}
{{ ''|placeholder }}
{% endif %}

View File

@ -2,7 +2,7 @@
{% load i18n %}
{% block extra_table_controls %}
<button class="btn btn-outline-dark dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="mdi mdi-eye"></i>
</button>
<ul class="dropdown-menu">

View File

@ -1,15 +0,0 @@
{% extends 'generic/confirmation_form.html' %}
{% load form_helpers %}
{% load i18n %}
{% block title %}
{% blocktrans %}Delete device bay {{ devicebay }}?{% endblocktrans %}
{% endblock %}
{% block message %}
<p>
{% blocktrans trimmed with device=devicebay.device %}
Are you sure you want to delete this device bay from <strong>{{ device }}</strong>?
{% endblocktrans %}
</p>
{% endblock %}

View File

@ -1,6 +0,0 @@
{% extends 'generic/bulk_delete.html' %}
{% load i18n %}
{% block message_extra %}
<p class="text-center text-danger"><i class="mdi mdi-alert"></i> {% trans "This will also delete all child inventory items of those listed" %}.</p>
{% endblock %}

View File

@ -32,8 +32,8 @@
<div class="row">
<h5 class="col-9 offset-3">{% trans "Component Assignment" %}</h5>
</div>
<div class="row mb-2 offset-sm-3">
<ul class="nav nav-pills" role="tablist">
<div class="row offset-sm-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="consoleport_tab" data-bs-toggle="tab" aria-controls="consoleport" data-bs-target="#consoleport" class="nav-link {% if form.initial.consoleport or form.no_component %}active{% endif %}">
{% trans "Console Port" %}

View File

@ -72,16 +72,14 @@
</tr>
<tr>
<th scope="row">{% trans "Physical Address" %}</th>
<td class="position-relative">
<td class="d-flex justify-content-between">
{% if object.physical_address %}
{% if config.MAPS_URL %}
<div class="position-absolute top-50 end-0 translate-middle-y d-print-none">
<a href="{{ config.MAPS_URL }}{{ object.physical_address|urlencode }}" target="_blank" class="btn btn-primary">
<i class="mdi mdi-map-marker"></i> {% trans "Map" %}
</a>
</div>
{% endif %}
<span>{{ object.physical_address|linebreaksbr }}</span>
{% if config.MAPS_URL %}
<a href="{{ config.MAPS_URL }}{{ object.physical_address|urlencode }}" target="_blank" class="btn btn-primary btn-sm d-print-none">
<i class="mdi mdi-map-marker"></i> {% trans "Map" %}
</a>
{% endif %}
{% else %}
{{ ''|placeholder }}
{% endif %}

View File

@ -6,16 +6,16 @@
{% block page-header %}
<div class="container-xl mt-2 d-print-none">
<div class="row align-items-center">
<div class="d-flex justify-content-between">
{# Title #}
<div class="col">
<div>
<h2 class="page-title my-1">{% block title %}{% endblock title %}</h2>
{% block subtitle %}{% endblock %}
</div>
{# Controls #}
<div class="col-auto d-print-none">
<div class="d-print-none">
{% block controls %}
<div class="btn-list">
{% block control-buttons %}{% endblock %}

View File

@ -57,7 +57,7 @@ Context:
{% endblock subtitle %}
{% block controls %}
<div class="btn-list mb-2">
<div class="btn-list justify-content-end mb-2">
{% plugin_buttons object %}
{# Add/edit/delete/etc. buttons #}

View File

@ -43,7 +43,7 @@
{{ p }}
</a>
{% elif p %}
<a href="{% querystring request page=p %}" class="btn btn-outline-secondary{% if page.number == p %} active{% endif %}">
<a href="{% querystring request page=p %}" class="page-link {% if page.number == p %} active{% endif %}">
{{ p }}
</a>
{% else %}

View File

@ -5,11 +5,11 @@
{% if heading %}
<h5 class="card-header{% if panel_class %} text-{{ panel_class }}{% endif %}">{{ heading }}</h5>
{% endif %}
<div class="table-responsive">
{% if table.rows %}
{% if table.rows %}
<div class="table-responsive">
{% render_table table 'inc/table.html' %}
{% else %}
<div class="text-muted">{% trans "None" %}</div>
{% endif %}
</div>
</div>
{% else %}
<div class="card-body text-muted">{% trans "None" %}</div>
{% endif %}
</div>

View File

@ -5,14 +5,16 @@
{% if custom_fields %}
<div class="card">
<h5 class="card-header">{% trans "Custom Fields" %}</h5>
{% for group_name, fields in custom_fields.items %}
{% if group_name %}
<h6>{{ group_name }}</h6>
{% endif %}
<table class="table table-hover attr-table">
<table class="table table-hover attr-table">
{% for group_name, fields in custom_fields.items %}
{% if group_name %}
<tr>
<th scope="row" colspan="2" class="fw-bold">{{ group_name }}</th>
</tr>
{% endif %}
{% for field, value in fields.items %}
<tr>
<th scope="row">{{ field }}
<th scope="row"{% if group_name %} class="ps-3"{% endif %}>{{ field }}
{% if field.description %}
<i
class="mdi mdi-information text-primary"
@ -27,8 +29,8 @@
</td>
</tr>
{% endfor %}
</table>
{% endfor %}
{% endfor %}
</table>
</div>
{% endif %}
{% endwith %}

View File

@ -3,12 +3,14 @@
<div class="row mb-3">
<div class="col-auto d-print-none">
<div class="input-group me-2 quicksearch hide-last-child">
<input type="search" results="5" name="q" id="quicksearch" class="form-control" placeholder="Quick search"
<div class="input-group input-group-flat me-2 quicksearch">
<input type="search" results="5" name="q" id="quicksearch" class="form-control px-2 py-1" placeholder="Quick search"
hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
<button class="btn bg-transparent" type="button" id="quicksearch_clear"><i class="mdi mdi-close-circle"></i></button>
</div>
<span class="input-group-text py-1">
<a href="#" id="quicksearch_clear" class="d-none text-secondary"><i class="mdi mdi-close-circle"></i></a>
</span>
{% block extra_table_controls %}{% endblock %}
</div>
</div>
<div class="col-auto ms-auto d-print-none">
{% if request.user.is_authenticated and table_modal %}

View File

@ -33,7 +33,7 @@
</div>
</div>
{% else %}
<div class="btn-group">
<div class="btn-group ps-2">
<a class="btn btn-primary" type="button" href="{% url 'login' %}?next={{ request.path }}">
<i class="mdi mdi-login-variant"></i> {% trans "Log In" %}
</a>

View File

@ -36,7 +36,7 @@
</div>
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.vminterface and not form.initial.fhrpgroup %}active{% endif %}">
{% trans "Device" %}

View File

@ -11,7 +11,7 @@
{# Device/VM selection #}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.virtual_machine %}active{% endif %}">
{% trans "Device" %}
@ -37,7 +37,7 @@
{# Template or custom #}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="template_tab" data-bs-toggle="tab" data-bs-target="#template" class="nav-link active">
{% trans "From Template" %}

View File

@ -10,7 +10,7 @@
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.virtual_machine %}active{% endif %}">
{% trans "Device" %}

View File

@ -32,7 +32,7 @@
{% with site_tab_active=form.initial.site %}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link{% if not site_tab_active %} active{% endif %}" href="#group" role="tab" data-bs-toggle="tab">{% trans "VLAN Group" %}</a>
</li>

View File

@ -33,7 +33,7 @@
<div class="card card-md">
<div class="card-body">
<h3 class="text-center mb-4">Log In</h3>
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
{# Login form #}
<form action="{% url 'login' %}" method="post">
@ -46,25 +46,30 @@
<input type="hidden" name="next" value="{{ request.POST.next }}" />
{% endif %}
{{ form }}
{% render_form form %}
<button type="submit" class="btn btn-primary btn-lg w-100 mt-4">
{% trans "Sign In" %}
</button>
<div class="form-footer">
<button type="submit" class="btn btn-primary w-100">
{% trans "Sign In" %}
</button>
</div>
</form>
</div>
{# SSO login #}
{% if auth_backends %}
<div class="hr-text">or</div>
<div class="hr-text">{% trans "Or" context "Denotes an alternative option" %}</div>
<div class="card-body">
<h6 class="mt-4 mb-3">{% trans "Or use a single sign-on (SSO) provider" %}:</h6>
{% for backend in auth_backends %}
<h5>
{% if backend.icon_name %}<i class="mdi mdi-{{ backend.icon_name }}"></i>{% endif %}
<a href="{{ backend.url }}" class="my-2">{{ backend.display_name }}</a>
</h5>
{% endfor %}
<div class="row">
{% for backend in auth_backends %}
<div class="col">
<a href="{{ backend.url }}" class="btn w-100">
{% if backend.icon_name %}<i class="mdi mdi-{{ backend.icon_name }}"></i>{% endif %}
{{ backend.display_name }}
</a>
</div>
{% endfor %}
</div>
</div>
{% endif %}

View File

@ -9,9 +9,9 @@
<h5 class="col-9 offset-3">{% trans "L2VPN Termination" %}</h5>
</div>
{% render_field form.l2vpn %}
<div class="row mb-3">
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills" role="tablist">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vlan_tab" data-bs-toggle="tab" aria-controls="vlan" data-bs-target="#vlan" class="nav-link {% if not form.initial.interface or form.initial.vminterface %}active{% endif %}">
{% trans "VLAN" %}

View File

@ -23,6 +23,16 @@ class MarkdownWidget(forms.Textarea):
"""
template_name = 'widgets/markdown_input.html'
def __init__(self, attrs=None):
# Markdown fields should use monospace font
default_attrs = {
"class": "font-monospace",
}
if attrs:
default_attrs.update(attrs)
super().__init__(default_attrs)
class NumberWithOptions(forms.NumberInput):
"""

View File

@ -23,11 +23,14 @@
</div>
{# Render checkbox labels to the right of the field #}
{% elif field|widget_type == 'checkboxinput' %}
<div class="form-check">
<div class="form-check mb-0">
{{ field }}
<label for="{{ field.id_for_label }}" class="form-check-label">
{{ label }}
</label>
{% if field.help_text %}
<span class="form-text">{{ field.help_text|safe }}</span>
{% endif %}
</div>
{# Include a copy-to-clipboard button #}
{% elif 'data-clipboard' in field.field.widget.attrs %}
@ -54,7 +57,7 @@
{% endif %}
{# Help text #}
{% if field.help_text %}
{% if field.help_text and field|widget_type != 'checkboxinput' %}
<span class="form-text">{{ field.help_text|safe }}</span>
{% endif %}

View File

@ -28,7 +28,7 @@
{% if buttons %}
<div class="btn-group ms-1">
{% for button in buttons %}
<a href="{% url button.link %}" class="btn btn-sm btn-{{ button.color|default:"outline-dark" }} lh-2" title="{{ button.title }}">
<a href="{% url button.link %}" class="btn btn-sm btn-{{ button.color|default:"outline-dark" }} lh-2 px-2" title="{{ button.title }}">
<i class="{{ button.icon_class }}"></i>
</a>
{% endfor %}

View File

@ -1,23 +1,23 @@
{% load i18n %}
<div class="border rounded">
<ul class="nav nav-tabs px-3 pt-2 rounded-top border-0">
<li class="nav-item" role="presentation">
<button class="nav-link active " id="{{ widget.name }}-input-tab" data-bs-toggle="tab" data-bs-target="#{{ widget.name }}-input" type="button" role="tab" aria-controls="{{ widget.name }}-input" aria-selected="true">
{% trans "Write" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button hx-target="#{{ widget.name }}-preview" hx-swap="innerHTML" hx-post="{% url 'extras:render_markdown' %}" class="nav-link preview-button" id="{{ widget.name }}-markdown-preview-tab" data-bs-toggle="tab" data-bs-target="#{{ widget.name }}-markdown-preview" type="button" role="tab" aria-controls="{{ widget.name }}-markdown-preview" aria-selected="false">
{% trans "Preview" %}
</button>
</li>
</ul>
<div class="tab-content text-bg-body rounded-bottom border-top">
<div class="tab-pane show active" id="{{ widget.name }}-input" role="tabpanel" aria-labelledby="{{ widget.name }}-input-tab">
{% include "django/forms/widgets/textarea.html" %}
</div>
<div class="tab-pane show" id="{{ widget.name }}-markdown-preview" role="tabpanel" aria-labelledby="{{ widget.name }}-markdown-preview-tab">
<div id="{{ widget.name }}-preview" class="preview px-3 py-2">{% trans "Testing" %}</div>
</div>
<div class="markdown-widget">
<ul class="nav nav-pills mb-1">
<li class="nav-item" role="presentation">
<button class="nav-link active " id="{{ widget.name }}-input-tab" data-bs-toggle="tab" data-bs-target="#{{ widget.name }}-input" type="button" role="tab" aria-controls="{{ widget.name }}-input" aria-selected="true">
{% trans "Write" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button hx-target="#{{ widget.name }}-preview" hx-swap="innerHTML" hx-post="{% url 'extras:render_markdown' %}" class="nav-link preview-button" id="{{ widget.name }}-markdown-preview-tab" data-bs-toggle="tab" data-bs-target="#{{ widget.name }}-markdown-preview" type="button" role="tab" aria-controls="{{ widget.name }}-markdown-preview" aria-selected="false">
{% trans "Preview" %}
</button>
</li>
</ul>
<div class="tab-content text-bg-body rounded-bottom">
<div class="tab-pane show active" id="{{ widget.name }}-input" role="tabpanel" aria-labelledby="{{ widget.name }}-input-tab">
{% include "django/forms/widgets/textarea.html" %}
</div>
<div class="tab-pane show" id="{{ widget.name }}-markdown-preview" role="tabpanel" aria-labelledby="{{ widget.name }}-markdown-preview-tab">
<div id="{{ widget.name }}-preview" class="preview px-3 py-2 border-1"></div>
</div>
</div>
</div>