Skip to content

Commit

Permalink
feature #6649 Add a new Twig component to create Action Menus (javier…
Browse files Browse the repository at this point in the history
…eguiluz)

This PR was squashed before being merged into the 4.x branch.

Discussion
----------

Add a new Twig component to create Action Menus

This is the first anonymous Twig Component that we added to the project. It's modeled after GitHub's `ActionMenu` component (https://primer.style/components/action-menu) and allows to create dropdowns.

Sadly, using this component means that we lost the `{% block user_menu %}...{% endblock %}` TWig block in the template. This is because I can't make it work with the new Twig component. If anybody knows how to keep that block, please tell me. Thanks!

-----

Again, this was possible thanks to the excellent article written by `@yceruto` in https://dev.to/yceruto/bundling-your-symfony-ux-twig-components-4997

Just a quick comment for `@yceruto`. In this section: https://dev.to/yceruto/bundling-your-symfony-ux-twig-components-4997#bundling-uionly-components you propose to use this:

```php
        $builder->prependExtensionConfig('twig', [
            'paths' => [
                'templates/bundles/AcmeBundle/' => null,
                dirname(__DIR__).'/templates/' => null,
            ],
        ]);
```

This didn't work for me because the application that installs the bundle might not have defined the `templates/bundles/AcmeBundle/` dir. Maybe I'm doing something wrong ... but in any case, I updated it as follows:

```php
        $bundleTemplatesOverrideDir = $builder->getParameter('kernel.project_dir').'/templates/bundles/EasyAdminBundle/';
        $builder->prependExtensionConfig('twig', [
            'paths' => is_dir($bundleTemplatesOverrideDir)
                ? [
                    'templates/bundles/EasyAdminBundle/' => null,
                    dirname(__DIR__).'/../templates/' => 'ea',
                ]
                : [
                    dirname(__DIR__).'/../templates/' => 'ea',
                ],
        ]);
```

Commits
-------

da8ece2 Add a new Twig component to create Action Menus
  • Loading branch information
javiereguiluz committed Jan 4, 2025
2 parents 7eb3f83 + da8ece2 commit bd70f3b
Show file tree
Hide file tree
Showing 20 changed files with 216 additions and 112 deletions.
9 changes: 9 additions & 0 deletions assets/css/easyadmin-theme/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ body.ea-mobile-sidebar-visible .sidebar {
inset-inline-start: 0;
}

.dropdown-toggle.dropdown-toggle-hidden-marker:after { display: none; }
.dropdown-toggle.dropdown-toggle-hidden-marker:hover { cursor: pointer; }

.user-menu-wrapper a.user-details,
a.user-menu-wrapper .user-details:hover {
align-items: center;
Expand Down Expand Up @@ -232,6 +235,9 @@ a.user-menu-wrapper .user-details:hover {
inline-size: 2em;
text-align: center;
}
.user-menu-wrapper .dropdown-user-details .user-avatar .icon {
display: block;
}

.user-menu-wrapper .dropdown-menu {
min-inline-size: 200px;
Expand Down Expand Up @@ -718,6 +724,9 @@ a.user-menu-wrapper .user-details:hover {
margin: 0 10px 0 4px;
font-size: 15px;
}
.dropdown-menu .icon {
display: inline-flex;
}

.dropdown-menu .dropdown-item,
.dropdown-menu .dropdown-header {
Expand Down
19 changes: 14 additions & 5 deletions assets/css/easyadmin-theme/datagrids.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ table.datagrid {
margin-block-end: 0;
inline-size: 100%;
}
table.datagrid:not(.datagrid-empty) tr:not(.empty-row) td.actions,
table.datagrid:not(.datagrid-empty) tr:not(.empty-row) td.actions.actions-as-dropdown {
min-width: 50px;
}
@media (max-width: 767px) {
table.datagrid:not(.datagrid-empty) tbody,
table.datagrid:not(.datagrid-empty) tr,
Expand Down Expand Up @@ -182,17 +186,22 @@ table.datagrid {
outline: none;
}

.datagrid .dropdown-actions {
display: inline-block;
}
.datagrid .dropdown-actions .dropdown-toggle {
border: 1px solid transparent;
border-radius: var(--border-radius);
color: var(--dropdown-toggle-color);
padding: 3px 5px;
display: block;
padding: 1px 5px;
}
/* hides the caret added automatically by Bootstrap */
.datagrid .dropdown-actions .dropdown-toggle:after { display: none; }
.datagrid .dropdown-actions .dropdown-toggle:hover { cursor: pointer; }

.datagrid .dropdown-actions .dropdown-toggle svg { vertical-align: top; }
.datagrid .dropdown-actions .dropdown-toggle .icon {
display: block;
font-size: 21px;
inline-size: unset;
}

.datagrid .dropdown-actions .dropdown-menu { z-index: var(--zindex-900); }

Expand Down
4 changes: 4 additions & 0 deletions assets/icons/internal/dots-horizontal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"symfony/uid": "^5.4|^6.0|^7.0",
"symfony/ux-twig-component": "^2.21",
"symfony/validator": "^5.4|^6.0|^7.0",
"twig/extra-bundle": "^3.17",
"twig/html-extra": "^3.17",
"twig/twig": "^3.15"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion public/app.25fa02d0.css → public/app.62f32d02.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/entrypoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"entrypoints": {
"app": {
"css": [
"/app.25fa02d0.css"
"/app.62f32d02.css"
],
"js": [
"/app.1ecd6d7a.js"
Expand Down
2 changes: 1 addition & 1 deletion public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"app.css": "app.25fa02d0.css",
"app.css": "app.62f32d02.css",
"app.js": "app.1ecd6d7a.js",
"form.js": "form.bcec6c2a.js",
"page-layout.js": "page-layout.3347892e.js",
Expand Down
12 changes: 12 additions & 0 deletions src/DependencyInjection/EasyAdminExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,17 @@ public function prepend(ContainerBuilder $builder): void
],
],
]);

$bundleTemplatesOverrideDir = $builder->getParameter('kernel.project_dir').'/templates/bundles/EasyAdminBundle/';
$builder->prependExtensionConfig('twig', [
'paths' => is_dir($bundleTemplatesOverrideDir)
? [
'templates/bundles/EasyAdminBundle/' => 'ea',
\dirname(__DIR__).'/../templates/' => 'ea',
]
: [
\dirname(__DIR__).'/../templates/' => 'ea',
],
]);
}
}
7 changes: 7 additions & 0 deletions templates/components/ActionMenu.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{# ActionMenu is a component to create dropdowns of related actions.
It defines several sub-components (Overlay, ActionList, etc.)
Inspired by https://primer.style/components/action-menu
#}
<div {{ attributes.defaults({class: 'dropdown'}) }}>
<twig:block name="content"></twig:block>
</div>
3 changes: 3 additions & 0 deletions templates/components/ActionMenu/ActionList.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<ul {{ attributes.defaults({class: 'dropdown-menu dropdown-menu-end'}) }}>
<twig:block name="content"></twig:block>
</ul>
3 changes: 3 additions & 0 deletions templates/components/ActionMenu/ActionList/Content.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<li {{ attributes }}>
<twig:block name="content"></twig:block>
</li>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<li class="dropdown-divider"></li>
13 changes: 13 additions & 0 deletions templates/components/ActionMenu/ActionList/Header.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% props
label = null,
renderLabelRaw = false,
icon = null,
htmlAttributes = {},
%}

{% if label is not empty or icon is not empty %}
<li {{ attributes.defaults({class: 'dropdown-header'}|merge(htmlAttributes)) }}>
{%- if icon %}<twig:ea:Icon {{ ...attributes.nested('icon').defaults({name: icon}) }} /> {% endif -%}
{%- if label is not empty -%}<span {{ attributes.nested('label') }}>{{ renderLabelRaw ? label|raw : label }}</span>{%- endif -%}
</li>
{% endif %}
14 changes: 14 additions & 0 deletions templates/components/ActionMenu/ActionList/Item.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% props
label = null,
renderLabelRaw = false,
icon = null,
url = null,
htmlAttributes = {},
%}

<li>
<a {{ attributes.defaults({class: 'dropdown-item', href: url}|merge(htmlAttributes)) }}>
{%- if icon %}<twig:ea:Icon {{ ...attributes.nested('icon').defaults({name: icon}) }} /> {% endif -%}
{%- if label is not empty -%}<span {{ attributes.nested('label') }}>{{ renderLabelRaw ? label|raw : label }}</span>{%- endif -%}
</a>
</li>
12 changes: 12 additions & 0 deletions templates/components/ActionMenu/Button.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% props
withoutDropdownToggleMarker = false,
%}

{% set css_class = html_classes(
'dropdown-toggle',
{ 'dropdown-toggle-hidden-marker': withoutDropdownToggleMarker }
) %}

<a {{ attributes.defaults({class: css_class, href: '#', role: 'button', 'data-bs-toggle': 'dropdown', 'aria-haspopup': 'true', 'aria-expanded': 'false'}) }}>
<twig:block name="content"></twig:block>
</a>
3 changes: 3 additions & 0 deletions templates/components/ActionMenu/Overlay.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div {{ attributes.defaults({class: 'dropdown-overlay'}) }}>
<twig:block name="content"></twig:block>
</div>
32 changes: 17 additions & 15 deletions templates/crud/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,23 @@
<td class="actions {{ ea.crud.showEntityActionsAsDropdown ? 'actions-as-dropdown' }}">
{% if entity.actions.count > 0 %}
{% if ea.crud.showEntityActionsAsDropdown %}
<div class="dropdown dropdown-actions">
<a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{# don't use FontAwesome 'fa-ellipsis-h' icon here because it doesn't look good #}
{# this icon is 'dots-horizontal' icon from https://heroicons.com/ #}
<svg xmlns="http://www.w3.org/2000/svg" height="21" width="21" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z" />
</svg>
</a>

<div class="dropdown-menu dropdown-menu-right">
{% for action in entity.actions %}
{{ include(action.templatePath, { action: action, entity: entity, isIncludedInDropdown: ea.crud.showEntityActionsAsDropdown }, with_context = false) }}
{% endfor %}
</div>
</div>
<twig:ea:ActionMenu class="dropdown-actions">
<twig:ea:ActionMenu:Button withoutDropdownToggleMarker>
<twig:ea:Icon name="internal:dots-horizontal" />
</twig:ea:ActionMenu:Button>

<twig:ea:ActionMenu:Overlay>
<twig:ea:ActionMenu:ActionList>
{% for action in entity.actions %}
<twig:ea:ActionMenu:ActionList:Item
class="{{ action.cssClass }}" url="{{ action.linkUrl }}"
icon="{{ action.icon }}" icon:class="action-icon"
htmlAttributes="{{ action.htmlAttributes }}"
label="{{ action.label|trans }}" label:class="action-label" renderLabelRaw />
{% endfor %}
</twig:ea:ActionMenu:ActionList>
</twig:ea:ActionMenu:Overlay>
</twig:ea:ActionMenu>
{% else %}
{% for action in entity.actions %}
{{ include(action.templatePath, { action: action, entity: entity, isIncludedInDropdown: ea.crud.showEntityActionsAsDropdown }, with_context = false) }}
Expand Down
Loading

0 comments on commit bd70f3b

Please sign in to comment.