mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-10-29 10:18:29 -04:00
One actions_menu helper now builds the three-dot toggle and dropdown for seeds, harvests, crops, gardens, posts, photos, activities and comments, replacing the text "Actions" toggle. Every item carries a green line icon (menu_icon), and delete uses a darker red ($danger-text, 5.6:1 on white) so it stays readable; it is still last, under a divider, with its own icon. The React menus draw the same icons. DESIGN.md now says menu items have icons. Also fixes the posts menu delete, which confirmed but never sent DELETE. Closes #4939 Closes #4940 Closes #4942 Closes #4943 Closes #4944 Closes #4945 Closes #4946 Part of #4933 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
63 lines
2.3 KiB
React
63 lines
2.3 KiB
React
import React from 'react';
|
|
|
|
import MenuIcon from './MenuIcon';
|
|
|
|
// A Bootstrap dropdown of links. The server decides the items (label, href,
|
|
// and for non-GET links `method` and `confirm`); we render them with the
|
|
// data-method / data-confirm attributes that jquery_ujs already handles, and
|
|
// Bootstrap's delegated data-api drives the dropdown, so neither needs to
|
|
// know about React.
|
|
// A click that onSelect has taken over (by preventing the link) is not the page's
|
|
// any more: jquery_ujs, further up the page, would still send the link's
|
|
// data-method request (as for "mark as finished"), and Bootstrap, which closes the
|
|
// menu as the click passes by, would not see it. So stop it here, and close the menu.
|
|
function handled(event, buttonId) {
|
|
event.stopPropagation();
|
|
const toggle = document.getElementById(buttonId);
|
|
const dropdown = toggle && window.bootstrap && window.bootstrap.Dropdown.getInstance(toggle);
|
|
if (dropdown) dropdown.hide();
|
|
}
|
|
|
|
export default function ActionsMenu({id, actions, label = 'Actions', ariaLabel, className = 'btn dropdown-toggle', menuClassName = 'dropdown-menu-end', onSelect}) {
|
|
if (!actions || actions.length === 0) return null;
|
|
|
|
const buttonId = `actions-${id}`;
|
|
|
|
return (
|
|
<div className="dropdown garden-actions actions-menu">
|
|
<a
|
|
id={buttonId}
|
|
className={className}
|
|
href="#"
|
|
role="button"
|
|
data-bs-toggle="dropdown"
|
|
aria-expanded="false"
|
|
aria-haspopup="true"
|
|
aria-label={ariaLabel}
|
|
>
|
|
{label}
|
|
</a>
|
|
<div className={`dropdown-menu ${menuClassName}`} aria-labelledby={buttonId}>
|
|
{actions.map((action) => (
|
|
<React.Fragment key={action.key}>
|
|
{action.divider && <div className="dropdown-divider" />}
|
|
<a
|
|
className={`dropdown-item${action.key === 'delete' ? ' text-danger' : ''}`}
|
|
href={action.href}
|
|
data-method={action.method}
|
|
data-confirm={action.confirm}
|
|
onClick={(event) => {
|
|
if (onSelect) onSelect(action, event);
|
|
if (event.defaultPrevented) handled(event, buttonId);
|
|
}}
|
|
>
|
|
<MenuIcon name={action.key} />
|
|
{action.label}
|
|
</a>
|
|
</React.Fragment>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|