@cedx/base 0.1.0 → 0.3.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 -2
- package/lib/Date.d.ts +72 -0
- package/lib/Date.d.ts.map +1 -0
- package/lib/Date.js +125 -0
- package/lib/Duration.d.ts +26 -0
- package/lib/Duration.d.ts.map +1 -0
- package/lib/Duration.js +21 -0
- package/lib/Html/AppTheme.d.ts +4 -4
- package/lib/Html/AppTheme.d.ts.map +1 -1
- package/lib/Html/AppTheme.js +4 -4
- package/lib/Html/Context.d.ts +32 -0
- package/lib/Html/Context.d.ts.map +1 -0
- package/lib/Html/Context.js +34 -0
- package/lib/Html/File.d.ts +32 -0
- package/lib/Html/File.d.ts.map +1 -0
- package/lib/Html/File.js +76 -0
- package/lib/UI/LoadingIndicator.d.ts +1 -11
- package/lib/UI/LoadingIndicator.d.ts.map +1 -1
- package/lib/UI/LoadingIndicator.js +5 -20
- package/lib/UI/MenuActivator.d.ts +22 -0
- package/lib/UI/MenuActivator.d.ts.map +1 -0
- package/lib/UI/MenuActivator.js +27 -0
- package/lib/UI/OfflineIndicator.d.ts +1 -7
- package/lib/UI/OfflineIndicator.d.ts.map +1 -1
- package/lib/UI/OfflineIndicator.js +8 -18
- package/lib/UI/ThemeDropdown.d.ts +2 -36
- package/lib/UI/ThemeDropdown.d.ts.map +1 -1
- package/lib/UI/ThemeDropdown.js +41 -86
- package/package.json +3 -3
- package/src/Client/Date.ts +138 -0
- package/src/Client/Duration.ts +30 -0
- package/src/Client/Html/AppTheme.ts +4 -4
- package/src/Client/Html/Context.ts +44 -0
- package/src/Client/Html/File.ts +85 -0
- package/src/Client/Html/ViewportScroller.ts +1 -1
- package/src/Client/Html/tsconfig.json +4 -1
- package/src/Client/UI/LoadingIndicator.ts +4 -16
- package/src/Client/UI/MenuActivator.ts +42 -0
- package/src/Client/UI/OfflineIndicator.ts +10 -17
- package/src/Client/UI/ThemeDropdown.ts +34 -65
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import type {ILoadingIndicator} from "#Abstractions/ILoadingIndicator.js";
|
|
2
|
-
import {html, LitElement, type TemplateResult} from "lit";
|
|
3
|
-
import {customElement} from "lit/decorators.js";
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* A component that shows up when an HTTP request starts, and hides when all concurrent HTTP requests are completed.
|
|
7
5
|
*/
|
|
8
|
-
|
|
9
|
-
export class LoadingIndicator extends LitElement implements ILoadingIndicator {
|
|
6
|
+
export class LoadingIndicator extends HTMLElement implements ILoadingIndicator {
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* The number of concurrent HTTP requests.
|
|
@@ -14,11 +11,10 @@ export class LoadingIndicator extends LitElement implements ILoadingIndicator {
|
|
|
14
11
|
#requestCount = 0;
|
|
15
12
|
|
|
16
13
|
/**
|
|
17
|
-
*
|
|
14
|
+
* Registers the component.
|
|
18
15
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.hidden = true;
|
|
16
|
+
static {
|
|
17
|
+
customElements.define("loading-indicator", this);
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
/**
|
|
@@ -42,14 +38,6 @@ export class LoadingIndicator extends LitElement implements ILoadingIndicator {
|
|
|
42
38
|
document.body.classList.remove("loading");
|
|
43
39
|
}
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Renders this component.
|
|
48
|
-
* @returns The view template.
|
|
49
|
-
*/
|
|
50
|
-
protected override render(): TemplateResult {
|
|
51
|
-
return html`<slot></slot>`;
|
|
52
|
-
}
|
|
53
41
|
}
|
|
54
42
|
|
|
55
43
|
/**
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component that activates the items of a menu based on the current document URL.
|
|
3
|
+
*/
|
|
4
|
+
export class MenuActivator extends HTMLElement {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The root element.
|
|
8
|
+
*/
|
|
9
|
+
readonly #root = this.firstElementChild!;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registers the component.
|
|
13
|
+
*/
|
|
14
|
+
static {
|
|
15
|
+
customElements.define("menu-activator", this);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Method invoked when this component is connected.
|
|
20
|
+
*/
|
|
21
|
+
connectedCallback(): void {
|
|
22
|
+
for (const anchor of this.#root.getElementsByTagName("a"))
|
|
23
|
+
if (anchor.href != location.href) anchor.classList.remove("active");
|
|
24
|
+
else {
|
|
25
|
+
anchor.classList.add("active");
|
|
26
|
+
anchor.closest(".nav-item.dropdown")?.querySelector(".nav-link")?.classList.add("active");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Declaration merging.
|
|
33
|
+
*/
|
|
34
|
+
declare global {
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The map of HTML tag names.
|
|
38
|
+
*/
|
|
39
|
+
interface HTMLElementTagNameMap {
|
|
40
|
+
"menu-activator": MenuActivator;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import {html, LitElement, type TemplateResult} from "lit";
|
|
2
|
-
import {customElement} from "lit/decorators.js";
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* A component that shows up when the network is unavailable, and hides when connectivity is restored.
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
|
-
export class OfflineIndicator extends LitElement {
|
|
4
|
+
export class OfflineIndicator extends HTMLElement {
|
|
9
5
|
|
|
10
6
|
/**
|
|
11
7
|
* Creates a new offline indicator.
|
|
@@ -15,20 +11,25 @@ export class OfflineIndicator extends LitElement {
|
|
|
15
11
|
this.hidden = navigator.onLine;
|
|
16
12
|
}
|
|
17
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Registers the component.
|
|
16
|
+
*/
|
|
17
|
+
static {
|
|
18
|
+
customElements.define("offline-indicator", this);
|
|
19
|
+
}
|
|
20
|
+
|
|
18
21
|
/**
|
|
19
22
|
* Method invoked when this component is connected.
|
|
20
23
|
*/
|
|
21
|
-
|
|
22
|
-
super.connectedCallback();
|
|
24
|
+
connectedCallback(): void {
|
|
23
25
|
for (const event of ["online", "offline"]) addEventListener(event, this);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Method invoked when this component is disconnected.
|
|
28
30
|
*/
|
|
29
|
-
|
|
31
|
+
disconnectedCallback(): void {
|
|
30
32
|
for (const event of ["online", "offline"]) removeEventListener(event, this);
|
|
31
|
-
super.disconnectedCallback();
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/**
|
|
@@ -37,14 +38,6 @@ export class OfflineIndicator extends LitElement {
|
|
|
37
38
|
handleEvent(): void {
|
|
38
39
|
this.hidden = navigator.onLine;
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Renders this component.
|
|
43
|
-
* @returns The view template.
|
|
44
|
-
*/
|
|
45
|
-
protected override render(): TemplateResult {
|
|
46
|
-
return html`<slot></slot>`;
|
|
47
|
-
}
|
|
48
41
|
}
|
|
49
42
|
|
|
50
43
|
/**
|
|
@@ -1,74 +1,60 @@
|
|
|
1
|
-
import {AppTheme,
|
|
2
|
-
import {MenuAlignment} from "#Html/MenuAlignment.js";
|
|
3
|
-
import {html, LitElement, type TemplateResult} from "lit";
|
|
4
|
-
import {customElement, property, state} from "lit/decorators.js";
|
|
5
|
-
import {classMap} from "lit/directives/class-map.js";
|
|
6
|
-
import {when} from "lit/directives/when.js";
|
|
1
|
+
import {AppTheme, getIcon} from "#Html/AppTheme.js";
|
|
7
2
|
|
|
8
3
|
/**
|
|
9
|
-
* A dropdown menu for switching the
|
|
4
|
+
* A dropdown menu for switching the application theme.
|
|
10
5
|
*/
|
|
11
|
-
|
|
12
|
-
export class ThemeDropdown extends LitElement {
|
|
6
|
+
export class ThemeDropdown extends HTMLElement {
|
|
13
7
|
|
|
14
8
|
/**
|
|
15
|
-
* The
|
|
9
|
+
* The media query used to check the application theme.
|
|
16
10
|
*/
|
|
17
|
-
|
|
11
|
+
readonly #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
|
|
18
12
|
|
|
19
13
|
/**
|
|
20
|
-
* The
|
|
14
|
+
* The root element.
|
|
21
15
|
*/
|
|
22
|
-
|
|
16
|
+
readonly #root = this.firstElementChild!;
|
|
23
17
|
|
|
24
18
|
/**
|
|
25
|
-
* The key of the storage entry providing the saved theme.
|
|
19
|
+
* The key of the storage entry providing the saved theme mode.
|
|
26
20
|
*/
|
|
27
|
-
|
|
21
|
+
readonly #storageKey = this.getAttribute("storageKey") ?? "AppTheme";
|
|
28
22
|
|
|
29
23
|
/**
|
|
30
24
|
* The current application theme.
|
|
31
25
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* The media query used to check the system theme.
|
|
36
|
-
*/
|
|
37
|
-
readonly #mediaQuery = matchMedia("(prefers-color-scheme: dark)");
|
|
26
|
+
#theme: AppTheme;
|
|
38
27
|
|
|
39
28
|
/**
|
|
40
29
|
* Creates a new theme dropdown.
|
|
41
30
|
*/
|
|
42
31
|
constructor() {
|
|
43
32
|
super();
|
|
44
|
-
const theme = localStorage.getItem(this
|
|
45
|
-
this
|
|
33
|
+
const theme = localStorage.getItem(this.#storageKey) as AppTheme;
|
|
34
|
+
this.#theme = Object.values(AppTheme).includes(theme) ? theme : AppTheme.System;
|
|
35
|
+
for (const button of this.#root.querySelectorAll("button")) button.addEventListener("click", this.#setTheme.bind(this));
|
|
46
36
|
}
|
|
47
37
|
|
|
48
38
|
/**
|
|
49
|
-
*
|
|
39
|
+
* Registers the component.
|
|
50
40
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
localStorage.setItem(this.storageKey, this.appTheme = value);
|
|
54
|
-
this.#applyTheme();
|
|
41
|
+
static {
|
|
42
|
+
customElements.define("theme-dropdown", this);
|
|
55
43
|
}
|
|
56
44
|
|
|
57
45
|
/**
|
|
58
46
|
* Method invoked when this component is connected.
|
|
59
47
|
*/
|
|
60
|
-
|
|
61
|
-
super.connectedCallback();
|
|
62
|
-
this.#applyTheme();
|
|
48
|
+
connectedCallback(): void {
|
|
63
49
|
this.#mediaQuery.addEventListener("change", this);
|
|
50
|
+
this.#applyTheme();
|
|
64
51
|
}
|
|
65
52
|
|
|
66
53
|
/**
|
|
67
54
|
* Method invoked when this component is disconnected.
|
|
68
55
|
*/
|
|
69
|
-
|
|
56
|
+
disconnectedCallback(): void {
|
|
70
57
|
this.#mediaQuery.removeEventListener("change", this);
|
|
71
|
-
super.disconnectedCallback();
|
|
72
58
|
}
|
|
73
59
|
|
|
74
60
|
/**
|
|
@@ -79,44 +65,27 @@ export class ThemeDropdown extends LitElement {
|
|
|
79
65
|
}
|
|
80
66
|
|
|
81
67
|
/**
|
|
82
|
-
*
|
|
83
|
-
* @returns The node into which this component should render.
|
|
68
|
+
* Applies the theme to the document.
|
|
84
69
|
*/
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
70
|
+
#applyTheme(): void {
|
|
71
|
+
const theme = this.#theme == AppTheme.System ? (this.#mediaQuery.matches ? AppTheme.Dark : AppTheme.Light) : this.#theme;
|
|
72
|
+
document.documentElement.dataset.bsTheme = theme.toLowerCase();
|
|
73
|
+
this.#root.querySelector(".dropdown-toggle > .icon")!.textContent = getIcon(this.#theme);
|
|
88
74
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
protected override render(): TemplateResult {
|
|
94
|
-
return html`
|
|
95
|
-
<li class="nav-item dropdown">
|
|
96
|
-
<a class="dropdown-toggle nav-link" data-bs-toggle="dropdown" href="#">
|
|
97
|
-
<i class="icon icon-fill">${themeIcon(this.appTheme)}</i>
|
|
98
|
-
${when(this.label, () => html`<span class="ms-1">${this.label}</span>`)}
|
|
99
|
-
</a>
|
|
100
|
-
<ul class="dropdown-menu ${classMap({"dropdown-menu-end": this.alignment == MenuAlignment.End})}">
|
|
101
|
-
${Object.values(AppTheme).map(value => html`
|
|
102
|
-
<li>
|
|
103
|
-
<button class="dropdown-item d-flex align-items-center justify-content-between" @click=${() => this.theme = value}>
|
|
104
|
-
<span><i class="icon icon-fill me-1">${themeIcon(value)}</i> ${themeLabel(value)}</span>
|
|
105
|
-
${when(value == this.appTheme, () => html`<i class="icon ms-2">check</i>`)}
|
|
106
|
-
</button>
|
|
107
|
-
</li>
|
|
108
|
-
`)}
|
|
109
|
-
</ul>
|
|
110
|
-
</li>
|
|
111
|
-
`;
|
|
75
|
+
const checkIcon = this.#root.querySelector(".dropdown-item > .icon")!;
|
|
76
|
+
checkIcon.remove();
|
|
77
|
+
const activeButton = this.#root.querySelector(`button[data-theme="${this.#theme}"]`)!
|
|
78
|
+
activeButton.appendChild(checkIcon);
|
|
112
79
|
}
|
|
113
80
|
|
|
114
81
|
/**
|
|
115
|
-
*
|
|
82
|
+
* Changes the current theme.
|
|
83
|
+
* @param event The dispatched event.
|
|
116
84
|
*/
|
|
117
|
-
#
|
|
118
|
-
const
|
|
119
|
-
|
|
85
|
+
#setTheme(event: Event): void {
|
|
86
|
+
const button = (event.target as HTMLElement).closest("button")!;
|
|
87
|
+
localStorage.setItem(this.#storageKey, this.#theme = button.dataset.theme as AppTheme);
|
|
88
|
+
this.#applyTheme();
|
|
120
89
|
}
|
|
121
90
|
}
|
|
122
91
|
|