basecoat-cli 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/jinja/dialog.html.jinja +69 -85
- package/dist/assets/jinja/dropdown-menu.html.jinja +46 -38
- package/dist/assets/jinja/popover.html.jinja +11 -19
- package/dist/assets/jinja/select.html.jinja +43 -33
- package/dist/assets/jinja/sidebar.html.jinja +28 -22
- package/dist/assets/jinja/tabs.html.jinja +21 -18
- package/dist/assets/jinja/toast.html.jinja +46 -135
- package/dist/assets/nunjucks/dropdown-menu.njk +17 -11
- package/dist/assets/nunjucks/popover.njk +1 -1
- package/dist/assets/nunjucks/select.njk +10 -6
- package/dist/assets/nunjucks/sidebar.njk +21 -12
- package/dist/assets/nunjucks/tabs.njk +12 -8
- package/dist/assets/nunjucks/toast.njk +5 -5
- package/package.json +1 -1
|
@@ -8,103 +8,87 @@
|
|
|
8
8
|
@param footer {string} [optional] - HTML content for the dialog footer.
|
|
9
9
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
10
10
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
11
|
-
@param
|
|
12
|
-
@param
|
|
13
|
-
@param
|
|
14
|
-
@param
|
|
15
|
-
@param open {boolean} [optional] [default=
|
|
16
|
-
@param close_button {boolean} [optional] [default=
|
|
17
|
-
@param close_on_overlay_click {boolean} [optional] [default=
|
|
11
|
+
@param dialog_attrs {object} [optional] - Additional HTML attributes for the dialog content article.
|
|
12
|
+
@param header_attrs {object} [optional] - Additional HTML attributes for the dialog header.
|
|
13
|
+
@param body_attrs {object} [optional] - Additional HTML attributes for the dialog body section.
|
|
14
|
+
@param footer_attrs {object} [optional] - Additional HTML attributes for the dialog footer.
|
|
15
|
+
@param open {boolean} [optional] [default=false] - Whether the dialog should be open initially.
|
|
16
|
+
@param close_button {boolean} [optional] [default=true] - Whether to include a close button.
|
|
17
|
+
@param close_on_overlay_click {boolean} [optional] [default=true] - Whether clicking the overlay closes the dialog.
|
|
18
18
|
#}
|
|
19
19
|
{% macro dialog(
|
|
20
|
-
id,
|
|
20
|
+
id=None,
|
|
21
21
|
trigger=None,
|
|
22
22
|
title=None,
|
|
23
23
|
description=None,
|
|
24
24
|
footer=None,
|
|
25
|
-
|
|
25
|
+
dialog_attrs={},
|
|
26
26
|
trigger_attrs={},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
close_on_overlay_click=True
|
|
27
|
+
header_attrs={},
|
|
28
|
+
body_attrs={},
|
|
29
|
+
footer_attrs={},
|
|
30
|
+
open=false,
|
|
31
|
+
close_button=true,
|
|
32
|
+
close_on_overlay_click=true
|
|
34
33
|
) %}
|
|
35
|
-
|
|
34
|
+
{% set id = id or ("dialog-" + (range(100000, 999999) | random | string)) %}
|
|
35
|
+
{% if trigger %}
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
onclick="document.getElementById('{{ id }}').showModal()"
|
|
39
|
+
{% for key, value in trigger_attrs.items() %}
|
|
40
|
+
{{ key }}="{{ value }}"
|
|
41
|
+
{% endfor %}
|
|
42
|
+
>
|
|
43
|
+
{{ trigger }}
|
|
44
|
+
</button>
|
|
45
|
+
{% endif %}
|
|
46
|
+
<dialog
|
|
36
47
|
id="{{ id }}"
|
|
37
|
-
x-data="dialog({{ 'true' if open else 'false' }}, {{ 'true' if close_on_overlay_click else 'false' }})"
|
|
38
|
-
x-bind="$main"
|
|
39
48
|
class="dialog"
|
|
40
|
-
{
|
|
49
|
+
aria-labelledby="{{ id }}-title"
|
|
50
|
+
{% if description %}aria-describedby="{{ id }}-description"{% endif %}
|
|
51
|
+
{% if close_on_overlay_click %}onclick="this.close()"{% endif %}
|
|
52
|
+
{% for key, value in dialog_attrs.items() %}
|
|
41
53
|
{{ key }}="{{ value }}"
|
|
42
54
|
{% endfor %}
|
|
43
55
|
>
|
|
44
|
-
{% if
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
>
|
|
77
|
-
<h2 id="{{ id }}-title">{{ title | safe }}</h2>
|
|
78
|
-
{% if description %}<p>{{ description | safe }}</p>{% endif %}
|
|
79
|
-
</header>
|
|
80
|
-
{% endif %}
|
|
81
|
-
{% if caller %}
|
|
82
|
-
<section
|
|
83
|
-
{% for key, value in content_body_attrs.items() %}
|
|
84
|
-
{{ key }}="{{ value }}"
|
|
85
|
-
{% endfor %}
|
|
86
|
-
>
|
|
87
|
-
{{ caller() }}
|
|
88
|
-
</section>
|
|
89
|
-
{% endif %}
|
|
90
|
-
{% if footer %}
|
|
91
|
-
<footer
|
|
92
|
-
{% for key, value in content_footer_attrs.items() %}
|
|
93
|
-
{{ key }}="{{ value }}"
|
|
94
|
-
{% endfor %}
|
|
95
|
-
>
|
|
96
|
-
{{ footer | safe }}
|
|
97
|
-
</footer>
|
|
98
|
-
{% endif %}
|
|
99
|
-
{% if close_button %}
|
|
100
|
-
<button
|
|
101
|
-
@click="hide()"
|
|
102
|
-
aria-label="Close dialog"
|
|
103
|
-
>
|
|
56
|
+
<article {% if close_on_overlay_click %}onclick="event.stopPropagation()"{% endif %}>
|
|
57
|
+
{% if title or description %}
|
|
58
|
+
<header
|
|
59
|
+
{% for key, value in header_attrs %}
|
|
60
|
+
{{ key }}="{{ value }}"
|
|
61
|
+
{% endfor %}
|
|
62
|
+
>
|
|
63
|
+
<h2 id="{{ id }}-title">{{ title | safe }}</h2>
|
|
64
|
+
{% if description %}<p id="{{ id }}-description">{{ description | safe }}</p>{% endif %}
|
|
65
|
+
</header>
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% if caller %}
|
|
68
|
+
<section
|
|
69
|
+
{% for key, value in body_attrs.items() %}
|
|
70
|
+
{{ key }}="{{ value }}"
|
|
71
|
+
{% endfor %}
|
|
72
|
+
>
|
|
73
|
+
{{ caller() }}
|
|
74
|
+
</section>
|
|
75
|
+
{% endif %}
|
|
76
|
+
{% if footer %}
|
|
77
|
+
<footer
|
|
78
|
+
{% for key, value in footer_attrs.items() %}
|
|
79
|
+
{{ key }}="{{ value }}"
|
|
80
|
+
{% endfor %}
|
|
81
|
+
>
|
|
82
|
+
{{ footer | safe }}
|
|
83
|
+
</footer>
|
|
84
|
+
{% endif %}
|
|
85
|
+
{% if close_button %}
|
|
86
|
+
<form method="dialog">
|
|
87
|
+
<button aria-label="Close dialog">
|
|
104
88
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
</
|
|
109
|
-
</
|
|
89
|
+
</button>
|
|
90
|
+
</form>
|
|
91
|
+
{% endif %}
|
|
92
|
+
</article>
|
|
93
|
+
</dialog>
|
|
110
94
|
{% endmacro %}
|
|
@@ -3,61 +3,62 @@
|
|
|
3
3
|
|
|
4
4
|
@param id {string} [optional] - Unique identifier for the dropdown component.
|
|
5
5
|
@param trigger {string} [optional] - HTML content for the button that triggers the dropdown.
|
|
6
|
-
@param
|
|
6
|
+
@param items {array} [optional] - Array of menu items for the dropdown.
|
|
7
7
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
8
8
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
9
|
-
@param
|
|
9
|
+
@param popover_attrs {object} [optional] - Additional HTML attributes for the dropdown content div.
|
|
10
10
|
#}
|
|
11
11
|
{% macro dropdown_menu(
|
|
12
|
+
trigger,
|
|
12
13
|
id=None,
|
|
13
|
-
|
|
14
|
-
menu=None,
|
|
14
|
+
items=None,
|
|
15
15
|
main_attrs={},
|
|
16
16
|
trigger_attrs={},
|
|
17
|
-
|
|
17
|
+
popover_attrs={},
|
|
18
|
+
menu_attrs={}
|
|
18
19
|
) %}
|
|
20
|
+
{% set id = id or ("dropdown-menu-" + (range(100000, 999999) | random | string)) %}
|
|
21
|
+
|
|
19
22
|
<div
|
|
20
|
-
class="
|
|
21
|
-
x-data="dropdownMenu"
|
|
22
|
-
@click.away="open = false"
|
|
23
|
-
{% if id %}id="{{ id }}"{% endif %}
|
|
23
|
+
class="dropdown-menu {{ main_attrs.class }}"
|
|
24
24
|
{% for key, value in main_attrs.items() %}
|
|
25
|
-
{% if key !=
|
|
25
|
+
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
26
26
|
{% endfor %}
|
|
27
27
|
>
|
|
28
|
-
{% if trigger %}
|
|
29
28
|
<button
|
|
30
29
|
type="button"
|
|
31
|
-
aria-haspopup="menu"
|
|
32
|
-
aria-expanded="false"
|
|
33
|
-
x-bind="$trigger"
|
|
34
|
-
{% if id %}
|
|
35
30
|
id="{{ id }}-trigger"
|
|
31
|
+
aria-haspopup="menu"
|
|
36
32
|
aria-controls="{{ id }}-menu"
|
|
37
|
-
|
|
33
|
+
aria-expanded="false"
|
|
38
34
|
{% for key, value in trigger_attrs.items() %}
|
|
39
35
|
{{ key }}="{{ value }}"
|
|
40
36
|
{% endfor %}
|
|
41
37
|
>
|
|
42
38
|
{{ trigger | safe }}
|
|
43
39
|
</button>
|
|
44
|
-
{% endif %}
|
|
45
40
|
<div
|
|
41
|
+
id="{{ id }}"
|
|
46
42
|
data-popover
|
|
47
43
|
aria-hidden="true"
|
|
48
|
-
|
|
49
|
-
{% if id %}id="{{ id }}-menu"{% endif %}
|
|
50
|
-
{% for key, value in content_attrs.items() %}
|
|
44
|
+
{% for key, value in popover_attrs.items() %}
|
|
51
45
|
{{ key }}="{{ value }}"
|
|
52
46
|
{% endfor %}
|
|
53
47
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
<div
|
|
49
|
+
role="menu"
|
|
50
|
+
id="{{ id }}-menu"
|
|
51
|
+
aria-labelledby="{{ id }}-trigger"
|
|
52
|
+
{% for key, value in menu_attrs.items() %}
|
|
53
|
+
{{ key }}="{{ value }}"
|
|
54
|
+
{% endfor %}
|
|
55
|
+
>
|
|
56
|
+
{% if items %}
|
|
57
|
+
{{ render_dropdown_items(items, id ~ "-items" if id else "items") }}
|
|
57
58
|
{% else %}
|
|
58
59
|
{{ caller() if caller }}
|
|
59
60
|
{% endif %}
|
|
60
|
-
</
|
|
61
|
+
</div>
|
|
61
62
|
</div>
|
|
62
63
|
</div>
|
|
63
64
|
{% endmacro %}
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
@param parent_id_prefix {string} [optional] - Prefix for generating element IDs.
|
|
70
71
|
#}
|
|
71
72
|
{% macro render_dropdown_items(items, parent_id_prefix="items") %}
|
|
72
|
-
{% for item in items
|
|
73
|
+
{% for item in items %}
|
|
73
74
|
{% set item_id = parent_id_prefix ~ "-" ~ loop.index %}
|
|
74
75
|
|
|
75
76
|
{% if item.type == "group" %}
|
|
@@ -77,11 +78,13 @@
|
|
|
77
78
|
<div
|
|
78
79
|
role="group"
|
|
79
80
|
aria-labelledby="{{ group_label_id }}"
|
|
80
|
-
{%
|
|
81
|
-
{
|
|
82
|
-
|
|
81
|
+
{% if item.attrs %}
|
|
82
|
+
{% for key, value in item.attrs.items() %}
|
|
83
|
+
{{ key }}="{{ value }}"
|
|
84
|
+
{% endfor %}
|
|
85
|
+
{% endif %}
|
|
83
86
|
>
|
|
84
|
-
<div role="
|
|
87
|
+
<div role="presentation" id="{{ group_label_id }}">{{ item.label }}</div>
|
|
85
88
|
{{ render_dropdown_items(item.items, item_id) if item.items }}
|
|
86
89
|
</div>
|
|
87
90
|
{% elif item.type == "separator" %}
|
|
@@ -89,24 +92,29 @@
|
|
|
89
92
|
{% elif item.type == "item" or not item.type %}
|
|
90
93
|
{% if item.url %}
|
|
91
94
|
<a
|
|
95
|
+
id="{{ item_id }}"
|
|
92
96
|
role="menuitem"
|
|
93
97
|
href="{{ item.url }}"
|
|
94
|
-
{%
|
|
95
|
-
{%
|
|
96
|
-
|
|
98
|
+
{% if item.attrs %}
|
|
99
|
+
{% for key, value in item.attrs.items() %}
|
|
100
|
+
{% if key != "url" %} {{ key }}="{{ value }}" {% endif %}
|
|
101
|
+
{% endfor %}
|
|
102
|
+
{% endif %}
|
|
97
103
|
>
|
|
98
104
|
{{ item.label | safe }}
|
|
99
105
|
</a>
|
|
100
106
|
{% else %}
|
|
101
|
-
<
|
|
107
|
+
<div
|
|
108
|
+
id="{{ item_id }}"
|
|
102
109
|
role="menuitem"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
{% if item.attrs %}
|
|
111
|
+
{% for key, value in item.attrs.items() %}
|
|
112
|
+
{{ key }}="{{ value }}"
|
|
113
|
+
{% endfor %}
|
|
114
|
+
{% endif %}
|
|
107
115
|
>
|
|
108
116
|
{{ item.label | safe }}
|
|
109
|
-
</
|
|
117
|
+
</div>
|
|
110
118
|
{% endif %}
|
|
111
119
|
{% endif %}
|
|
112
120
|
{% endfor %}
|
|
@@ -5,51 +5,43 @@
|
|
|
5
5
|
@param trigger {string} [optional] - HTML content for the element that triggers the popover.
|
|
6
6
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
7
7
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger element.
|
|
8
|
-
@param
|
|
8
|
+
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
9
9
|
#}
|
|
10
10
|
{% macro popover(
|
|
11
|
+
trigger,
|
|
11
12
|
id=None,
|
|
12
|
-
trigger=None,
|
|
13
13
|
main_attrs={},
|
|
14
14
|
trigger_attrs={},
|
|
15
|
-
|
|
15
|
+
popover_attrs={}
|
|
16
16
|
) %}
|
|
17
|
+
{% set id = id or ("popover-" + (range(100000, 999999) | random | string)) %}
|
|
18
|
+
|
|
17
19
|
<div
|
|
18
20
|
class="popover {{ main_attrs.class }}"
|
|
19
|
-
x-data="popover"
|
|
20
|
-
@click.away="open = false"
|
|
21
|
-
{% if id %}id="{{ id }}"{% endif %}
|
|
22
21
|
{% for key, value in main_attrs.items() %}
|
|
23
22
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
24
23
|
{% endfor %}
|
|
25
24
|
>
|
|
26
|
-
{% if trigger %}
|
|
27
25
|
<button
|
|
26
|
+
id="{{ id }}-trigger"
|
|
28
27
|
type="button"
|
|
29
|
-
aria-haspopup="menu"
|
|
30
28
|
aria-expanded="false"
|
|
31
|
-
|
|
32
|
-
{% if id %}
|
|
33
|
-
id="{{ id }}-trigger"
|
|
34
|
-
aria-controls="{{ id }}-menu"
|
|
35
|
-
{% endif %}
|
|
29
|
+
aria-controls="{{ id }}"
|
|
36
30
|
{% for key, value in trigger_attrs.items() %}
|
|
37
31
|
{{ key }}="{{ value }}"
|
|
38
32
|
{% endfor %}
|
|
39
33
|
>
|
|
40
34
|
{{ trigger | safe }}
|
|
41
35
|
</button>
|
|
42
|
-
{% endif %}
|
|
43
36
|
<div
|
|
37
|
+
id="{{ id }}"
|
|
44
38
|
data-popover
|
|
45
39
|
aria-hidden="true"
|
|
46
|
-
|
|
47
|
-
{% if id %}id="{{ id }}-menu"{% endif %}
|
|
48
|
-
{% for key, value in content_attrs.items() %}
|
|
40
|
+
{% for key, value in popover_attrs.items() %}
|
|
49
41
|
{{ key }}="{{ value }}"
|
|
50
42
|
{% endfor %}
|
|
51
|
-
>
|
|
43
|
+
>
|
|
52
44
|
{{ caller() if caller }}
|
|
53
45
|
</div>
|
|
54
46
|
</div>
|
|
55
|
-
{% endmacro %}
|
|
47
|
+
{% endmacro %}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
@param name {string} [optional] - The name attribute for the hidden input storing the selected value.
|
|
7
7
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
8
8
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
9
|
-
@param
|
|
9
|
+
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
10
10
|
@param listbox_attrs {object} [optional] - Additional HTML attributes for the listbox div.
|
|
11
11
|
@param input_attrs {object} [optional] - Additional HTML attributes for the hidden input.
|
|
12
12
|
@param search_placeholder {string} [optional] [default="Search entries..."] - Placeholder text for the search input (combobox only).
|
|
@@ -17,49 +17,55 @@
|
|
|
17
17
|
selected=None,
|
|
18
18
|
name=None,
|
|
19
19
|
items=None,
|
|
20
|
+
main_attrs={},
|
|
20
21
|
trigger_attrs={},
|
|
21
22
|
popover_attrs={},
|
|
22
23
|
listbox_attrs={},
|
|
24
|
+
input_attrs={},
|
|
23
25
|
search_placeholder="Search entries...",
|
|
24
26
|
is_combobox=false
|
|
25
27
|
) %}
|
|
26
28
|
{% set id = id or ("select-" + (range(100000, 999999) | random | string)) %}
|
|
27
29
|
|
|
28
|
-
{% set first_option =
|
|
29
|
-
{% set selected_option =
|
|
30
|
+
{% set first_option = namespace(item=None) %}
|
|
31
|
+
{% set selected_option = namespace(item=None) %}
|
|
30
32
|
|
|
31
|
-
{% for item in items
|
|
33
|
+
{% for item in items %}
|
|
32
34
|
{% if item.type == "group" %}
|
|
33
|
-
{% for sub_item in item.items
|
|
34
|
-
{% if not first_option
|
|
35
|
-
{% set first_option =
|
|
35
|
+
{% for sub_item in item.items %}
|
|
36
|
+
{% if not first_option.item %}
|
|
37
|
+
{% set first_option.item = sub_item %}
|
|
36
38
|
{% endif %}
|
|
37
|
-
{% if selected and sub_item.value == selected and not selected_option
|
|
38
|
-
{% set selected_option =
|
|
39
|
+
{% if selected and sub_item.value == selected and not selected_option.item %}
|
|
40
|
+
{% set selected_option.item = sub_item %}
|
|
39
41
|
{% endif %}
|
|
40
42
|
{% endfor %}
|
|
41
43
|
{% else %}
|
|
42
|
-
{% if not first_option
|
|
43
|
-
{% set first_option =
|
|
44
|
+
{% if not first_option.item %}
|
|
45
|
+
{% set first_option.item = item %}
|
|
44
46
|
{% endif %}
|
|
45
|
-
{% if selected and item.value == selected and not selected_option
|
|
46
|
-
{% set selected_option =
|
|
47
|
+
{% if selected and item.value == selected and not selected_option.item %}
|
|
48
|
+
{% set selected_option.item = item %}
|
|
47
49
|
{% endif %}
|
|
48
50
|
{% endif %}
|
|
49
51
|
{% endfor %}
|
|
50
52
|
|
|
51
|
-
{% set default_option = selected_option
|
|
53
|
+
{% set default_option = selected_option.item or first_option.item or None %}
|
|
52
54
|
|
|
53
|
-
<div
|
|
55
|
+
<div
|
|
56
|
+
class="select {{ main_attrs.class }}"
|
|
57
|
+
{% for key, value in main_attrs.items() %}
|
|
58
|
+
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
59
|
+
{% endfor %}
|
|
60
|
+
>
|
|
54
61
|
<button
|
|
55
62
|
type="button"
|
|
56
63
|
class="btn-outline justify-between font-normal {{ trigger_attrs.class }}"
|
|
57
64
|
id="{{ id }}-trigger"
|
|
58
|
-
popovertarget="{{ id }}"
|
|
59
65
|
aria-haspopup="listbox"
|
|
60
66
|
aria-expanded="false"
|
|
61
67
|
aria-controls="{{ id }}-listbox"
|
|
62
|
-
{% for key, value in trigger_attrs %}
|
|
68
|
+
{% for key, value in trigger_attrs.items() %}
|
|
63
69
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
64
70
|
{% endfor %}
|
|
65
71
|
>
|
|
@@ -71,11 +77,11 @@
|
|
|
71
77
|
{% endif %}
|
|
72
78
|
</button>
|
|
73
79
|
<div
|
|
74
|
-
popover
|
|
75
80
|
id="{{ id }}"
|
|
76
|
-
|
|
81
|
+
data-popover
|
|
82
|
+
aria-hidden="true"
|
|
77
83
|
{% for key, value in popover_attrs.items() %}
|
|
78
|
-
{
|
|
84
|
+
{{ key }}="{{ value }}"
|
|
79
85
|
{% endfor %}
|
|
80
86
|
>
|
|
81
87
|
{% if is_combobox %}
|
|
@@ -90,8 +96,8 @@
|
|
|
90
96
|
spellcheck="false"
|
|
91
97
|
aria-autocomplete="list"
|
|
92
98
|
role="combobox"
|
|
93
|
-
aria-expanded="
|
|
94
|
-
aria-controls="{{ id }}-
|
|
99
|
+
aria-expanded="false"
|
|
100
|
+
aria-controls="{{ id }}-listbox"
|
|
95
101
|
aria-labelledby="{{ id }}-trigger"
|
|
96
102
|
>
|
|
97
103
|
</header>
|
|
@@ -101,11 +107,11 @@
|
|
|
101
107
|
id="{{ id }}-listbox"
|
|
102
108
|
aria-orientation="vertical"
|
|
103
109
|
aria-labelledby="{{ id }}-trigger"
|
|
104
|
-
{% for key, value in listbox_attrs %}
|
|
110
|
+
{% for key, value in listbox_attrs.items() %}
|
|
105
111
|
{{ key }}="{{ value }}"
|
|
106
112
|
{% endfor %}
|
|
107
113
|
>
|
|
108
|
-
{% if items
|
|
114
|
+
{% if items %}
|
|
109
115
|
{{ render_select_items(items, default_option.value, id ~ "-items" if id else "items") }}
|
|
110
116
|
{% else %}
|
|
111
117
|
{{ caller() if caller }}
|
|
@@ -115,7 +121,7 @@
|
|
|
115
121
|
<input
|
|
116
122
|
type="hidden"
|
|
117
123
|
name="{{ name or id ~ '-value' }}"
|
|
118
|
-
value="{{
|
|
124
|
+
value="{{ (default_option.value if default_option) or '' }}"
|
|
119
125
|
{% for key, value in input_attrs.items() %}
|
|
120
126
|
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
121
127
|
{% endfor %}
|
|
@@ -130,18 +136,20 @@
|
|
|
130
136
|
@param parent_id_prefix {string} [optional] - The prefix for the item id.
|
|
131
137
|
#}
|
|
132
138
|
{% macro render_select_items(items, selected, parent_id_prefix="items") %}
|
|
133
|
-
{% for item in items
|
|
139
|
+
{% for item in items %}
|
|
134
140
|
{% set item_id = parent_id_prefix ~ "-" ~ loop.index %}
|
|
135
141
|
{% if item.type == "group" %}
|
|
136
142
|
{% set group_label_id = item.id if item.id else "group-label-" + item_id %}
|
|
137
143
|
<div
|
|
138
144
|
role="group"
|
|
139
145
|
aria-labelledby="{{ group_label_id }}"
|
|
140
|
-
{%
|
|
141
|
-
{
|
|
142
|
-
|
|
146
|
+
{% if item.attrs %}
|
|
147
|
+
{% for key, value in item.attrs.items() %}
|
|
148
|
+
{{ key }}="{{ value }}"
|
|
149
|
+
{% endfor %}
|
|
150
|
+
{% endif %}
|
|
143
151
|
>
|
|
144
|
-
<div role="
|
|
152
|
+
<div role="presentation" id="{{ group_label_id }}">{{ item.label }}</div>
|
|
145
153
|
{{ render_select_items(item.items, selected, item_id) if item.items }}
|
|
146
154
|
</div>
|
|
147
155
|
{% elif item.type == "separator" %}
|
|
@@ -152,9 +160,11 @@
|
|
|
152
160
|
role="option"
|
|
153
161
|
data-value="{{ item.value }}"
|
|
154
162
|
{% if selected == item.value %}aria-selected="true"{% endif %}
|
|
155
|
-
{%
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
{% if item.attrs %}
|
|
164
|
+
{% for key, value in item.attrs.items() %}
|
|
165
|
+
{{ key }}="{{ value }}"
|
|
166
|
+
{% endfor %}
|
|
167
|
+
{% endif %}
|
|
158
168
|
>
|
|
159
169
|
{{ item.label | safe }}
|
|
160
170
|
</div>
|
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
Renders a sidebar component.
|
|
3
3
|
|
|
4
4
|
@param id {string} [optional] - Unique identifier for the sidebar component.
|
|
5
|
-
@param label {string} [optional]
|
|
6
|
-
@param open {boolean} [optional]
|
|
5
|
+
@param label {string} [optional] - Label for the sidebar navigation.
|
|
6
|
+
@param open {boolean} [optional] - Whether the sidebar is open.
|
|
7
7
|
@param side {string} [optional] - Side of the sidebar to display.
|
|
8
8
|
@param header {string} [optional] - Header content for the sidebar.
|
|
9
9
|
@param footer {string} [optional] - Footer content for the sidebar.
|
|
10
10
|
@param menu {array} [optional] - Array of menu items for the sidebar.
|
|
11
|
+
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
12
|
+
@param header_attrs {object} [optional] - Additional HTML attributes for the header div.
|
|
13
|
+
@param content_attrs {object} [optional] - Additional HTML attributes for the content div.
|
|
14
|
+
@param footer_attrs {object} [optional] - Additional HTML attributes for the footer div.
|
|
11
15
|
#}
|
|
12
16
|
{% macro sidebar(
|
|
13
17
|
id=None,
|
|
14
18
|
label="Sidebar navigation",
|
|
15
|
-
open=
|
|
19
|
+
open=true,
|
|
16
20
|
side=None,
|
|
17
21
|
header=None,
|
|
18
22
|
footer=None,
|
|
@@ -20,21 +24,17 @@
|
|
|
20
24
|
main_attrs={},
|
|
21
25
|
header_attrs={},
|
|
22
26
|
content_attrs={},
|
|
23
|
-
footer_attrs={}
|
|
24
|
-
content_wrapper_attrs=None
|
|
27
|
+
footer_attrs={}
|
|
25
28
|
) %}
|
|
26
|
-
<
|
|
29
|
+
<aside
|
|
27
30
|
{% if id %}id="{{ id }}"{% endif %}
|
|
28
31
|
class="sidebar {{ main_attrs.class }}"
|
|
29
|
-
data-uninitialized
|
|
30
32
|
data-side="{{ side if side else "left" }}"
|
|
31
33
|
aria-hidden="{{ "true" if not open else "false" }}"
|
|
32
34
|
{{ "inert" if not open }}
|
|
33
35
|
{% for key, value in main_attrs.items() %}
|
|
34
36
|
{% if key != "class" %}{{ key }}="{{ value }}"{% endif %}
|
|
35
37
|
{% endfor %}
|
|
36
|
-
x-data="sidebar({{ "true" if open else "false" }})"
|
|
37
|
-
x-bind="$main"
|
|
38
38
|
>
|
|
39
39
|
<nav
|
|
40
40
|
aria-label="{{ label }}"
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
</footer>
|
|
72
72
|
{% endif %}
|
|
73
73
|
</nav>
|
|
74
|
-
</
|
|
74
|
+
</aside>
|
|
75
75
|
{% endmacro %}
|
|
76
76
|
|
|
77
77
|
{#
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
@param parent_id_prefix {string} [optional] - Prefix for generating element IDs.
|
|
82
82
|
#}
|
|
83
83
|
{% macro render_sidebar_content(items, parent_id_prefix="content") %}
|
|
84
|
-
{% for item in items
|
|
84
|
+
{% for item in items %}
|
|
85
85
|
{% set item_id = parent_id_prefix ~ "-" ~ loop.index %}
|
|
86
86
|
|
|
87
87
|
{% if item.type == "group" %}
|
|
@@ -89,15 +89,17 @@
|
|
|
89
89
|
<div
|
|
90
90
|
role="group"
|
|
91
91
|
{% if item.label %}aria-labelledby="{{ group_label_id }}"{% endif %}
|
|
92
|
-
{%
|
|
93
|
-
{
|
|
94
|
-
|
|
92
|
+
{% if item.attrs %}
|
|
93
|
+
{% for key, value in item.attrs.items() %}
|
|
94
|
+
{{ key }}="{{ value }}"
|
|
95
|
+
{% endfor %}
|
|
96
|
+
{% endif %}
|
|
95
97
|
>
|
|
96
98
|
{% if item.label %}
|
|
97
99
|
<h3 id="{{ group_label_id }}">{{ item.label }}</h3>
|
|
98
100
|
{% endif %}
|
|
99
101
|
<ul>
|
|
100
|
-
{{ render_sidebar_content(item
|
|
102
|
+
{{ render_sidebar_content(item["items"], item_id) if item["items"] }}
|
|
101
103
|
</ul>
|
|
102
104
|
</div>
|
|
103
105
|
{% elif item.type == "separator" %}
|
|
@@ -107,16 +109,18 @@
|
|
|
107
109
|
<details
|
|
108
110
|
id="submenu-{{ item_id }}"
|
|
109
111
|
{{ "open" if item.open }}
|
|
110
|
-
{%
|
|
111
|
-
{%
|
|
112
|
-
|
|
112
|
+
{% if item.attrs %}
|
|
113
|
+
{% for key, value in item.attrs.items() %}
|
|
114
|
+
{% if key != "open" %}{{ key }}="{{ value }}"{% endif %}
|
|
115
|
+
{% endfor %}
|
|
116
|
+
{% endif %}
|
|
113
117
|
>
|
|
114
118
|
<summary aria-controls="submenu-{{ item_id }}-content">
|
|
115
119
|
{% if item.icon %}{{ item.icon | safe }}{% endif %}
|
|
116
120
|
{{ item.label }}
|
|
117
121
|
</summary>
|
|
118
122
|
<ul id="submenu-{{ item_id }}-content">
|
|
119
|
-
{{ render_sidebar_content(item
|
|
123
|
+
{{ render_sidebar_content(item["items"], item_id) if item["items"] }}
|
|
120
124
|
</ul>
|
|
121
125
|
</details>
|
|
122
126
|
</li>
|
|
@@ -125,9 +129,11 @@
|
|
|
125
129
|
<a
|
|
126
130
|
href="{{ item.url }}"
|
|
127
131
|
{{ 'aria-current="page"' if item.current }}
|
|
128
|
-
{%
|
|
129
|
-
{%
|
|
130
|
-
|
|
132
|
+
{% if item.attrs %}
|
|
133
|
+
{% for key, value in item.attrs.items() %}
|
|
134
|
+
{% if key != "href" and key != "aria-current" %}{{ key }}="{{ value }}"{% endif %}
|
|
135
|
+
{% endfor %}
|
|
136
|
+
{% endif %}
|
|
131
137
|
>
|
|
132
138
|
{% if item.icon %}{{ item.icon | safe }}{% endif %}
|
|
133
139
|
<span>{{ item.label }}</span>
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
@param default_tab_index {number} [optional] [default=1] - The 1-based index of the tab to be active initially.
|
|
15
15
|
#}
|
|
16
16
|
{% macro tabs(
|
|
17
|
-
id,
|
|
17
|
+
id=None,
|
|
18
18
|
tabsets=[],
|
|
19
|
-
main_attrs=
|
|
20
|
-
tablist_attrs=
|
|
19
|
+
main_attrs={},
|
|
20
|
+
tablist_attrs={},
|
|
21
21
|
default_tab_index=1
|
|
22
22
|
)
|
|
23
23
|
%}
|
|
24
|
+
{% set id = id or ("tabs-" + (range(100000, 999999) | random | string)) %}
|
|
24
25
|
<div
|
|
25
26
|
class="tabs {{ main_attrs.class }}"
|
|
26
|
-
|
|
27
|
-
{% if id %}id="{{ id }}"{% endif %}
|
|
27
|
+
id="{{ id }}"
|
|
28
28
|
{% for key, value in main_attrs.items() %}
|
|
29
29
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
30
30
|
{% endfor %}
|
|
@@ -32,40 +32,43 @@
|
|
|
32
32
|
<nav
|
|
33
33
|
role="tablist"
|
|
34
34
|
aria-orientation="horizontal"
|
|
35
|
-
x-bind="$tablist"
|
|
36
35
|
{% for key, value in tablist_attrs.items() %}
|
|
37
36
|
{{ key }}="{{ value }}"
|
|
38
37
|
{% endfor %}
|
|
39
38
|
>
|
|
40
|
-
{% for tabset in tabsets
|
|
39
|
+
{% for tabset in tabsets %}
|
|
41
40
|
<button
|
|
42
41
|
type="button"
|
|
43
42
|
role="tab"
|
|
44
|
-
id="{{
|
|
45
|
-
aria-controls="{{
|
|
43
|
+
id="{{ id }}-tab-{{ loop.index }}"
|
|
44
|
+
aria-controls="{{ id }}-panel-{{ loop.index }}"
|
|
46
45
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
47
46
|
tabindex="0"
|
|
48
|
-
{%
|
|
49
|
-
{
|
|
50
|
-
|
|
47
|
+
{% if tabset.tab_attrs %}
|
|
48
|
+
{% for key, value in tabset.tab_attrs.items() %}
|
|
49
|
+
{{ key }}="{{ value }}"
|
|
50
|
+
{% endfor %}
|
|
51
|
+
{% endif %}
|
|
51
52
|
>
|
|
52
53
|
{{ tabset.tab | safe }}
|
|
53
54
|
</button>
|
|
54
55
|
{% endfor %}
|
|
55
56
|
</nav>
|
|
56
57
|
|
|
57
|
-
{% for tabset in tabsets
|
|
58
|
+
{% for tabset in tabsets %}
|
|
58
59
|
{% if tabset.panel %}
|
|
59
60
|
<div
|
|
60
61
|
role="tabpanel"
|
|
61
|
-
id="{{
|
|
62
|
-
aria-labelledby="{{
|
|
62
|
+
id="{{ id }}-panel-{{ loop.index }}"
|
|
63
|
+
aria-labelledby="{{ id }}-tab-{{ loop.index }}"
|
|
63
64
|
tabindex="-1"
|
|
64
65
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
65
66
|
{% if loop.index != default_tab_index %}hidden{% endif %}
|
|
66
|
-
{%
|
|
67
|
-
{
|
|
68
|
-
|
|
67
|
+
{% if tabset.panel_attrs %}
|
|
68
|
+
{% for key, value in tabset.panel_attrs.items() %}
|
|
69
|
+
{{ key }}="{{ value }}"
|
|
70
|
+
{% endfor %}
|
|
71
|
+
{% endif %}
|
|
69
72
|
>
|
|
70
73
|
{{ tabset.panel | safe }}
|
|
71
74
|
</div>
|
|
@@ -5,21 +5,19 @@
|
|
|
5
5
|
@param id {string} [optional] [default="toaster"] - Unique identifier for the toaster container.
|
|
6
6
|
@param toasts {array} [optional] - An array of toast objects to render initially. See the <code>toast()</code> macro for more details.
|
|
7
7
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main toaster container div.
|
|
8
|
-
@param is_fragment {boolean} [optional] [default=
|
|
8
|
+
@param is_fragment {boolean} [optional] [default=false] - If true, renders only the toast elements with hx-swap-oob="beforeend", suitable for htmx responses. Skips script and template inclusion.
|
|
9
9
|
#}
|
|
10
10
|
{% macro toaster(
|
|
11
11
|
id="toaster",
|
|
12
12
|
toasts=[],
|
|
13
|
-
|
|
14
|
-
is_fragment=False
|
|
13
|
+
attrs={}
|
|
15
14
|
) %}
|
|
16
15
|
<div
|
|
17
16
|
id="{{ id }}"
|
|
18
|
-
class="toaster"
|
|
19
|
-
{% for key, value in
|
|
20
|
-
{{ key }}="{{ value }}"
|
|
17
|
+
class="toaster {{ attrs.class }}"
|
|
18
|
+
{% for key, value in attrs.items() %}
|
|
19
|
+
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
21
20
|
{% endfor %}
|
|
22
|
-
{% if is_fragment %}hx-swap-oob="beforeend"{% endif %}
|
|
23
21
|
>
|
|
24
22
|
{% for item in toasts %}
|
|
25
23
|
{{ toast(
|
|
@@ -31,79 +29,6 @@
|
|
|
31
29
|
) }}
|
|
32
30
|
{% endfor %}
|
|
33
31
|
</div>
|
|
34
|
-
|
|
35
|
-
{% if not is_fragment %}
|
|
36
|
-
<template id="toast-template">
|
|
37
|
-
<div
|
|
38
|
-
class="toast"
|
|
39
|
-
role="status"
|
|
40
|
-
aria-atomic="true"
|
|
41
|
-
x-bind="$toastBindings"
|
|
42
|
-
>
|
|
43
|
-
<div class="toast-content">
|
|
44
|
-
<div class="flex items-center justify-between gap-x-3 p-4 [&>svg]:size-4 [&>svg]:shrink-0 [&>[role=img]]:size-4 [&>[role=img]]:shrink-0 [&>[role=img]>svg]:size-4">
|
|
45
|
-
<template x-if="config.icon">
|
|
46
|
-
<span aria-hidden="true" role="img" x-html="config.icon"></span>
|
|
47
|
-
</template>
|
|
48
|
-
<template x-if="!config.icon && config.category === 'success'">
|
|
49
|
-
{{ toast_icons.success | safe }}
|
|
50
|
-
</template>
|
|
51
|
-
<template x-if="!config.icon && config.category === 'error'">
|
|
52
|
-
{{ toast_icons.error | safe }}
|
|
53
|
-
</template>
|
|
54
|
-
<template x-if="!config.icon && config.category === 'info'">
|
|
55
|
-
{{ toast_icons.info | safe }}
|
|
56
|
-
</template>
|
|
57
|
-
<template x-if="!config.icon && config.category === 'warning'">
|
|
58
|
-
{{ toast_icons.warning | safe }}
|
|
59
|
-
</template>
|
|
60
|
-
<section class="flex-1 flex flex-col gap-0.5 items-start">
|
|
61
|
-
<template x-if="config.title">
|
|
62
|
-
<h2 class="font-medium" x-text="config.title"></h2>
|
|
63
|
-
</template>
|
|
64
|
-
<template x-if="config.description">
|
|
65
|
-
<p class="text-muted-foreground" x-text="config.description"></p>
|
|
66
|
-
</template>
|
|
67
|
-
</section>
|
|
68
|
-
<template x-if="config.action || config.cancel">
|
|
69
|
-
<footer class="flex flex-col gap-1 self-start">
|
|
70
|
-
<template x-if="config.action?.click">
|
|
71
|
-
<button
|
|
72
|
-
type="button"
|
|
73
|
-
class="btn h-6 text-xs px-2.5 rounded-sm"
|
|
74
|
-
@click="executeAction(config.action.click)"
|
|
75
|
-
x-text="config.action.label"
|
|
76
|
-
></button>
|
|
77
|
-
</template>
|
|
78
|
-
<template x-if="config.action?.url">
|
|
79
|
-
<a
|
|
80
|
-
:href="config.action.url"
|
|
81
|
-
class="btn h-6 text-xs px-2.5 rounded-sm"
|
|
82
|
-
x-text="config.action.label"
|
|
83
|
-
></a>
|
|
84
|
-
</template>
|
|
85
|
-
<template x-if="config.cancel?.click">
|
|
86
|
-
<button
|
|
87
|
-
type="button"
|
|
88
|
-
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
|
89
|
-
@click="executeAction(config.cancel.click)"
|
|
90
|
-
x-text="config.cancel.label"
|
|
91
|
-
></button>
|
|
92
|
-
</template>
|
|
93
|
-
<template x-if="config.cancel?.url">
|
|
94
|
-
<a
|
|
95
|
-
:href="config.cancel.url"
|
|
96
|
-
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
|
97
|
-
x-text="config.cancel.label"
|
|
98
|
-
></a>
|
|
99
|
-
</template>
|
|
100
|
-
</footer>
|
|
101
|
-
</template>
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</template>
|
|
106
|
-
{% endif %}
|
|
107
32
|
{% endmacro %}
|
|
108
33
|
|
|
109
34
|
{#
|
|
@@ -134,65 +59,51 @@
|
|
|
134
59
|
aria-atomic="true"
|
|
135
60
|
aria-hidden="false"
|
|
136
61
|
{% if category %}data-category="{{ category }}"{% endif %}
|
|
137
|
-
x-data="toast({
|
|
138
|
-
category: '{{ category }}',
|
|
139
|
-
duration: {{ duration or 'null' }}
|
|
140
|
-
})"
|
|
141
|
-
x-bind="$toastBindings"
|
|
142
62
|
>
|
|
143
63
|
<div class="toast-content">
|
|
144
|
-
|
|
145
|
-
{% if category
|
|
146
|
-
|
|
64
|
+
{% if category in ["error", "success", "info", "warning"] %}
|
|
65
|
+
{% if category == "success" %}
|
|
66
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
|
|
67
|
+
{% elif category == "error" %}
|
|
68
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
|
|
69
|
+
{% elif category == "info" %}
|
|
70
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
|
71
|
+
{% elif category == "warning" %}
|
|
72
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
|
147
73
|
{% endif %}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
74
|
+
{% endif %}
|
|
75
|
+
<section>
|
|
76
|
+
{% if title %}<h2>{{ title }}</h2>{% endif %}
|
|
77
|
+
{% if description %}<p>{{ description }}</p>{% endif %}
|
|
78
|
+
</section>
|
|
79
|
+
{% if action or cancel %}
|
|
80
|
+
<footer>
|
|
81
|
+
{% if action %}
|
|
82
|
+
{% if action.href %}
|
|
83
|
+
<a
|
|
84
|
+
href="{{ action.href }}"
|
|
85
|
+
class="btn-sm"
|
|
86
|
+
data-toast-action
|
|
87
|
+
>{{ action.label }}</a>
|
|
88
|
+
{% else %}
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="btn"
|
|
92
|
+
data-toast-action
|
|
93
|
+
{% if action.onclick %}onclick="{{ action.onclick }}"{% endif %}
|
|
94
|
+
>{{ action.label }}</button>
|
|
95
|
+
{% endif %}
|
|
151
96
|
{% endif %}
|
|
152
|
-
{% if
|
|
153
|
-
<
|
|
97
|
+
{% if cancel %}
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
class="btn-sm-outline"
|
|
101
|
+
data-toast-cancel
|
|
102
|
+
{% if cancel.onclick %}onclick="{{ cancel.onclick }}"{% endif %}
|
|
103
|
+
>{{ cancel.label }}</button>
|
|
154
104
|
{% endif %}
|
|
155
|
-
</
|
|
156
|
-
|
|
157
|
-
<footer class="flex flex-col gap-1 self-start">
|
|
158
|
-
{% if action %}
|
|
159
|
-
{% if action.click %}
|
|
160
|
-
<button
|
|
161
|
-
type="button"
|
|
162
|
-
class="btn h-6 text-xs px-2.5 rounded-sm"
|
|
163
|
-
@click="{{ action.click }}"
|
|
164
|
-
>{{ action.label }}</button>
|
|
165
|
-
{% elif action.url %}
|
|
166
|
-
<a
|
|
167
|
-
href="{{ action.url }}"
|
|
168
|
-
class="btn h-6 text-xs px-2.5 rounded-sm"
|
|
169
|
-
>{{ action.label }}</a>
|
|
170
|
-
{% endif %}
|
|
171
|
-
{% endif %}
|
|
172
|
-
{% if cancel %}
|
|
173
|
-
{% if cancel.click %}
|
|
174
|
-
<button
|
|
175
|
-
type="button"
|
|
176
|
-
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
|
177
|
-
@click="{{ cancel.click }}"
|
|
178
|
-
>{{ cancel.label }}</button>
|
|
179
|
-
{% elif cancel.url %}
|
|
180
|
-
<a
|
|
181
|
-
href="{{ cancel.url }}"
|
|
182
|
-
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
|
183
|
-
>{{ toast.cancel.label }}</a>
|
|
184
|
-
{% endif %}
|
|
185
|
-
{% endif %}
|
|
186
|
-
</footer>
|
|
187
|
-
{% endif %}
|
|
188
|
-
</div>
|
|
105
|
+
</footer>
|
|
106
|
+
{% endif %}
|
|
189
107
|
</div>
|
|
190
108
|
</div>
|
|
191
|
-
{% endmacro %}
|
|
192
|
-
|
|
193
|
-
{% set toast_icons = {
|
|
194
|
-
'success': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
195
|
-
'error': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-x-icon lucide-circle-x"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
|
196
|
-
'info': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info-icon lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
197
|
-
'warning': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert-icon lucide-triangle-alert"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
|
198
|
-
} %}
|
|
109
|
+
{% endmacro %}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
|
|
4
4
|
@param id {string} [optional] - Unique identifier for the dropdown component.
|
|
5
5
|
@param trigger {string} [optional] - HTML content for the button that triggers the dropdown.
|
|
6
|
-
@param
|
|
6
|
+
@param items {array} [optional] - Array of menu items for the dropdown.
|
|
7
7
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
8
8
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
9
9
|
@param popover_attrs {object} [optional] - Additional HTML attributes for the dropdown content div.
|
|
10
10
|
#}
|
|
11
11
|
{% macro dropdown_menu(
|
|
12
|
-
id=None,
|
|
13
12
|
trigger,
|
|
13
|
+
id=None,
|
|
14
14
|
items=None,
|
|
15
15
|
main_attrs={},
|
|
16
16
|
trigger_attrs={},
|
|
@@ -78,9 +78,11 @@
|
|
|
78
78
|
<div
|
|
79
79
|
role="group"
|
|
80
80
|
aria-labelledby="{{ group_label_id }}"
|
|
81
|
-
{%
|
|
82
|
-
{
|
|
83
|
-
|
|
81
|
+
{% if item.attrs %}
|
|
82
|
+
{% for key, value in item.attrs %}
|
|
83
|
+
{{ key }}="{{ value }}"
|
|
84
|
+
{% endfor %}
|
|
85
|
+
{% endif %}
|
|
84
86
|
>
|
|
85
87
|
<div role="presentation" id="{{ group_label_id }}">{{ item.label }}</div>
|
|
86
88
|
{{ render_dropdown_items(item.items, item_id) if item.items }}
|
|
@@ -93,9 +95,11 @@
|
|
|
93
95
|
id="{{ item_id }}"
|
|
94
96
|
role="menuitem"
|
|
95
97
|
href="{{ item.url }}"
|
|
96
|
-
{%
|
|
97
|
-
{%
|
|
98
|
-
|
|
98
|
+
{% if item.attrs %}
|
|
99
|
+
{% for key, value in item.attrs %}
|
|
100
|
+
{% if key != "url" %} {{ key }}="{{ value }}" {% endif %}
|
|
101
|
+
{% endfor %}
|
|
102
|
+
{% endif %}
|
|
99
103
|
>
|
|
100
104
|
{{ item.label | safe }}
|
|
101
105
|
</a>
|
|
@@ -103,9 +107,11 @@
|
|
|
103
107
|
<div
|
|
104
108
|
id="{{ item_id }}"
|
|
105
109
|
role="menuitem"
|
|
106
|
-
{%
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
{% if item.attrs %}
|
|
111
|
+
{% for key, value in item.attrs %}
|
|
112
|
+
{{ key }}="{{ value }}"
|
|
113
|
+
{% endfor %}
|
|
114
|
+
{% endif %}
|
|
109
115
|
>
|
|
110
116
|
{{ item.label | safe }}
|
|
111
117
|
</div>
|
|
@@ -145,9 +145,11 @@
|
|
|
145
145
|
<div
|
|
146
146
|
role="group"
|
|
147
147
|
aria-labelledby="{{ group_label_id }}"
|
|
148
|
-
{%
|
|
149
|
-
{
|
|
150
|
-
|
|
148
|
+
{% if item.attrs %}
|
|
149
|
+
{% for key, value in item.attrs %}
|
|
150
|
+
{{ key }}="{{ value }}"
|
|
151
|
+
{% endfor %}
|
|
152
|
+
{% endif %}
|
|
151
153
|
>
|
|
152
154
|
<div role="presentation" id="{{ group_label_id }}">{{ item.label }}</div>
|
|
153
155
|
{{ render_select_items(item.items, selected, item_id) if item.items }}
|
|
@@ -160,9 +162,11 @@
|
|
|
160
162
|
role="option"
|
|
161
163
|
data-value="{{ item.value }}"
|
|
162
164
|
{% if selected == item.value %}aria-selected="true"{% endif %}
|
|
163
|
-
{%
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
{% if item.attrs %}
|
|
166
|
+
{% for key, value in item.attrs %}
|
|
167
|
+
{{ key }}="{{ value }}"
|
|
168
|
+
{% endfor %}
|
|
169
|
+
{% endif %}
|
|
166
170
|
>
|
|
167
171
|
{{ item.label | safe }}
|
|
168
172
|
</div>
|
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
@param side {string} [optional] - Side of the sidebar to display.
|
|
8
8
|
@param header {string} [optional] - Header content for the sidebar.
|
|
9
9
|
@param footer {string} [optional] - Footer content for the sidebar.
|
|
10
|
-
@param
|
|
10
|
+
@param items {array} [optional] - Array of menu items for the sidebar.
|
|
11
|
+
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
12
|
+
@param header_attrs {object} [optional] - Additional HTML attributes for the header element.
|
|
13
|
+
@param content_attrs {object} [optional] - Additional HTML attributes for the content section.
|
|
14
|
+
@param footer_attrs {object} [optional] - Additional HTML attributes for the footer element.
|
|
11
15
|
#}
|
|
12
16
|
{% macro sidebar(
|
|
13
17
|
id=None,
|
|
@@ -20,8 +24,7 @@
|
|
|
20
24
|
main_attrs={},
|
|
21
25
|
header_attrs={},
|
|
22
26
|
content_attrs={},
|
|
23
|
-
footer_attrs={}
|
|
24
|
-
content_wrapper_attrs=None
|
|
27
|
+
footer_attrs={}
|
|
25
28
|
) %}
|
|
26
29
|
<aside
|
|
27
30
|
{% if id %}id="{{ id }}"{% endif %}
|
|
@@ -86,9 +89,11 @@
|
|
|
86
89
|
<div
|
|
87
90
|
role="group"
|
|
88
91
|
{% if item.label %}aria-labelledby="{{ group_label_id }}"{% endif %}
|
|
89
|
-
{%
|
|
90
|
-
{
|
|
91
|
-
|
|
92
|
+
{% if item.attrs %}
|
|
93
|
+
{% for key, value in item.attrs %}
|
|
94
|
+
{{ key }}="{{ value }}"
|
|
95
|
+
{% endfor %}
|
|
96
|
+
{% endif %}
|
|
92
97
|
>
|
|
93
98
|
{% if item.label %}
|
|
94
99
|
<h3 id="{{ group_label_id }}">{{ item.label }}</h3>
|
|
@@ -104,9 +109,11 @@
|
|
|
104
109
|
<details
|
|
105
110
|
id="submenu-{{ item_id }}"
|
|
106
111
|
{{ "open" if item.open }}
|
|
107
|
-
{%
|
|
108
|
-
{%
|
|
109
|
-
|
|
112
|
+
{% if item.attrs %}
|
|
113
|
+
{% for key, value in item.attrs %}
|
|
114
|
+
{% if key != "open" %}{{ key }}="{{ value }}"{% endif %}
|
|
115
|
+
{% endfor %}
|
|
116
|
+
{% endif %}
|
|
110
117
|
>
|
|
111
118
|
<summary aria-controls="submenu-{{ item_id }}-content">
|
|
112
119
|
{% if item.icon %}{{ item.icon | safe }}{% endif %}
|
|
@@ -122,9 +129,11 @@
|
|
|
122
129
|
<a
|
|
123
130
|
href="{{ item.url }}"
|
|
124
131
|
{{ 'aria-current="page"' if item.current }}
|
|
125
|
-
{%
|
|
126
|
-
{%
|
|
127
|
-
|
|
132
|
+
{% if item.attrs %}
|
|
133
|
+
{% for key, value in item.attrs %}
|
|
134
|
+
{% if key != "href" and key != "aria-current" %}{{ key }}="{{ value }}"{% endif %}
|
|
135
|
+
{% endfor %}
|
|
136
|
+
{% endif %}
|
|
128
137
|
>
|
|
129
138
|
{% if item.icon %}{{ item.icon | safe }}{% endif %}
|
|
130
139
|
<span>{{ item.label }}</span>
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
{% macro tabs(
|
|
17
17
|
id=None,
|
|
18
18
|
tabsets=[],
|
|
19
|
-
main_attrs=
|
|
20
|
-
tablist_attrs=
|
|
19
|
+
main_attrs={},
|
|
20
|
+
tablist_attrs={},
|
|
21
21
|
default_tab_index=1
|
|
22
22
|
)
|
|
23
23
|
%}
|
|
@@ -44,9 +44,11 @@
|
|
|
44
44
|
aria-controls="{{ id }}-panel-{{ loop.index }}"
|
|
45
45
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
46
46
|
tabindex="0"
|
|
47
|
-
{%
|
|
48
|
-
{
|
|
49
|
-
|
|
47
|
+
{% if tabset.tab_attrs %}
|
|
48
|
+
{% for key, value in tabset.tab_attrs %}
|
|
49
|
+
{{ key }}="{{ value }}"
|
|
50
|
+
{% endfor %}
|
|
51
|
+
{% endif %}
|
|
50
52
|
>
|
|
51
53
|
{{ tabset.tab | safe }}
|
|
52
54
|
</button>
|
|
@@ -62,9 +64,11 @@
|
|
|
62
64
|
tabindex="-1"
|
|
63
65
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
64
66
|
{% if loop.index != default_tab_index %}hidden{% endif %}
|
|
65
|
-
{%
|
|
66
|
-
{
|
|
67
|
-
|
|
67
|
+
{% if tabset.panel_attrs %}
|
|
68
|
+
{% for key, value in tabset.panel_attrs %}
|
|
69
|
+
{{ key }}="{{ value }}"
|
|
70
|
+
{% endfor %}
|
|
71
|
+
{% endif %}
|
|
68
72
|
>
|
|
69
73
|
{{ tabset.panel | safe }}
|
|
70
74
|
</div>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
{% macro toaster(
|
|
11
11
|
id="toaster",
|
|
12
12
|
toasts=[],
|
|
13
|
-
attrs=
|
|
13
|
+
attrs={}
|
|
14
14
|
) %}
|
|
15
15
|
<div
|
|
16
16
|
id="{{ id }}"
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
<div class="toast-content">
|
|
64
64
|
{% if category in ["error", "success", "info", "warning"] %}
|
|
65
65
|
{% if category == "success" %}
|
|
66
|
-
|
|
66
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
|
|
67
67
|
{% elif category == "error" %}
|
|
68
|
-
|
|
68
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
|
|
69
69
|
{% elif category == "info" %}
|
|
70
|
-
|
|
70
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
|
71
71
|
{% elif category == "warning" %}
|
|
72
|
-
|
|
72
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
|
73
73
|
{% endif %}
|
|
74
74
|
{% endif %}
|
|
75
75
|
<section>
|