Member index phase 2 - mock filters modal (#17578)

* mock filters popover

* fix for safari

* add missing label
This commit is contained in:
Suzanne Aitchison 2022-05-17 15:25:21 +01:00 committed by GitHub
parent 256ba5e8f5
commit c37bbd77e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 143 additions and 16 deletions

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m12 13.172 4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222l4.95 4.95Z"/>
</svg>

After

Width:  |  Height:  |  Size: 192 B

View file

@ -279,3 +279,19 @@ which may be more easily removed once we no longer wish admin layouts to have a
display: none;
}
}
.admin-details {
border-bottom: 1px solid var(--base-10);
summary::marker {
display: none;
}
summary::-webkit-details-marker {
display: none;
}
&[open] .summary-icon {
transform: rotate(180deg);
}
}

View file

@ -131,6 +131,7 @@
height: 100%;
max-height: 100%;
border-radius: 0;
grid-template-rows: 1fr;
}
&.crayons-modal--left {

View file

@ -15,6 +15,7 @@ export const Modal = ({
sheet,
centered,
noBackdrop,
showHeader = true,
sheetAlign = 'center',
backdropDismissible = false,
onClose = () => {},
@ -43,15 +44,17 @@ export const Modal = ({
aria-label="modal"
className="crayons-modal__box"
>
<header className="crayons-modal__box__header">
<h2 class="crayons-subtitle-2">{title}</h2>
<Button
icon={CloseIcon}
aria-label="Close"
className="crayons-modal__dismiss"
onClick={onClose}
/>
</header>
{showHeader && (
<header className="crayons-modal__box__header">
<h2 class="crayons-subtitle-2">{title}</h2>
<Button
icon={CloseIcon}
aria-label="Close"
className="crayons-modal__dismiss"
onClick={onClose}
/>
</header>
)}
<div className="crayons-modal__box__body">{children}</div>
</div>
{!noBackdrop && (
@ -80,4 +83,5 @@ Modal.propTypes = {
focusTrapSelector: PropTypes.string,
sheet: PropTypes.bool,
sheetAlign: PropTypes.oneOf(['center', 'left', 'right']),
showHeader: PropTypes.bool,
};

View file

@ -45,6 +45,13 @@ export default {
defaultValue: { summary: true },
},
},
showHeader: {
description:
'Whether or not to display the standard header (with title and close button). If `false`, make sure to provide an alternative close button.',
table: {
defaultValue: { summary: true },
},
},
backdropDismissible: {
description:
'If `backdrop` is visible you can also make it clickable so clicking it would dismiss the Modal',
@ -110,6 +117,11 @@ const Template = (args) => {
</p>
)}
</div>
{!args.showHeader && (
<Button variant="primary" onClick={() => setIsModalOpen(false)}>
OK
</Button>
)}
</Modal>
)}
</div>
@ -125,6 +137,7 @@ Default.args = {
prompt: false,
centered: false,
sheet: false,
showHeader: true,
};
export const Prompt = Template.bind({});
@ -137,6 +150,7 @@ Prompt.args = {
prompt: true,
centered: false,
sheet: false,
showHeader: true,
};
export const PromptCentered = Template.bind({});
@ -149,6 +163,7 @@ PromptCentered.args = {
prompt: true,
centered: true,
sheet: false,
showHeader: true,
};
export const Sheet = Template.bind({});
@ -160,6 +175,7 @@ Sheet.args = {
prompt: false,
centered: false,
sheet: true,
showHeader: true,
};
export const SheetLeftAligned = Template.bind({});
@ -172,6 +188,7 @@ SheetLeftAligned.args = {
centered: false,
sheet: true,
sheetAlign: 'left',
showHeader: true,
};
export const SheetRightAligned = Template.bind({});
@ -184,6 +201,7 @@ SheetRightAligned.args = {
centered: false,
sheet: true,
sheetAlign: 'right',
showHeader: true,
};
export const BackdropDismissible = Template.bind({});
@ -195,6 +213,7 @@ BackdropDismissible.args = {
prompt: false,
centered: false,
sheet: false,
showHeader: true,
};
export const NoBackdrop = Template.bind({});
@ -206,4 +225,17 @@ NoBackdrop.args = {
prompt: false,
centered: false,
sheet: false,
showHeader: true,
};
export const NoHeader = Template.bind({});
NoHeader.args = {
size: undefined,
title: 'Modal title',
noBackdrop: false,
backdropDismissible: false,
prompt: false,
centered: false,
sheet: false,
showHeader: false,
};

View file

@ -1,4 +1,9 @@
import { INTERACTIVE_ELEMENTS_QUERY } from '@utilities/dropdownUtils';
import {
showWindowModal,
closeWindowModal,
WINDOW_MODAL_ID,
} from '@utilities/showModal';
const expandSearchButton = document.getElementById('expand-search-btn');
const expandFilterButton = document.getElementById('expand-filter-btn');
@ -112,5 +117,28 @@ const toggleIndicator = ({ value, indicator }) => {
}
};
/**
* Controls the triggering of the filters popover modal
*/
const initializeFilterPopoverButtons = () => {
document.querySelectorAll('.js-open-filter-modal-btn').forEach((button) => {
button.addEventListener('click', () => {
showWindowModal({
contentSelector: '.js-filters-modal',
showHeader: false,
sheet: true,
sheetAlign: 'right',
size: 'small',
onOpen: () => {
document
.querySelector(`#${WINDOW_MODAL_ID} .js-filter-modal-cancel-btn`)
.addEventListener('click', closeWindowModal);
},
});
});
});
};
initializeExpandingSections();
initializeSectionIndicators();
initializeFilterPopoverButtons();

View file

@ -21,19 +21,16 @@ const getModalImports = () => {
/**
* This helper function finds the HTML with the given contentSelector, and presents it inside a Preact modal.
* Only one modal will be presented at any given time.
* Only one modal will be presented at any given time. All additional props will be passed directly to the Modal component.
*
* @param {Object} args
* @param {string} args.title The title of the modal (presented at the top of the modal dialog)
* @param {string} args.contentSelector The CSS query to locate the HTML to be presented in the modal (e.g. '#my-modal-content')
* @param {string} args.size The size prop for the modal ('small', 'medium', or 'large')
* @param {Function} args.onOpen A callback function to run when the modal opens. This can be useful, for example, to attach any event listeners to items inside the modal.
*/
export const showWindowModal = async ({
title,
contentSelector,
size = 'small',
onOpen,
...modalProps
}) => {
const [{ Modal }, { render, h }] = await getModalImports();
@ -49,14 +46,14 @@ export const showWindowModal = async ({
render(
<Modal
title={title}
onClose={() => {
render(null, currentModalContainer);
}}
size={size}
focusTrapSelector={`#${WINDOW_MODAL_ID}`}
{...modalProps}
>
<div
className="h-100 w-100"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: document.querySelector(contentSelector).innerHTML,

View file

@ -124,3 +124,6 @@
</div>
</div>
<% if FeatureFlag.enabled?(:member_index_view) %>
<%= render "admin/users/index/filters_modal" %>
<% end %>

View file

@ -38,6 +38,9 @@
<div class="flex">
<%= paginate @users, theme: "admin", scope: @users, label: "Paginate users", context: "medium" %>
<%= render "admin/users/controls/export" %>
<% if FeatureFlag.enabled?(:member_index_view) %>
<button aria-label="Filter" class="js-open-filter-modal-btn c-btn c-btn--icon-alone"><%= crayons_icon_tag("filter", aria_hidden: true) %></button>
<% end %>
</div>
</div>

View file

@ -0,0 +1,40 @@
<div class="js-filters-modal hidden">
<%= form_with url: admin_users_path, method: :get, local: true, class: "flex flex-col h-100" do |f| %>
<div class="flex justify-between items-center border-0 border-b-1 border-base-10 border-solid -mx-7 px-7 pb-2">
<h2 class="crayons-subtitle-2">Filters</h2>
<button type="button" class="c-btn">Clear filters</button>
</div>
<div class="py-4">
<details class="admin-details">
<summary class="py-4 flex justify-between text-uppercase color-base-60 fs-s">Member roles<%= crayons_icon_tag("chevron-down", aria_hidden: true, class: "summary-icon") %></summary>
<fieldset class="pb-4">
<legend class="screen-reader-only">Member roles</legend>
<div class="crayons-field crayons-field--radio">
<%= f.radio_button :role, "admin", class: "crayons-radio", role: "radio", id: "admin" %>
<%= label_tag "admin", "Admin", class: "crayons-field__label" %>
</div>
</fieldset>
</details>
<details class="admin-details">
<summary class="py-4 flex justify-between text-uppercase color-base-60 fs-s">Status<%= crayons_icon_tag("chevron-down", aria_hidden: true, class: "summary-icon") %></summary>
Status options
</details>
<details class="admin-details">
<summary class="py-4 flex justify-between text-uppercase color-base-60 fs-s">Joining date<%= crayons_icon_tag("chevron-down", aria_hidden: true, class: "summary-icon") %></summary>
Joining date options
</details>
<details class="admin-details">
<summary class="py-4 flex justify-between text-uppercase color-base-60 fs-s">Last activity<%= crayons_icon_tag("chevron-down", aria_hidden: true, class: "summary-icon") %></summary>
Last activity options
</details>
<details class="admin-details">
<summary class="py-4 flex justify-between text-uppercase color-base-60 fs-s">Organizations<%= crayons_icon_tag("chevron-down", aria_hidden: true, class: "summary-icon") %></summary>
Organizations options
</details>
</div>
<div class="flex gap-2 mt-auto">
<button class="c-btn c-btn--primary grow-1">Apply filters</button>
<button type="button" class="js-filter-modal-cancel-btn c-btn grow-1">Cancel</button>
</div>
<% end %>
</div>