@cedx/base 0.10.1 → 0.12.0
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/ReadMe.md +1 -1
- package/lib/Data/Pagination.d.ts +3 -3
- package/lib/Data/Pagination.js +10 -10
- package/lib/UI/Components/KeyboardAccelerator.d.ts +11 -0
- package/lib/UI/Components/KeyboardAccelerator.d.ts.map +1 -1
- package/lib/UI/Components/KeyboardAccelerator.js +1 -1
- package/lib/UI/Components/OfflineIndicator.d.ts +0 -4
- package/lib/UI/Components/OfflineIndicator.d.ts.map +1 -1
- package/lib/UI/Components/OfflineIndicator.js +5 -11
- package/lib/UI/Components/TabActivator.d.ts +2 -2
- package/lib/UI/Components/TabActivator.d.ts.map +1 -1
- package/lib/UI/Components/TabActivator.js +6 -6
- package/lib/UI/Components/ThemeDropdown.d.ts +16 -0
- package/lib/UI/Components/ThemeDropdown.d.ts.map +1 -1
- package/lib/UI/Components/ThemeDropdown.js +73 -29
- package/lib/UI/Components/Toast.d.ts +74 -0
- package/lib/UI/Components/Toast.d.ts.map +1 -0
- package/lib/UI/Components/Toast.js +225 -0
- package/lib/UI/ElementExtensions.d.ts +13 -0
- package/lib/UI/ElementExtensions.d.ts.map +1 -0
- package/lib/UI/ElementExtensions.js +18 -0
- package/lib/UI/Position.d.ts +46 -0
- package/lib/UI/Position.d.ts.map +1 -0
- package/lib/UI/Position.js +41 -0
- package/lib/UI/Size.d.ts +34 -0
- package/lib/UI/Size.d.ts.map +1 -0
- package/lib/UI/Size.js +29 -0
- package/lib/UI/Variant.d.ts +26 -0
- package/lib/UI/Variant.d.ts.map +1 -0
- package/lib/UI/Variant.js +21 -0
- package/lib/UI/ViewportScroller.js +1 -1
- package/package.json +5 -5
- package/src/Client/Data/Pagination.ts +11 -11
- package/src/Client/UI/Components/KeyboardAccelerator.ts +14 -1
- package/src/Client/UI/Components/MessageBox.old +242 -0
- package/src/Client/UI/Components/OfflineIndicator.ts +5 -13
- package/src/Client/UI/Components/TabActivator.ts +7 -7
- package/src/Client/UI/Components/ThemeDropdown.ts +79 -26
- package/src/Client/UI/Components/Toast.ts +252 -0
- package/src/Client/UI/Components/Toaster.old +0 -0
- package/src/Client/UI/ElementExtensions.ts +19 -0
- package/src/Client/UI/Position.ts +55 -0
- package/src/Client/UI/Size.ts +40 -0
- package/src/Client/UI/Variant.ts +30 -0
- package/src/Client/UI/ViewportScroller.ts +1 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {Context, getIcon} from "../Context.js";
|
|
2
|
+
import {Variant} from "../Variant.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Specifies the return value of a message box.
|
|
6
|
+
*/
|
|
7
|
+
export const MessageBoxResult = Object.freeze({
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The message box does not return any value.
|
|
11
|
+
*/
|
|
12
|
+
None: "",
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The return value of the message box is "OK".
|
|
16
|
+
*/
|
|
17
|
+
OK: "OK",
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The return value of the message box is "Cancel".
|
|
21
|
+
*/
|
|
22
|
+
Cancel: "Cancel"
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Specifies the return value of a message box.
|
|
27
|
+
*/
|
|
28
|
+
export type MessageBoxResult = typeof MessageBoxResult[keyof typeof MessageBoxResult];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Displays a message window, also known as dialog box, which presents a message to the user.
|
|
32
|
+
*/
|
|
33
|
+
export class MessageBox extends HTMLElement {
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Value indicating whether to vertically center this message box.
|
|
37
|
+
*/
|
|
38
|
+
@property({type: Boolean}) centered = false;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The buttons displayed in the footer.
|
|
42
|
+
*/
|
|
43
|
+
@state() private buttons: MessageBoxButton[] = [];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The title displayed in the header.
|
|
47
|
+
*/
|
|
48
|
+
@state() private caption = "";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The message displayed in the body.
|
|
52
|
+
*/
|
|
53
|
+
@state() private content: TemplateResult = html``;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A contextual modifier.
|
|
57
|
+
*/
|
|
58
|
+
@state() private context: Context|null = null;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The icon displayed next to the body.
|
|
62
|
+
*/
|
|
63
|
+
@state() private icon = "";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The root element.
|
|
67
|
+
*/
|
|
68
|
+
@query("dialog", true) private readonly root!: HTMLDialogElement;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The function invoked to return the dialog box result.
|
|
72
|
+
*/
|
|
73
|
+
#resolve: (value: string) => void = () => { /* Noop */ };
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Opens an alert dialog with the specified message and an "OK" button.
|
|
77
|
+
* @param caption The title displayed in the header.
|
|
78
|
+
* @param message The message to show.
|
|
79
|
+
* @param options The message box options.
|
|
80
|
+
* @returns Resolves with the value of the clicked button.
|
|
81
|
+
*/
|
|
82
|
+
alert(caption: string, message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
|
|
83
|
+
const context = options.context ?? Context.Warning;
|
|
84
|
+
return this.show(message, {
|
|
85
|
+
buttons: options.buttons ?? [{label: "OK", value: MessageBoxResult.OK}],
|
|
86
|
+
caption,
|
|
87
|
+
context,
|
|
88
|
+
icon: options.icon ?? getIcon(context)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Closes the message box.
|
|
94
|
+
* @param result The message box result.
|
|
95
|
+
*/
|
|
96
|
+
close(result: MessageBoxResult = MessageBoxResult.None): void {
|
|
97
|
+
this.root.close(result);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Opens a confirmation dialog with the specified message and two buttons, "OK" and "Cancel".
|
|
102
|
+
* @param caption The title displayed in the header.
|
|
103
|
+
* @param message The message to show.
|
|
104
|
+
* @param options The message box options.
|
|
105
|
+
* @returns Resolves with the value of the clicked button.
|
|
106
|
+
*/
|
|
107
|
+
confirm(caption: string, message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
|
|
108
|
+
const context = options.context ?? Context.Warning;
|
|
109
|
+
return this.show(message, {
|
|
110
|
+
caption,
|
|
111
|
+
context,
|
|
112
|
+
icon: options.icon ?? getIcon(context),
|
|
113
|
+
buttons: options.buttons ?? [
|
|
114
|
+
{label: "OK", value: MessageBoxResult.OK},
|
|
115
|
+
{label: "Annuler", value: MessageBoxResult.Cancel, variant: Variant.Secondary}
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Opens a modal dialog with the specified message and options.
|
|
122
|
+
* @param message The message to show.
|
|
123
|
+
* @param options The message box options.
|
|
124
|
+
* @returns Resolves with the value of the clicked button.
|
|
125
|
+
*/
|
|
126
|
+
show(message: TemplateResult, options: MessageBoxOptions = {}): Promise<string> {
|
|
127
|
+
this.buttons = options.buttons ?? [];
|
|
128
|
+
this.caption = options.caption ?? "";
|
|
129
|
+
this.content = message;
|
|
130
|
+
this.context = options.context ?? null;
|
|
131
|
+
this.icon = options.icon ?? "";
|
|
132
|
+
|
|
133
|
+
this.root.returnValue = MessageBoxResult.None;
|
|
134
|
+
this.root.showModal();
|
|
135
|
+
this.root.querySelector<HTMLButtonElement>(".btn-close")?.blur();
|
|
136
|
+
|
|
137
|
+
const {promise, resolve} = Promise.withResolvers<string>();
|
|
138
|
+
this.#resolve = resolve;
|
|
139
|
+
return promise;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Renders this component.
|
|
144
|
+
* @returns The view template.
|
|
145
|
+
*/
|
|
146
|
+
protected override render(): TemplateResult {
|
|
147
|
+
const centered = classMap({"modal-dialog-centered": this.centered});
|
|
148
|
+
return html`
|
|
149
|
+
<dialog class="modal modal-dialog modal-dialog-scrollable ${centered}" @click=${this.#onDialogClick} @close=${this.#onDialogClose}>
|
|
150
|
+
<form class="modal-content" method="dialog">
|
|
151
|
+
<div class="modal-header user-select-none">
|
|
152
|
+
${when(this.caption, () => html`<h1 class="modal-title fs-5">${this.caption}</h1>`)}
|
|
153
|
+
<button class="btn-close"></button>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="modal-body d-flex">
|
|
156
|
+
${when(this.icon, () => html`
|
|
157
|
+
<i class="icon icon-fill fs-1 fw-semibold me-2 ${classMap({[`text-${this.context}`]: this.context ?? ""})}">${this.icon}</i>
|
|
158
|
+
`)}
|
|
159
|
+
<div class="flex-grow-1">${this.content}</div>
|
|
160
|
+
</div>
|
|
161
|
+
${when(this.buttons.length, () => html`
|
|
162
|
+
<div class="modal-footer user-select-none">
|
|
163
|
+
${this.buttons.map(button => html`
|
|
164
|
+
<button class="btn btn-${button.variant ?? Variant.Primary}" value=${button.value ?? MessageBoxResult.None}>
|
|
165
|
+
${when(button.icon, () => html`<i class="icon icon-fill ${classMap({"me-1": button.label ?? ""})}">${button.icon}</i>`)}
|
|
166
|
+
${button.label}
|
|
167
|
+
</button>
|
|
168
|
+
`)}
|
|
169
|
+
</div>
|
|
170
|
+
`)}
|
|
171
|
+
</form>
|
|
172
|
+
</dialog>
|
|
173
|
+
`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Handles the `click` event.
|
|
178
|
+
* @param event The dispatched event.
|
|
179
|
+
*/
|
|
180
|
+
#onDialogClick(event: Event): void {
|
|
181
|
+
if (event.target == this.root) this.close();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handles the `close` event.
|
|
186
|
+
*/
|
|
187
|
+
#onDialogClose(): void {
|
|
188
|
+
this.#resolve(this.root.returnValue);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* A message box button.
|
|
194
|
+
*/
|
|
195
|
+
export type MessageBoxButton = Partial<{
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The button icon.
|
|
199
|
+
*/
|
|
200
|
+
icon: string;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The button label.
|
|
204
|
+
*/
|
|
205
|
+
label: string;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The button value.
|
|
209
|
+
*/
|
|
210
|
+
value: string;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* A tone variant.
|
|
214
|
+
*/
|
|
215
|
+
variant: Context|Variant;
|
|
216
|
+
}>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Defines the options of a {@link MessageBox} instance.
|
|
220
|
+
*/
|
|
221
|
+
export type MessageBoxOptions = Partial<{
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* The buttons displayed in the footer.
|
|
225
|
+
*/
|
|
226
|
+
buttons: MessageBoxButton[];
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The title displayed in the header.
|
|
230
|
+
*/
|
|
231
|
+
caption: string;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* A contextual modifier.
|
|
235
|
+
*/
|
|
236
|
+
context: Context;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* The icon displayed next to the body.
|
|
240
|
+
*/
|
|
241
|
+
icon: string;
|
|
242
|
+
}>;
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export class OfflineIndicator extends HTMLElement {
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Creates a new offline indicator.
|
|
8
|
-
*/
|
|
9
|
-
constructor() {
|
|
10
|
-
super();
|
|
11
|
-
this.#updateHiddenState();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
/**
|
|
15
7
|
* Registers the component.
|
|
16
8
|
*/
|
|
@@ -22,21 +14,21 @@ export class OfflineIndicator extends HTMLElement {
|
|
|
22
14
|
* Method invoked when this component is connected.
|
|
23
15
|
*/
|
|
24
16
|
connectedCallback(): void {
|
|
25
|
-
|
|
17
|
+
this.#update();
|
|
18
|
+
for (const event of ["online", "offline"]) addEventListener(event, this.#update);
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
/**
|
|
29
22
|
* Method invoked when this component is disconnected.
|
|
30
23
|
*/
|
|
31
24
|
disconnectedCallback(): void {
|
|
32
|
-
for (const event of ["online", "offline"]) removeEventListener(event, this.#
|
|
25
|
+
for (const event of ["online", "offline"]) removeEventListener(event, this.#update);
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
/**
|
|
36
|
-
* Updates
|
|
29
|
+
* Updates this component.
|
|
37
30
|
*/
|
|
38
|
-
readonly #
|
|
39
|
-
this.hidden = navigator.onLine;
|
|
31
|
+
readonly #update: () => void = () => this.hidden = navigator.onLine;
|
|
40
32
|
}
|
|
41
33
|
|
|
42
34
|
/**
|
|
@@ -14,14 +14,14 @@ export class TabActivator extends HTMLElement {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* The
|
|
17
|
+
* The index of the active tab.
|
|
18
18
|
*/
|
|
19
19
|
get activeTabIndex(): number {
|
|
20
|
-
const index = Number
|
|
21
|
-
return Math.max(
|
|
20
|
+
const index = Number(this.storage.getItem(this.storageKey) ?? "1");
|
|
21
|
+
return Math.max(0, Math.min(this.tabs.length, Number.isNaN(index) ? 0 : index - 1));
|
|
22
22
|
}
|
|
23
23
|
set activeTabIndex(value: number) {
|
|
24
|
-
this.storage.setItem(this.storageKey, value.toString());
|
|
24
|
+
this.storage.setItem(this.storageKey, (value + 1).toString());
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -56,7 +56,7 @@ export class TabActivator extends HTMLElement {
|
|
|
56
56
|
/**
|
|
57
57
|
* The tab list.
|
|
58
58
|
*/
|
|
59
|
-
get tabs(): NodeListOf<
|
|
59
|
+
get tabs(): NodeListOf<HTMLElement> {
|
|
60
60
|
return this.querySelectorAll('[data-bs-toggle="tab"]');
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -65,8 +65,8 @@ export class TabActivator extends HTMLElement {
|
|
|
65
65
|
*/
|
|
66
66
|
connectedCallback(): void {
|
|
67
67
|
const {activeTabIndex, tabs} = this;
|
|
68
|
-
for (let index =
|
|
69
|
-
const tab = tabs.item(index
|
|
68
|
+
for (let index = 0; index < tabs.length - 1; index++) {
|
|
69
|
+
const tab = tabs.item(index);
|
|
70
70
|
tab.addEventListener("click", () => this.activeTabIndex = index);
|
|
71
71
|
if (index == activeTabIndex) Tab.getOrCreateInstance(tab).show();
|
|
72
72
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Dropdown} from "bootstrap";
|
|
1
2
|
import {AppTheme, getIcon} from "../AppTheme.js";
|
|
2
3
|
import {MenuAlignment} from "../MenuAlignment.js";
|
|
3
4
|
|
|
@@ -11,11 +12,24 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
11
12
|
*/
|
|
12
13
|
static readonly observedAttributes = ["alignment", "apptheme", "label"];
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* The dropdown menu.
|
|
17
|
+
*/
|
|
18
|
+
#dropdown!: Dropdown;
|
|
19
|
+
|
|
14
20
|
/**
|
|
15
21
|
* The media query used to check the application theme.
|
|
16
22
|
*/
|
|
17
23
|
readonly #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
|
|
18
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new theme dropdown.
|
|
27
|
+
*/
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
for (const button of this.querySelectorAll("button")) button.addEventListener("click", this.#setAppTheme);
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
/**
|
|
20
34
|
* Registers the component.
|
|
21
35
|
*/
|
|
@@ -43,7 +57,6 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
43
57
|
}
|
|
44
58
|
set appTheme(value: AppTheme) {
|
|
45
59
|
this.setAttribute("apptheme", value);
|
|
46
|
-
localStorage.setItem(this.storageKey, this.appTheme);
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
/**
|
|
@@ -76,51 +89,63 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
76
89
|
*/
|
|
77
90
|
attributeChangedCallback(attribute: string, oldValue: string|null, newValue: string|null): void {
|
|
78
91
|
if (newValue != oldValue) switch (attribute) {
|
|
79
|
-
case "alignment":
|
|
80
|
-
|
|
81
|
-
const {classList} = this.querySelector(".dropdown-menu")!;
|
|
82
|
-
if (alignment == MenuAlignment.End) classList.add("dropdown-menu-end");
|
|
83
|
-
else classList.remove("dropdown-menu-end");
|
|
92
|
+
case "alignment":
|
|
93
|
+
this.#updateAlignment(Object.values(MenuAlignment).includes(newValue as MenuAlignment) ? newValue as MenuAlignment : MenuAlignment.End);
|
|
84
94
|
break;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const appTheme = Object.values(AppTheme).includes(newValue as AppTheme) ? newValue as AppTheme : AppTheme.System;
|
|
88
|
-
this.querySelector(".dropdown-toggle > .icon")!.textContent = getIcon(appTheme);
|
|
89
|
-
this.querySelector(`button[data-theme="${appTheme}"]`)!.appendChild(this.querySelector(".dropdown-item > .icon")!);
|
|
90
|
-
this.#applyTheme();
|
|
95
|
+
case "apptheme":
|
|
96
|
+
this.#updateAppTheme(Object.values(AppTheme).includes(newValue as AppTheme) ? newValue as AppTheme : AppTheme.System);
|
|
91
97
|
break;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.querySelector(".dropdown-toggle > span")!.textContent = (newValue ?? "").trim() || "Thème";
|
|
98
|
+
case "label":
|
|
99
|
+
this.#updateLabel(newValue ?? "");
|
|
95
100
|
break;
|
|
96
|
-
}
|
|
97
101
|
// No default
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Closes the dropdown menu.
|
|
107
|
+
*/
|
|
108
|
+
close(): void {
|
|
109
|
+
this.#dropdown.hide();
|
|
110
|
+
}
|
|
111
|
+
|
|
101
112
|
/**
|
|
102
113
|
* Method invoked when this component is connected.
|
|
103
114
|
*/
|
|
104
115
|
connectedCallback(): void {
|
|
105
|
-
for (const button of this.querySelectorAll("button")) button.addEventListener("click", this.#setTheme);
|
|
106
|
-
this.#mediaQuery.addEventListener("change", this.#applyTheme);
|
|
107
|
-
|
|
108
116
|
const appTheme = localStorage.getItem(this.storageKey) as AppTheme|null;
|
|
109
|
-
if (appTheme) this.
|
|
117
|
+
if (appTheme) this.appTheme = appTheme;
|
|
118
|
+
|
|
119
|
+
this.#dropdown = new Dropdown(this.querySelector(".dropdown-toggle")!);
|
|
120
|
+
this.#mediaQuery.addEventListener("change", this.#applyToDocument);
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
/**
|
|
113
124
|
* Method invoked when this component is disconnected.
|
|
114
125
|
*/
|
|
115
126
|
disconnectedCallback(): void {
|
|
116
|
-
|
|
117
|
-
this.#mediaQuery.removeEventListener("change", this.#
|
|
127
|
+
this.#dropdown.dispose();
|
|
128
|
+
this.#mediaQuery.removeEventListener("change", this.#applyToDocument);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Opens the dropdown menu.
|
|
133
|
+
*/
|
|
134
|
+
open(): void {
|
|
135
|
+
this.#dropdown.show();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Saves the current application theme into the local storage.
|
|
140
|
+
*/
|
|
141
|
+
save(): void {
|
|
142
|
+
localStorage.setItem(this.storageKey, this.appTheme);
|
|
118
143
|
}
|
|
119
144
|
|
|
120
145
|
/**
|
|
121
146
|
* Applies the application theme to the document.
|
|
122
147
|
*/
|
|
123
|
-
readonly #
|
|
148
|
+
readonly #applyToDocument: () => void = () => {
|
|
124
149
|
const {appTheme} = this;
|
|
125
150
|
const bsTheme = appTheme == AppTheme.System ? (this.#mediaQuery.matches ? AppTheme.Dark : AppTheme.Light) : appTheme;
|
|
126
151
|
document.documentElement.dataset.bsTheme = bsTheme.toLowerCase();
|
|
@@ -130,11 +155,39 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
130
155
|
* Changes the current application theme.
|
|
131
156
|
* @param event The dispatched event.
|
|
132
157
|
*/
|
|
133
|
-
readonly #
|
|
158
|
+
readonly #setAppTheme: (event: Event) => void = event => {
|
|
134
159
|
event.preventDefault();
|
|
135
|
-
|
|
136
|
-
this.
|
|
160
|
+
this.appTheme = (event.target as Element).closest("button")!.dataset.theme! as AppTheme;
|
|
161
|
+
this.save();
|
|
137
162
|
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Updates the alignment of the dropdown menu.
|
|
166
|
+
* @param value The new value.
|
|
167
|
+
*/
|
|
168
|
+
#updateAlignment(value: MenuAlignment): void {
|
|
169
|
+
const {classList} = this.querySelector(".dropdown-menu")!;
|
|
170
|
+
if (value == MenuAlignment.End) classList.add("dropdown-menu-end");
|
|
171
|
+
else classList.remove("dropdown-menu-end");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Updates the application theme.
|
|
176
|
+
* @param value The new value.
|
|
177
|
+
*/
|
|
178
|
+
#updateAppTheme(value: AppTheme): void {
|
|
179
|
+
this.querySelector(".dropdown-toggle > .icon")!.textContent = getIcon(value);
|
|
180
|
+
this.querySelector(`button[data-theme="${value}"]`)!.appendChild(this.querySelector(".dropdown-item > .icon")!);
|
|
181
|
+
this.#applyToDocument();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Updates the label of the dropdown menu.
|
|
186
|
+
* @param value The new value.
|
|
187
|
+
*/
|
|
188
|
+
#updateLabel(value: string): void {
|
|
189
|
+
this.querySelector(".dropdown-toggle > span")!.textContent = value.trim() || "Thème";
|
|
190
|
+
}
|
|
138
191
|
}
|
|
139
192
|
|
|
140
193
|
/**
|