Skip to content

Commit cb94fff

Browse files
chore: Refactor the popups
1 parent 2e98707 commit cb94fff

16 files changed

Lines changed: 824 additions & 975 deletions

File tree

locales/fr_FR/LC_MESSAGES/main.mo

0 Bytes
Binary file not shown.

locales/fr_FR/LC_MESSAGES/main.po

Lines changed: 97 additions & 104 deletions
Large diffs are not rendered by default.

src/assets/javascripts/controllers/popup_controller.js

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,6 @@ import { Controller } from '@hotwired/stimulus';
22

33
export default class extends Controller {
44
connect () {
5-
const openerElement = this.element.querySelector('.popup__opener');
6-
if (openerElement) {
7-
openerElement.setAttribute('aria-haspopup', 'menu');
8-
openerElement.setAttribute('aria-expanded', this.element.open);
9-
}
10-
11-
const containerElement = this.element.querySelector('.popup__container');
12-
if (containerElement) {
13-
containerElement.setAttribute('role', 'menu');
14-
}
15-
16-
const itemsElements = this.element.querySelectorAll('.popup__item');
17-
itemsElements.forEach((element) => {
18-
element.setAttribute('role', 'menuitem');
19-
});
20-
215
this.element.addEventListener('keydown', this.closeOnEscape.bind(this));
226
this.element.addEventListener('keydown', this.toggleMenuOnKeydown.bind(this));
237
this.element.addEventListener('keydown', this.navigateInMenuOnArrow.bind(this));

src/views/collections/show.html.twig

Lines changed: 54 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -178,118 +178,75 @@
178178
{% endif %}
179179
{% endif %}
180180

181-
<details
182-
class="popup"
183-
data-controller="popup"
184-
data-action="toggle->popup#update click@window->popup#closeOnClickOutside keydown->popup#closeOnEscape"
185-
>
186-
<summary class="popup__opener">
187-
<span class="button">
188-
{{ icon('menu') }}
189-
{{ t('Actions') }}
190-
</span>
191-
</summary>
181+
{% embed 'components/popup.html.twig' %}
182+
{% block opener %}
183+
{{ icon('menu') }}
184+
{{ t('Actions') }}
185+
{% endblock %}
186+
187+
{% block items %}
188+
{% import _self as item %}
192189

193-
<nav class="popup__container popup__container--center">
194190
{% if is_following %}
195-
<button
196-
class="popup__item"
197-
data-controller="modal-opener"
198-
data-action="modal-opener#fetch"
199-
data-modal-opener-href-value="{{ url('edit collection filter', { id: collection.id }) }}"
200-
aria-haspopup="dialog"
201-
aria-controls="modal"
202-
>
203-
{{ icon('slider') }}
204-
{{ t('Adjust for the news') }}
205-
</button>
191+
{{ item.modal(
192+
url: url('edit collection filter', { id: collection.id }),
193+
label: t('Adjust for the news'),
194+
icon: 'slider',
195+
) }}
206196
{% endif %}
207197

208198
{% if can_update or (is_following and not app.user.isAlphaEnabled) %}
209-
<button
210-
class="popup__item"
211-
data-controller="modal-opener"
212-
data-action="modal-opener#fetch"
213-
data-modal-opener-href-value="{{ url('edit group collection', { id: collection.id }) }}"
214-
aria-haspopup="dialog"
215-
aria-controls="modal"
216-
>
217-
{{ icon('directory') }}
218-
{{ t('Put in a group') }}
219-
</button>
199+
{{ item.modal(
200+
url: url('edit group collection', { id: collection.id }),
201+
label: t('Put in a group'),
202+
icon: 'directory',
203+
) }}
220204

221-
<div class="popup__separator"></div>
205+
{{ item.separator() }}
222206
{% endif %}
223207

224-
<div data-controller="copy-to-clipboard">
225-
<input type="hidden" value="{{ url_full('collection', { id: collection.id }) }}" data-copy-to-clipboard-target="copyable">
208+
{{ item.clipboard(
209+
value: url_full('collection', { id: collection.id }),
210+
label: t('Copy link to collection'),
211+
) }}
226212

227-
<button
228-
class="popup__item"
229-
data-action="copy-to-clipboard#copy"
230-
data-copy-to-clipboard-target="feedback"
231-
>
232-
{{ icon('copy-to-clipboard') }}
233-
{{ t('Copy link to collection') }}
234-
</button>
235-
</div>
236-
237-
<div data-controller="copy-to-clipboard">
238-
<input type="hidden" value="{{ url_full('collection feed', { id: collection.id }) }}" data-copy-to-clipboard-target="copyable">
239-
240-
<button
241-
class="popup__item"
242-
data-action="copy-to-clipboard#copy"
243-
data-copy-to-clipboard-target="feedback"
244-
>
245-
{{ icon('feed') }}
246-
{{ t('Copy link to Web feed') }}
247-
</button>
248-
</div>
213+
{{ item.clipboard(
214+
value: url_full('collection feed', { id: collection.id }),
215+
label: t('Copy link to Web feed'),
216+
icon: 'feed',
217+
) }}
249218

250219
{% if is_following %}
251-
<div class="popup__separator"></div>
252-
253-
<form method="post" action="{{ url('mark collection as read', { id: collection.id }) }}">
254-
<button class="popup__item">
255-
{{ icon('check') }}
256-
{{ t('Mark all as read') }}
257-
</button>
258-
259-
<input type="hidden" name="csrf_token" value="{{ csrf_token('collections\\MarkCollectionAsRead') }}">
260-
</form>
261-
262-
<form method="post" action="{{ url('never read collection', { id: collection.id }) }}">
263-
<button class="popup__item">
264-
{{ icon('times') }}
265-
{{ t('Remove the links from the news') }}
266-
</button>
267-
268-
<input type="hidden" name="csrf_token" value="{{ csrf_token('collections\\MarkCollectionAsNever') }}">
269-
</form>
220+
{{ item.separator() }}
221+
222+
{{ item.action(
223+
url: url('mark collection as read', { id: collection.id }),
224+
label: t('Mark all as read'),
225+
icon: 'check',
226+
csrf: 'collections\\MarkCollectionAsRead',
227+
) }}
228+
229+
{{ item.action(
230+
url: url('never read collection', { id: collection.id }),
231+
label: t('Remove the links from the news'),
232+
icon: 'times',
233+
csrf: 'collections\\MarkCollectionAsNever',
234+
) }}
270235
{% endif %}
271236

272237
{% if can_delete %}
273-
<div class="popup__separator"></div>
274-
275-
<form
276-
method="post"
277-
action="{{ url('delete collection', { id: collection.id }) }}"
278-
data-turbo-confirm="{{ t('Are you sure that you want to delete this collection? You may lose the links that are attached only to this collection.') }}"
279-
>
280-
<button
281-
type="submit"
282-
class="popup__item"
283-
>
284-
{{ icon('trash') }}
285-
{{ t('Delete') }}
286-
</button>
287-
288-
<input type="hidden" name="csrf_token" value="{{ csrf_token('collections\\DeleteCollection') }}">
289-
</form>
238+
{{ item.separator() }}
239+
240+
{{ item.action(
241+
url: url('delete collection', { id: collection.id }),
242+
label: t('Delete'),
243+
icon: 'trash',
244+
csrf: 'collections\\DeleteCollection',
245+
confirm: t('Are you sure that you want to delete this collection? You may lose the links that are attached only to this collection.'),
246+
) }}
290247
{% endif %}
291-
</nav>
292-
</details>
248+
{% endblock %}
249+
{% endembed %}
293250
</div>
294251

295252
{{ include('links/_pagination_count.html.twig') }}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
{#
2+
# A popup menu, to be used with {% embed %}:
3+
#
4+
# {% embed 'components/popup.html.twig' with {
5+
# opener_class: 'button button--ghost button--icon',
6+
# position: 'right',
7+
# tooltip: t('Actions'),
8+
# } %}
9+
# {% block opener %}
10+
# {{ icon('menu') }}
11+
#
12+
# <span class="sr-only">{{ t('Actions') }}</span>
13+
# {% endblock %}
14+
#
15+
# {% block items %}
16+
# {% import _self as item %}
17+
#
18+
# {{ item.modal(
19+
# url: url('edit note', { id: note.id }),
20+
# label: t('Edit'),
21+
# icon: 'pencil',
22+
# ) }}
23+
#
24+
# {{ item.separator() }}
25+
#
26+
# {{ item.action(
27+
# url: url('delete note', { id: note.id }),
28+
# label: t('Delete'),
29+
# icon: 'trash',
30+
# csrf: 'notes\\DeleteNote',
31+
# ) }}
32+
# {% endblock %}
33+
# {% endembed %}
34+
#
35+
# The `opener` block is wrapped in a span classed with `opener_class`, `button`
36+
# by default. An empty `opener_class` renders the block without any wrapper.
37+
#
38+
# The items are rendered by the macros declared at the end of this file.
39+
#}
40+
{% types {
41+
class: 'string',
42+
opener_class: 'string',
43+
position: 'string',
44+
drop_up: 'boolean',
45+
tooltip: 'string',
46+
} %}
47+
48+
{% set class = class ?? '' %}
49+
{% set opener_class = opener_class ?? 'button' %}
50+
{% set position = position ?? 'center' %}
51+
{% set drop_up = drop_up ?? false %}
52+
{% set tooltip = tooltip ?? '' %}
53+
54+
<details
55+
class="popup{% if class %} {{ class }}{% endif %}"
56+
data-controller="popup"
57+
data-action="toggle->popup#update click@window->popup#closeOnClickOutside keydown->popup#closeOnEscape"
58+
>
59+
<summary
60+
class="popup__opener"
61+
aria-haspopup="menu"
62+
aria-expanded="false"
63+
{% if tooltip %}title="{{ tooltip }}"{% endif %}
64+
>
65+
{% if opener_class %}
66+
<span class="{{ opener_class }}">
67+
{% block opener %}{% endblock %}
68+
</span>
69+
{% else %}
70+
{{ block('opener') }}
71+
{% endif %}
72+
</summary>
73+
74+
<nav
75+
class="popup__container popup__container--{{ position }}{{ drop_up ? ' popup__container--top' }}"
76+
role="menu"
77+
>
78+
{% block items %}{% endblock %}
79+
</nav>
80+
</details>
81+
82+
{#
83+
# A title, to introduce a section of the menu.
84+
#}
85+
{% macro heading(label) %}
86+
<div class="popup__title">{{ label }}</div>
87+
{% endmacro %}
88+
89+
{#
90+
# A link to another page.
91+
#}
92+
{% macro link(url, label, icon = '', current = false) %}
93+
<a
94+
class="popup__item"
95+
role="menuitem"
96+
href="{{ url }}"
97+
{% if current %}aria-current="page"{% endif %}
98+
>
99+
{% if icon %}
100+
{{ icon(icon) }}
101+
{% endif %}
102+
103+
{{ label }}
104+
</a>
105+
{% endmacro %}
106+
107+
{#
108+
# A button submitting a POST form. `csrf` is passed to the csrf_token()
109+
# function, and `params` is rendered as a list of hidden inputs.
110+
#}
111+
{% macro action(url, label, csrf, icon = '', params = {}, confirm = '', preserve_scroll = false) %}
112+
<form
113+
role="none"
114+
method="post"
115+
action="{{ url }}"
116+
{% if confirm %}data-turbo-confirm="{{ confirm }}"{% endif %}
117+
{% if preserve_scroll %}data-turbo-preserve-scroll{% endif %}
118+
>
119+
<button type="submit" class="popup__item" role="menuitem">
120+
{% if icon %}
121+
{{ icon(icon) }}
122+
{% endif %}
123+
124+
{{ label }}
125+
</button>
126+
127+
{% for param_name, param_value in params %}
128+
<input type="hidden" name="{{ param_name }}" value="{{ param_value }}">
129+
{% endfor %}
130+
131+
<input type="hidden" name="csrf_token" value="{{ csrf_token(csrf) }}">
132+
</form>
133+
{% endmacro %}
134+
135+
{#
136+
# A button opening the modal on the given URL.
137+
#}
138+
{% macro modal(url, label, icon = '') %}
139+
<button
140+
type="button"
141+
class="popup__item"
142+
role="menuitem"
143+
data-controller="modal-opener"
144+
data-action="modal-opener#fetch"
145+
data-modal-opener-href-value="{{ url }}"
146+
aria-haspopup="dialog"
147+
aria-controls="modal"
148+
>
149+
{% if icon %}
150+
{{ icon(icon) }}
151+
{% endif %}
152+
153+
{{ label }}
154+
</button>
155+
{% endmacro %}
156+
157+
{#
158+
# A button copying the given value to the clipboard.
159+
#}
160+
{% macro clipboard(value, label, icon = 'copy-to-clipboard') %}
161+
<div role="none" data-controller="copy-to-clipboard">
162+
<button
163+
type="button"
164+
class="popup__item"
165+
role="menuitem"
166+
data-action="copy-to-clipboard#copy"
167+
data-copy-to-clipboard-target="feedback"
168+
>
169+
{{ icon(icon) }}
170+
{{ label }}
171+
</button>
172+
173+
<input type="hidden" value="{{ value }}" data-copy-to-clipboard-target="copyable">
174+
</div>
175+
{% endmacro %}
176+
177+
{#
178+
# One choice among several, to be placed in a form provided by the caller.
179+
#}
180+
{% macro option(name, value, label, current = false) %}
181+
<button
182+
type="submit"
183+
class="popup__item popup__item--selectable"
184+
role="menuitem"
185+
name="{{ name }}"
186+
value="{{ value }}"
187+
{% if current %}aria-current="true"{% endif %}
188+
>
189+
{{ label }}
190+
</button>
191+
{% endmacro %}
192+
193+
{#
194+
# A horizontal rule between two sections of the menu.
195+
#}
196+
{% macro separator() %}
197+
<div class="popup__separator" role="separator"></div>
198+
{% endmacro %}

0 commit comments

Comments
 (0)