Slim sidebar: remember collapsed state

pull/7372/head
Storm Heg 2021-07-23 11:47:50 +02:00 zatwierdzone przez GitHub
rodzic 2c4db8f2b1
commit 952264a2ab
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 78 dodań i 21 usunięć

Wyświetl plik

@ -307,6 +307,7 @@ body.explorer-open {
}
body.sidebar-collapsed .wrapper {
@include transition(padding-left $menu-transition-duration ease);
padding-left: $menu-width-slim;
}

Wyświetl plik

@ -237,6 +237,7 @@ function renderSidebarStory(
return (
<div className="wrapper">
<Sidebar
collapsedOnLoad={false}
modules={modules}
currentPath={currentPath}
strings={strings || STRINGS}

Wyświetl plik

@ -30,17 +30,23 @@ export interface SidebarProps {
modules: ModuleDefinition[];
currentPath: string;
strings: Strings;
collapsedOnLoad: boolean;
navigate(url: string): Promise<void>;
onExpandCollapse?(collapsed: boolean);
}
export const Sidebar: React.FunctionComponent<SidebarProps> = (
{ modules, currentPath, strings, navigate, onExpandCollapse }) => {
{ modules, currentPath, collapsedOnLoad, strings, navigate, onExpandCollapse }) => {
// 'collapsed' is a persistent state that is controlled by the arrow icon at the top
// It records the user's general preference for a collapsed/uncollapsed menu
// This is just a hint though, and we may still collapse the menu if the screen is too small
// Also, we may display the full menu temporarily in collapsed mode (see 'peeking' below)
const [collapsed, setCollapsed] = React.useState(window.innerWidth < 800);
const [collapsed, setCollapsed] = React.useState((): boolean => {
if (window.innerWidth < 800 || collapsedOnLoad) {
return true;
}
return false;
});
// Call onExpandCollapse(true) if menu is initialised in collapsed state
React.useEffect(() => {

Wyświetl plik

@ -1,8 +1,11 @@
import * as React from 'react';
import ReactDOM from 'react-dom';
import Cookies from 'js-cookie';
import { Sidebar } from './Sidebar';
export const SIDEBAR_COLLAPSED_COOKIE_NAME = 'wagtail_sidebar_collapsed';
export function initSidebar() {
const element = document.getElementById('wagtail-sidebar');
@ -20,11 +23,17 @@ export function initSidebar() {
if (element instanceof HTMLElement && element.dataset.props) {
const props = window.telepath.unpack(JSON.parse(element.dataset.props));
const onExpandCollapse = (collapsed: boolean) => {
if (collapsed) {
const collapsedCookie: any = Cookies.get(SIDEBAR_COLLAPSED_COOKIE_NAME);
// Cast to boolean
const collapsed = !((collapsedCookie === undefined || collapsedCookie === '0'));
const onExpandCollapse = (_collapsed: boolean) => {
if (_collapsed) {
document.body.classList.add('sidebar-collapsed');
Cookies.set(SIDEBAR_COLLAPSED_COOKIE_NAME, 1);
} else {
document.body.classList.remove('sidebar-collapsed');
Cookies.set(SIDEBAR_COLLAPSED_COOKIE_NAME, 0);
}
};
@ -32,6 +41,7 @@ export function initSidebar() {
<Sidebar
modules={props.modules}
strings={wagtailConfig.STRINGS}
collapsedOnLoad={collapsed}
currentPath={window.location.pathname}
navigate={navigate}
onExpandCollapse={onExpandCollapse}

Wyświetl plik

@ -26,7 +26,6 @@ declare global {
/* eslint-disable-next-line camelcase */
display_name: string;
}[];
STRINGS: any;
}
const wagtailConfig: WagtailConfig;

5
package-lock.json wygenerowano
Wyświetl plik

@ -20259,6 +20259,11 @@
}
}
},
"js-cookie": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
},
"js-string-escape": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",

Wyświetl plik

@ -107,6 +107,7 @@
"focus-trap-react": "^8.4.2",
"formdata-polyfill": "^3.0.20",
"immer": "^9.0.1",
"js-cookie": "^2.2.1",
"postcss-calc": "^7.0.5",
"prop-types": "^15.6.2",
"react": "^16.14.0",

Wyświetl plik

@ -3,32 +3,32 @@
{% block furniture %}
{% slim_sidebar_enabled as slim_sidebar_enabled %}
<aside id="wagtail-sidebar" class="nav-wrapper" {% if slim_sidebar_enabled %}data-props="{% menu_props %}"{% else %}data-nav-primary{% endif %}>
{% if slim_sidebar_enabled %}
<aside id="wagtail-sidebar" data-props="{% menu_props %}"></aside>
{% else %}
<aside id="wagtail-sidebar" class="nav-wrapper" data-nav-primary>
<div class="inner">
<a href="{% url 'wagtailadmin_home' %}" class="logo" aria-label="{% trans 'Dashboard' %}">
{% block branding_logo %}
{% if not slim_sidebar_enabled %}
{# Mobile-only logo: #}
<div class="wagtail-logo-container__mobile u-hidden@sm">
<img class="wagtail-logo wagtail-logo__full" src="{% versioned_static 'wagtailadmin/images/wagtail-logo.svg' %}" alt="" width="80" />
</div>
{# Mobile-only logo: #}
<div class="wagtail-logo-container__mobile u-hidden@sm">
<img class="wagtail-logo wagtail-logo__full" src="{% versioned_static 'wagtailadmin/images/wagtail-logo.svg' %}" alt="" width="80" />
</div>
{# Desktop logo (animated): #}
{% include "wagtailadmin/shared/animated_logo.html" %}
{% endif %}
{# Desktop logo (animated): #}
{% include "wagtailadmin/shared/animated_logo.html" %}
{% endblock %}
<span class="u-hidden@sm">{% trans "Dashboard" %}</span>
</a>
{% if not slim_sidebar_enabled %}
{% menu_search %}
{% main_nav %}
{% endif %}
{% menu_search %}
{% main_nav %}
</div>
<div class="explorer__wrapper" data-explorer-menu></div>
</aside>
{% endif %}
<main class="content-wrapper" role="main" id="main">
<main class="content-wrapper {% if slim_sidebar_enabled %}sidebar--open{% endif %}" role="main" id="main">
<div class="content">
{# Always show messages div so it can be appended to by JS #}
<div class="messages">

Wyświetl plik

@ -18,7 +18,9 @@
{% block branding_favicon %}{% endblock %}
</head>
<body id="wagtail" class="{% block bodyclass %}{% endblock %} {% if messages %}has-messages{% endif %} focus-outline-on">
{% slim_sidebar_enabled as slim_sidebar_enabled %}
{% sidebar_collapsed as sidebar_collapsed %}
<body id="wagtail" class="{% block bodyclass %}{% endblock %} {% if slim_sidebar_enabled and sidebar_collapsed %}sidebar-collapsed{% endif %} {% if messages %}has-messages{% endif %} focus-outline-on">
<div data-sprite></div>
<script>
function loadIconSprite() {

Wyświetl plik

@ -678,6 +678,15 @@ def slim_sidebar_enabled():
return 'slim-sidebar' in getattr(settings, 'WAGTAIL_EXPERIMENTAL_FEATURES', [])
@register.simple_tag(takes_context=True)
def sidebar_collapsed(context):
request = context.get('request')
collapsed = request.COOKIES.get('wagtail_sidebar_collapsed', '0')
if collapsed == '0':
return False
return True
@register.simple_tag(takes_context=True)
def menu_props(context):
request = context['request']

Wyświetl plik

@ -1,4 +1,5 @@
from django.test import RequestFactory, TestCase
from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse
from wagtail.admin.menu import AdminOnlyMenuItem, Menu, MenuItem, SubmenuMenuItem
from wagtail.admin.ui import sidebar
@ -17,6 +18,28 @@ class TestMenuRendering(TestCase, WagtailTestUtils):
def setUp(self):
self.request = RequestFactory().get('/admin')
self.request.user = self.create_superuser(username='admin')
self.user = self.login()
@override_settings(WAGTAIL_EXPERIMENTAL_FEATURES={"slim-sidebar"})
def test_remember_collapsed(self):
'''Sidebar should render with collapsed class applied.'''
# Sidebar should not be collapsed
self.client.cookies['wagtail_sidebar_collapsed'] = '0'
response = self.client.get(reverse('wagtailadmin_home'))
self.assertNotContains(response, 'sidebar-collapsed')
# Sidebar should be collapsed
self.client.cookies['wagtail_sidebar_collapsed'] = '1'
response = self.client.get(reverse('wagtailadmin_home'))
self.assertContains(response, 'sidebar-collapsed')
@override_settings(WAGTAIL_EXPERIMENTAL_FEATURES={})
def test_collapsed_only_with_feature_flag(self):
'''Sidebar should only remember its collapsed state with the right feature flag set.'''
# Sidebar should not be collapsed because the feature flag is not enabled
self.client.cookies['wagtail_sidebar_collapsed'] = '1'
response = self.client.get(reverse('wagtailadmin_home'))
self.assertNotContains(response, 'sidebar-collapsed')
def test_simple_menu(self):
# Note: initialise the menu before registering hooks as this is what happens in reality.