Allow customization of preview device sizes

Co-authored-by: Bartosz Cieliński <bart@fullfatthings.com>
pull/12414/head
alexkiro 2024-10-14 15:30:52 +03:00 zatwierdzone przez Sage Abdullah
rodzic 49f9ae3a96
commit b38141ad82
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: EB1A33CC51CC0217
7 zmienionych plików z 257 dodań i 12 usunięć

Wyświetl plik

@ -202,6 +202,12 @@ See also [django-treebeard](https://django-treebeard.readthedocs.io/en/latest/in
.. autoattribute:: preview_modes
.. autoattribute:: default_preview_mode
.. autoattribute:: preview_sizes
.. autoattribute:: default_preview_size
.. automethod:: serve_preview
.. automethod:: get_parent
@ -576,6 +582,10 @@ Pages already include this mixin, so there is no need to add it.
.. autoattribute:: preview_modes
.. autoattribute:: default_preview_mode
.. autoattribute:: preview_sizes
.. autoattribute:: default_preview_size
.. automethod:: is_previewable

Wyświetl plik

@ -12,18 +12,25 @@
>
<div class="w-preview__sizes">
{% block size_buttons %}
<label class="w-preview__size-button">
{% icon name="mobile-alt" %}
<input type="radio" class="w-preview__proxy" name="preview-size" value="mobile" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="375" data-default-size checked aria-label="{% trans 'Preview in mobile size' %}" />
</label>
<label class="w-preview__size-button">
{% icon name="tablet-alt" %}
<input type="radio" class="w-preview__proxy" name="preview-size" value="tablet" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="768" aria-label="{% trans 'Preview in tablet size' %}" />
</label>
<label class="w-preview__size-button">
{% icon name="desktop" %}
<input type="radio" class="w-preview__proxy" name="preview-size" value="desktop" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="1280" aria-label="{% trans 'Preview in desktop size' %}" />
</label>
{% for size in object.preview_sizes %}
<label class="w-preview__size-button">
{% icon name=size.icon %}
<input
type="radio"
class="w-preview__proxy"
name="preview-size"
value="{{ size.name }}"
data-action="w-preview#togglePreviewSize"
data-w-preview-target="size"
aria-label="{{ size.label }}"
data-device-width="{{ size.device_width|stringformat:'s' }}"
{% if object.default_preview_size == size.name %}
data-default-size
checked
{% endif %}
/>
</label>
{% endfor %}
{% endblock %}
{% block new_tab_button %}

Wyświetl plik

@ -9,6 +9,7 @@ from freezegun import freeze_time
from wagtail.admin.views.pages.preview import PreviewOnEdit
from wagtail.models import Page
from wagtail.test.testapp.models import (
CustomPreviewSizesPage,
EventCategory,
MultiPreviewModesPage,
SimplePage,
@ -415,6 +416,26 @@ class TestPreview(WagtailTestUtils, TestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, template)
def test_preview_sizes(self):
page = CustomPreviewSizesPage(title="Custom preview size")
self.home_page.add_child(instance=page)
edit_url = reverse("wagtailadmin_pages:edit", args=(page.id,))
response = self.client.get(edit_url)
self.assertEqual(response.status_code, 200)
soup = self.get_soup(response.content)
radios = soup.select('input[type="radio"][name="preview-size"]')
self.assertEqual(len(radios), 2)
self.assertEqual("412", radios[0]["data-device-width"])
self.assertEqual("Custom mobile preview", radios[0]["aria-label"])
self.assertFalse(radios[0].has_attr("checked"))
self.assertEqual("1280", radios[1]["data-device-width"])
self.assertEqual("Original desktop", radios[1]["aria-label"])
self.assertTrue(radios[1].has_attr("checked"))
class TestEnablePreview(WagtailTestUtils, TestCase):
def setUp(self):

Wyświetl plik

@ -805,6 +805,26 @@ class PreviewableMixin:
full_url = property(get_full_url)
DEFAULT_PREVIEW_MODES = [("", _("Default"))]
DEFAULT_PREVIEW_SIZES = [
{
"name": "mobile",
"icon": "mobile-alt",
"device_width": 375,
"label": _("Preview in mobile size"),
},
{
"name": "tablet",
"icon": "tablet-alt",
"device_width": 768,
"label": _("Preview in tablet size"),
},
{
"name": "desktop",
"icon": "desktop",
"device_width": 1280,
"label": _("Preview in desktop size"),
},
]
@property
def preview_modes(self):
@ -828,6 +848,43 @@ class PreviewableMixin:
"""
return self.preview_modes[0][0]
@property
def preview_sizes(self):
"""
Returns a list of dictionaries, each representing a preview size option for this object.
Override this property to customize the preview sizes.
Each dictionary in the list should include the following keys:
- `name`: A string representing the internal name of the preview size.
- `icon`: A string specifying the icon's name for the preview size button.
- `device_width`: An integer indicating the device's width in pixels.
- `label`: A string for the aria label on the preview size button.
.. code-block:: python
@property
def preview_sizes(self):
return [
{
"name": "mobile",
"icon": "mobile-icon",
"device_width": 320,
"label": "Preview in mobile size"
},
# Add more preview size dictionaries as needed.
]
"""
return PreviewableMixin.DEFAULT_PREVIEW_SIZES
@property
def default_preview_size(self):
"""
The default preview size name to use in live preview.
Defaults to ``"mobile"``, which is the first one defined in ``preview_sizes``.
If ``preview_sizes`` is empty, an ``IndexError`` will be raised.
"""
return self.preview_sizes[0]["name"]
def is_previewable(self):
"""Returns ``True`` if at least one preview mode is specified in ``preview_modes``."""
return bool(self.preview_modes)

Wyświetl plik

@ -63,10 +63,12 @@ from wagtail.test.testapp.models import (
AdvertWithCustomPrimaryKey,
AdvertWithCustomUUIDPrimaryKey,
AdvertWithTabbedInterface,
CustomPreviewSizesModel,
DraftStateCustomPrimaryKeyModel,
DraftStateModel,
FullFeaturedSnippet,
MultiPreviewModesModel,
PreviewableModel,
RevisableChildModel,
RevisableModel,
SnippetChooserModel,
@ -1991,6 +1993,49 @@ class TestSnippetEditView(BaseTestSnippetEditView):
html=True,
)
def test_previewable_snippet(self):
self.test_snippet = PreviewableModel.objects.create(
text="Preview-enabled snippet"
)
response = self.get()
self.assertEqual(response.status_code, 200)
soup = self.get_soup(response.content)
radios = soup.select('input[type="radio"][name="preview-size"]')
self.assertEqual(len(radios), 3)
self.assertEqual(
[
"Preview in mobile size",
"Preview in tablet size",
"Preview in desktop size",
],
[radio["aria-label"] for radio in radios],
)
self.assertEqual("375", radios[0]["data-device-width"])
self.assertTrue(radios[0].has_attr("checked"))
def test_custom_preview_sizes(self):
self.test_snippet = CustomPreviewSizesModel.objects.create(
text="Preview-enabled with custom sizes",
)
response = self.get()
self.assertEqual(response.status_code, 200)
soup = self.get_soup(response.content)
radios = soup.select('input[type="radio"][name="preview-size"]')
self.assertEqual(len(radios), 2)
self.assertEqual("412", radios[0]["data-device-width"])
self.assertEqual("Custom mobile preview", radios[0]["aria-label"])
self.assertFalse(radios[0].has_attr("checked"))
self.assertEqual("1280", radios[1]["data-device-width"])
self.assertEqual("Original desktop", radios[1]["aria-label"])
self.assertTrue(radios[1].has_attr("checked"))
class TestEditTabbedSnippet(BaseTestSnippetEditView):
def setUp(self):

Wyświetl plik

@ -0,0 +1,52 @@
# Generated by Django 5.0.9 on 2024-10-16 05:17
import django.db.models.deletion
import wagtail.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("tests", "0043_customimage_description"),
("wagtailcore", "0094_alter_page_locale"),
]
operations = [
migrations.CreateModel(
name="CustomPreviewSizesModel",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField()),
],
bases=(wagtail.models.PreviewableMixin, models.Model),
),
migrations.CreateModel(
name="CustomPreviewSizesPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
]

Wyświetl plik

@ -215,6 +215,31 @@ class MultiPreviewModesPage(Page):
return super().get_preview_template(request, mode_name)
class CustomPreviewSizesPage(Page):
template = "tests/simple_page.html"
@property
def preview_sizes(self):
return [
{
"name": "custom-mobile",
"icon": "mobile-alt",
"device_width": 412,
"label": "Custom mobile preview",
},
{
"name": "desktop",
"icon": "desktop",
"device_width": 1280,
"label": "Original desktop",
},
]
@property
def default_preview_size(self):
return "desktop"
# Page with Excluded Fields when copied
class PageWithExcludedCopyField(Page):
content = models.TextField()
@ -1083,6 +1108,34 @@ class PreviewableModel(PreviewableMixin, ClusterableModel):
register_snippet(PreviewableModel)
class CustomPreviewSizesModel(PreviewableMixin, models.Model):
text = models.TextField()
@property
def preview_sizes(self):
return [
{
"name": "custom-mobile",
"icon": "mobile-alt",
"device_width": 412,
"label": "Custom mobile preview",
},
{
"name": "desktop",
"icon": "desktop",
"device_width": 1280,
"label": "Original desktop",
},
]
@property
def default_preview_size(self):
return "desktop"
register_snippet(CustomPreviewSizesModel)
class MultiPreviewModesModel(PreviewableMixin, RevisionMixin, models.Model):
text = models.TextField()