Member index phase 2 - mock filters modal (#17578)
* mock filters popover * fix for safari * add missing label
This commit is contained in:
parent
256ba5e8f5
commit
c37bbd77e5
10 changed files with 143 additions and 16 deletions
3
app/assets/images/chevron-down.svg
Normal file
3
app/assets/images/chevron-down.svg
Normal 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 |
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@
|
|||
height: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 0;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
&.crayons-modal--left {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
28
app/javascript/packs/admin/users/controls.js
vendored
28
app/javascript/packs/admin/users/controls.js
vendored
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -124,3 +124,6 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<% if FeatureFlag.enabled?(:member_index_view) %>
|
||||
<%= render "admin/users/index/filters_modal" %>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
40
app/views/admin/users/index/_filters_modal.html.erb
Normal file
40
app/views/admin/users/index/_filters_modal.html.erb
Normal 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>
|
||||
Loading…
Add table
Reference in a new issue