Fixed #36437 -- Improved accessibility of messages in admin.
@ -35,8 +35,11 @@ html[data-theme="light"],
|
|||||||
--error-fg: #ba2121;
|
--error-fg: #ba2121;
|
||||||
|
|
||||||
--message-success-bg: #dfd;
|
--message-success-bg: #dfd;
|
||||||
|
--message-success-icon: url(../img/icon-yes.svg);
|
||||||
--message-warning-bg: #ffc;
|
--message-warning-bg: #ffc;
|
||||||
|
--message-warning-icon: url(../img/icon-alert.svg);
|
||||||
--message-error-bg: #ffefef;
|
--message-error-bg: #ffefef;
|
||||||
|
--message-error-icon: url(../img/icon-no.svg);
|
||||||
|
|
||||||
--darkened-bg: #f8f8f8; /* A bit darker than --body-bg */
|
--darkened-bg: #f8f8f8; /* A bit darker than --body-bg */
|
||||||
--selected-bg: #e4e4e4; /* E.g. selected table cells */
|
--selected-bg: #e4e4e4; /* E.g. selected table cells */
|
||||||
@ -637,20 +640,29 @@ ul.messagelist li {
|
|||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
padding: 10px 10px 10px 65px;
|
padding: 10px 10px 10px 65px;
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px 0;
|
||||||
background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat;
|
|
||||||
background-size: 16px auto;
|
|
||||||
color: var(--body-fg);
|
color: var(--body-fg);
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
background-color: var(--message-success-bg);
|
||||||
|
background-image: var(--message-success-icon);
|
||||||
|
background-position: 40px 12px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 16px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.messagelist li.warning {
|
ul.messagelist li.warning {
|
||||||
background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat;
|
background-color: var(--message-warning-bg);
|
||||||
background-size: 14px auto;
|
background-image: var(--message-warning-icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.messagelist li.error {
|
ul.messagelist li.error {
|
||||||
background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat;
|
background-color: var(--message-error-bg);
|
||||||
background-size: 16px auto;
|
background-image: var(--message-error-icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (forced-colors: active) {
|
||||||
|
ul.messagelist li {
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.errornote {
|
.errornote {
|
||||||
|
@ -21,8 +21,11 @@
|
|||||||
|
|
||||||
--error-fg: #e35f5f;
|
--error-fg: #e35f5f;
|
||||||
--message-success-bg: #006b1b;
|
--message-success-bg: #006b1b;
|
||||||
|
--message-success-icon: url(../img/icon-yes-dark.svg);
|
||||||
--message-warning-bg: #583305;
|
--message-warning-bg: #583305;
|
||||||
|
--message-warning-icon: url(../img/icon-alert-dark.svg);
|
||||||
--message-error-bg: #570808;
|
--message-error-bg: #570808;
|
||||||
|
--message-error-icon: url(../img/icon-no-dark.svg);
|
||||||
|
|
||||||
--darkened-bg: #212121;
|
--darkened-bg: #212121;
|
||||||
--selected-bg: #1b1b1b;
|
--selected-bg: #1b1b1b;
|
||||||
@ -58,8 +61,11 @@ html[data-theme="dark"] {
|
|||||||
|
|
||||||
--error-fg: #e35f5f;
|
--error-fg: #e35f5f;
|
||||||
--message-success-bg: #006b1b;
|
--message-success-bg: #006b1b;
|
||||||
|
--message-success-icon: url(../img/icon-yes-dark.svg);
|
||||||
--message-warning-bg: #583305;
|
--message-warning-bg: #583305;
|
||||||
|
--message-warning-icon: url(../img/icon-alert-dark.svg);
|
||||||
--message-error-bg: #570808;
|
--message-error-bg: #570808;
|
||||||
|
--message-error-icon: url(../img/icon-no-dark.svg);
|
||||||
|
|
||||||
--darkened-bg: #212121;
|
--darkened-bg: #212121;
|
||||||
--selected-bg: #1b1b1b;
|
--selected-bg: #1b1b1b;
|
||||||
|
@ -337,16 +337,8 @@ input[type="submit"], button {
|
|||||||
/* Messages */
|
/* Messages */
|
||||||
|
|
||||||
ul.messagelist li {
|
ul.messagelist li {
|
||||||
padding-left: 55px;
|
padding: 10px 10px 10px 55px;
|
||||||
background-position: 30px 12px;
|
background-position-x: 30px;
|
||||||
}
|
|
||||||
|
|
||||||
ul.messagelist li.error {
|
|
||||||
background-position: 30px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.messagelist li.warning {
|
|
||||||
background-position: 30px 14px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Login */
|
/* Login */
|
||||||
@ -739,16 +731,8 @@ input[type="submit"], button {
|
|||||||
/* Messages */
|
/* Messages */
|
||||||
|
|
||||||
ul.messagelist li {
|
ul.messagelist li {
|
||||||
padding-left: 40px;
|
padding: 10px 10px 10px 40px;
|
||||||
background-position: 15px 12px;
|
background-position-x: 15px;
|
||||||
}
|
|
||||||
|
|
||||||
ul.messagelist li.error {
|
|
||||||
background-position: 15px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.messagelist li.warning {
|
|
||||||
background-position: 15px 14px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Paginator */
|
/* Paginator */
|
||||||
|
@ -47,6 +47,11 @@
|
|||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 16px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[dir="rtl"] ul.messagelist li {
|
||||||
|
padding: 10px 55px 10px 10px;
|
||||||
|
background-position-x: calc(100% - 30px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MOBILE */
|
/* MOBILE */
|
||||||
@ -86,4 +91,9 @@
|
|||||||
[dir="rtl"] :enabled.selector-add:focus, :enabled.selector-add:hover {
|
[dir="rtl"] :enabled.selector-add:focus, :enabled.selector-add:hover {
|
||||||
background-position: 0 -72px;
|
background-position: 0 -72px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[dir="rtl"] ul.messagelist li {
|
||||||
|
padding: 10px 40px 10px 10px;
|
||||||
|
background-position-x: calc(100% - 15px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,3 +291,8 @@ form .form-row p.datetime {
|
|||||||
.selector .selector-chooser {
|
.selector .selector-chooser {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.messagelist li {
|
||||||
|
padding: 10px 65px 10px 10px;
|
||||||
|
background-position-x: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="14" height="14">
|
||||||
|
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
||||||
|
<!--
|
||||||
|
Icon Name: triangle-exclamation
|
||||||
|
Icon Family: classic
|
||||||
|
Icon Style: solid
|
||||||
|
-->
|
||||||
|
<path fill="#efb80b" d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 684 B |
@ -5,5 +5,5 @@
|
|||||||
Icon Family: classic
|
Icon Family: classic
|
||||||
Icon Style: solid
|
Icon Style: solid
|
||||||
-->
|
-->
|
||||||
<path fill="#efb80b" d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/>
|
<path fill="#b78b02" d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 684 B After Width: | Height: | Size: 684 B |
9
django/contrib/admin/static/admin/img/icon-no-dark.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="13" height="13" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
||||||
|
<!--
|
||||||
|
Icon Name: circle-xmark
|
||||||
|
Icon Family: classic
|
||||||
|
Icon Style: solid
|
||||||
|
-->
|
||||||
|
<path fill="#f15f5f" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 645 B |
@ -5,5 +5,5 @@
|
|||||||
Icon Family: classic
|
Icon Family: classic
|
||||||
Icon Style: solid
|
Icon Style: solid
|
||||||
-->
|
-->
|
||||||
<path fill="#dd4646" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/>
|
<path fill="#c63d3d" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 645 B |
9
django/contrib/admin/static/admin/img/icon-yes-dark.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="13" height="13" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
||||||
|
<!--
|
||||||
|
Icon Name: circle-check
|
||||||
|
Icon Family: classic
|
||||||
|
Icon Style: solid
|
||||||
|
-->
|
||||||
|
<path fill="#73c12f" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 558 B |
@ -5,5 +5,5 @@
|
|||||||
Icon Family: classic
|
Icon Family: classic
|
||||||
Icon Style: solid
|
Icon Style: solid
|
||||||
-->
|
-->
|
||||||
<path fill="#70bf2b" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
|
<path fill="#649c35" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 558 B |
@ -135,6 +135,7 @@ from .models import (
|
|||||||
UnchangeableObject,
|
UnchangeableObject,
|
||||||
UndeletableObject,
|
UndeletableObject,
|
||||||
UnorderedObject,
|
UnorderedObject,
|
||||||
|
UserMessenger,
|
||||||
UserProxy,
|
UserProxy,
|
||||||
Villain,
|
Villain,
|
||||||
Vodcast,
|
Vodcast,
|
||||||
@ -6876,6 +6877,36 @@ class SeleniumTests(AdminSeleniumTestCase):
|
|||||||
name_input_value = name_input.get_attribute("value")
|
name_input_value = name_input.get_attribute("value")
|
||||||
self.assertEqual(name_input_value, "Test section 1")
|
self.assertEqual(name_input_value, "Test section 1")
|
||||||
|
|
||||||
|
@screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"])
|
||||||
|
@override_settings(MESSAGE_LEVEL=10)
|
||||||
|
def test_messages(self):
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support.ui import Select
|
||||||
|
|
||||||
|
with override_settings(MESSAGE_LEVEL=10):
|
||||||
|
self.admin_login(
|
||||||
|
username="super", password="secret", login_url=reverse("admin:index")
|
||||||
|
)
|
||||||
|
UserMessenger.objects.create()
|
||||||
|
for level in ["warning", "info", "error", "success", "debug"]:
|
||||||
|
self.selenium.get(
|
||||||
|
self.live_server_url
|
||||||
|
+ reverse("admin:admin_views_usermessenger_changelist"),
|
||||||
|
)
|
||||||
|
checkbox = self.selenium.find_element(
|
||||||
|
By.CSS_SELECTOR, "tr input.action-select"
|
||||||
|
)
|
||||||
|
checkbox.click()
|
||||||
|
Select(self.selenium.find_element(By.NAME, "action")).select_by_value(
|
||||||
|
f"message_{level}"
|
||||||
|
)
|
||||||
|
self.selenium.find_element(By.XPATH, '//button[text()="Run"]').click()
|
||||||
|
message = self.selenium.find_element(
|
||||||
|
By.CSS_SELECTOR, "ul.messagelist li"
|
||||||
|
)
|
||||||
|
self.assertEqual(message.get_attribute("innerText"), f"Test {level}")
|
||||||
|
self.take_screenshot(level)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF="admin_views.urls")
|
@override_settings(ROOT_URLCONF="admin_views.urls")
|
||||||
class ReadonlyTest(AdminFieldExtractionMixin, TestCase):
|
class ReadonlyTest(AdminFieldExtractionMixin, TestCase):
|
||||||
|