blue-web 1.10.1 → 1.11.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/README.md +43 -24
- package/dist/js/dialog.bundle.js +1 -1
- package/dist/js/dialog.js +45 -6
- package/dist/js/progress.bundle.js +1 -1
- package/dist/js/progress.js +3 -4
- package/dist/js/read-view.bundle.js +1 -1
- package/dist/js/read-view.d.ts +4 -0
- package/dist/js/read-view.js +63 -6
- package/dist/js/side-layout.bundle.js +1 -1
- package/dist/js/side-layout.js +139 -1
- package/dist/js/utils.js +3 -3
- package/dist/merged.scss +263 -122
- package/dist/neu.scss +2 -0
- package/dist/style.css +338 -279
- package/dist/style.css.map +1 -1
- package/dist/style.min.css +6 -6
- package/dist/style.scss +2 -1
- package/dist/styles/_action-menu.scss +2 -3
- package/dist/styles/_layout.scss +120 -0
- package/package.json +18 -25
package/README.md
CHANGED
|
@@ -1,43 +1,62 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/bruegmann/blue-web/master/public/blue-readme-cover.png" alt="UI library based on Bootstrap">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
# Blue Web
|
|
6
2
|
|
|
7
|
-
[
|
|
8
|
-
|
|
9
|
-
[Checkout the docs](https://bruegmann.github.io/blue-web) to find out how to
|
|
10
|
-
use Blue Web.
|
|
3
|
+
Blue Web is the base library for [Blue React](https://bruegmann.github.io/blue-react) and [Blue Blazor](https://bruegmann.github.io/blue-react). This library builds heavily on top of [Bootstrap](https://getbootstrap.com/docs/) and also provides additional solutions in CSS and JavaScript.
|
|
11
4
|
|
|
12
|
-
##
|
|
5
|
+
## Use Blue Web
|
|
13
6
|
|
|
14
|
-
|
|
15
|
-
developing, just and install everything with `npm i` and run:
|
|
7
|
+
Install with NPM:
|
|
16
8
|
|
|
17
9
|
```
|
|
18
|
-
npm
|
|
10
|
+
npm i blue-web
|
|
19
11
|
```
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
[](https://www.npmjs.com/package/blue-web)
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
By running
|
|
15
|
+
## Implementation
|
|
25
16
|
|
|
17
|
+
If you have a React or Blazor project, you should use the components of [Blue React](https://bruegmann.github.io/blue-react) or [Blue Blazor](https://bruegmann.github.io/blue-blazor). Otherwise you can also write the markup of those components directly in HTML. Check out the examples in the docs to find out how.
|
|
18
|
+
|
|
19
|
+
For the JavaScript solutions you have to import the associated file. When installed using NPM, you can do it like this:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import "blue-web/dist/js/dialog.js"
|
|
23
|
+
import "blue-web/dist/js/progress.js"
|
|
24
|
+
// ...
|
|
26
25
|
```
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
You can also use a CDN like unpkg.com. Only recommended for testing, not for production.
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<script src="https://unpkg.com/blue-web@latest/dist/js/dialog.js"></script>
|
|
31
|
+
<script src="https://unpkg.com/blue-web@latest/dist/js/progress.js"></script>
|
|
32
|
+
<!-- ... -->
|
|
28
33
|
```
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
the NPM package will be released.
|
|
35
|
+
## Customization and theming
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
Since Blue Web is based on Bootstrap, you can customize many things by overriding Sass or CSS variables. For more information, see the [Bootstrap documentation](https://getbootstrap.com/docs/5.3/customize/overview/). Blue Web also provides some additional variables that you can use and override. Take a look at [dist/styles/\_variables.scss](https://github.com/bruegmann/blue-web/blob/main/dist/styles/_variables.scss) to see all of them.
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
39
|
+
Here is an example of how to override variables using Sass:
|
|
40
|
+
|
|
41
|
+
```scss
|
|
42
|
+
// Override Bootstrap Sass variable
|
|
43
|
+
$primary: tomato;
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
// Override Blue Web Sass variable
|
|
46
|
+
$theme: orange;
|
|
40
47
|
|
|
48
|
+
// Stylesheet for Blue Web. Already contains Bootstrap.
|
|
49
|
+
@import "~blue-web/dist/style";
|
|
41
50
|
```
|
|
42
|
-
|
|
51
|
+
|
|
52
|
+
An example of how to override CSS variables:
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
:root {
|
|
56
|
+
/* Override Bootstrap CSS variable */
|
|
57
|
+
--bs-body-font-family: "Inter", sans-serif;
|
|
58
|
+
|
|
59
|
+
/* Override Blue Web CSS variable */
|
|
60
|
+
--blue-sidebar-bg: #333;
|
|
61
|
+
}
|
|
43
62
|
```
|
package/dist/js/dialog.bundle.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var
|
|
1
|
+
(()=>{"use strict";var e={786:(e,n,t)=>{t.d(n,{k:()=>l});const o={Cancel:["Cancel","Abbrechen"],Yes:["Yes","Ja"],No:["No","Nein"],Message:["Message","Nachricht"],"Toggle menu":["Toggle menu","Menü umschalten"],"Close all":["Close all","Alle schließen"],Error:["Error","Fehler"],Information:["Information","Information"]};function l(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;return n=n||navigator.language.toLowerCase().indexOf("de")>-1?"de-DE":"en-US",t=t||o,t[e]?n.indexOf("de-")>-1?t[e][1]:t[e][0]:e}},762:(e,n,t)=>{function o(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}t.d(n,{Os:()=>l});const l=()=>o()+o()+"-"+o()+"-"+o()+"-"+o()+"-"+o()+o()+o()}},n={};function t(o){var l=n[o];if(void 0!==l)return l.exports;var a=n[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.d=(e,n)=>{for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},t.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n);var o=t(762),l=t(786);async function a(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},{title:a=(0,l.k)("Message"),icon:i,switchPrimaryBtn:r=!1,acceptBtnText:s=("verify"===e?(0,l.k)("Yes"):"OK"),cancelBtnText:d=("verify"===e?(0,l.k)("No"):(0,l.k)("Cancel")),inputType:c="text"}=t;const u=(0,o.Os)();return document.getElementById(u)||document.body.insertAdjacentHTML("beforeend",`<dialog class="blue-modal modal" id="${u}" aria-labelledby="${u}-label">\n <div class="modal-dialog">\n <div class="modal-content">\n <form>\n <div class="modal-header">\n ${i?`<div class="me-2">${i}</div>`:""}\n <h1 class="modal-title fs-5" id="${u}-label">${a}</h1>\n <button\n type="button"\n class="btn-close"\n aria-label="${d}"\n onclick="document.getElementById('${u}').close()"\n ></button>\n </div>\n <div class="modal-body">\n ${"ask"===e?`<label for="${u}-input">${n}</label>\n <input type="${c}" id="${u}-input" class="form-control mt-3" />`:n}\n </div>\n <div class="modal-footer">\n ${"verify"===e||"ask"===e?`<button\n type="button"\n class="btn ${r?"btn-primary":"blue-btn-plain-primary"}"\n onclick="document.getElementById('${u}').close()"\n >\n ${d}\n </button>`:""}\n <button\n type="submit"\n class="btn ${r?"blue-btn-plain-primary":"btn-primary"}"\n >\n ${s}\n </button>\n </div>\n </form>\n </div>\n </div>\n\n <form method="dialog" class="blue-modal-backdrop">\n <button>${d}</button>\n </form>\n </dialog>`),new Promise((n=>{const t=document.getElementById(u),o=()=>{const e=document.getElementById(u);e&&e.remove()};t?.showModal(),t?.addEventListener("close",(()=>{o(),n(!1)})),t?.querySelector(".modal-content > form")?.addEventListener("submit",(l=>{l.preventDefault(),"ask"===e&&(t.close(),o(),n((t?.querySelector("input")).value||"")),t.close(),o(),n(!0)}))}))}window.blueWeb=window.blueWeb||{},window.blueWeb.dialog={ask:async function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return await a("ask",e,n)},tell:async function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};await a("tell",e,n)},verify:async function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return!0===await a("verify",e,n)}}})();
|
package/dist/js/dialog.js
CHANGED
|
@@ -32,13 +32,52 @@ async function dialog(dialogType, text) {
|
|
|
32
32
|
} = options;
|
|
33
33
|
const id = (0, _utils.guid)();
|
|
34
34
|
const addToDom = () => {
|
|
35
|
-
document.body.insertAdjacentHTML("beforeend", /* HTML
|
|
35
|
+
document.body.insertAdjacentHTML("beforeend", /* HTML */`<dialog class="blue-modal modal" id="${id}" aria-labelledby="${id}-label">
|
|
36
|
+
<div class="modal-dialog">
|
|
37
|
+
<div class="modal-content">
|
|
38
|
+
<form>
|
|
39
|
+
<div class="modal-header">
|
|
40
|
+
${icon ? /* html */`<div class="me-2">${icon}</div>` : ""}
|
|
41
|
+
<h1 class="modal-title fs-5" id="${id}-label">${title}</h1>
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
class="btn-close"
|
|
45
|
+
aria-label="${cancelBtnText}"
|
|
46
|
+
onclick="document.getElementById('${id}').close()"
|
|
47
|
+
></button>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="modal-body">
|
|
50
|
+
${dialogType === "ask" ? /* HTML */`<label for="${id}-input">${text}</label>
|
|
51
|
+
<input type="${inputType}" id="${id}-input" class="form-control mt-3" />` : text}
|
|
52
|
+
</div>
|
|
53
|
+
<div class="modal-footer">
|
|
54
|
+
${dialogType === "verify" || dialogType === "ask" ? /* HTML */`<button
|
|
55
|
+
type="button"
|
|
56
|
+
class="btn ${switchPrimaryBtn ? "btn-primary" : "blue-btn-plain-primary"}"
|
|
57
|
+
onclick="document.getElementById('${id}').close()"
|
|
58
|
+
>
|
|
59
|
+
${cancelBtnText}
|
|
60
|
+
</button>` : ""}
|
|
61
|
+
<button
|
|
62
|
+
type="submit"
|
|
63
|
+
class="btn ${switchPrimaryBtn ? "blue-btn-plain-primary" : "btn-primary"}"
|
|
64
|
+
>
|
|
65
|
+
${acceptBtnText}
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</form>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<form method="dialog" class="blue-modal-backdrop">
|
|
73
|
+
<button>${cancelBtnText}</button>
|
|
74
|
+
</form>
|
|
75
|
+
</dialog>`);
|
|
36
76
|
};
|
|
37
77
|
if (!document.getElementById(id)) {
|
|
38
78
|
addToDom();
|
|
39
79
|
}
|
|
40
80
|
return new Promise(resolve => {
|
|
41
|
-
var _modalEl$querySelecto;
|
|
42
81
|
const modalEl = document.getElementById(id);
|
|
43
82
|
const removeFromDom = () => {
|
|
44
83
|
const modalEl = document.getElementById(id);
|
|
@@ -50,14 +89,14 @@ async function dialog(dialogType, text) {
|
|
|
50
89
|
removeFromDom();
|
|
51
90
|
resolve(false);
|
|
52
91
|
};
|
|
53
|
-
modalEl
|
|
54
|
-
modalEl
|
|
55
|
-
modalEl
|
|
92
|
+
modalEl?.showModal();
|
|
93
|
+
modalEl?.addEventListener("close", onHidden);
|
|
94
|
+
modalEl?.querySelector(".modal-content > form")?.addEventListener("submit", e => {
|
|
56
95
|
e.preventDefault();
|
|
57
96
|
if (dialogType === "ask") {
|
|
58
97
|
modalEl.close();
|
|
59
98
|
removeFromDom();
|
|
60
|
-
resolve((modalEl
|
|
99
|
+
resolve((modalEl?.querySelector("input")).value || "");
|
|
61
100
|
}
|
|
62
101
|
modalEl.close();
|
|
63
102
|
removeFromDom();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";window.blueWeb=window.blueWeb||{},window.blueWeb.progress={progress:0},window.blueWeb.progress={...window.blueWeb.progress,start:function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"blueWebProgress",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:document.body,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Loading data",t=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"fixed-top";const o="string"==typeof r||r instanceof String?document.querySelector(r.toString()):r;let
|
|
1
|
+
(()=>{"use strict";window.blueWeb=window.blueWeb||{},window.blueWeb.progress={progress:0},window.blueWeb.progress={...window.blueWeb.progress,start:function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"blueWebProgress",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:document.body,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Loading data",t=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"fixed-top";const o="string"==typeof r||r instanceof String?document.querySelector(r.toString()):r;let i=document.getElementById(e);i||(i=document.createElement("div"),i.id=e,i.className=`progress ${t} rounded-0`,i.setAttribute("style","--bs-progress-height: 0.25rem"),i.setAttribute("role","progressbar"),i.setAttribute("aria-label",s),i.setAttribute("aria-valuemin","0"),i.setAttribute("aria-valuemax","100"),i.innerHTML='<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 0%"></div>',o.appendChild(i));const n=i.querySelector(".progress-bar");if(n){window.blueWeb.progress.progress=0;var b=setInterval((function(){var e=5*Math.random();window.blueWeb.progress.progress+=e,window.blueWeb.progress.progress=Math.min(window.blueWeb.progress.progress,100),n.style.width=window.blueWeb.progress.progress+"%",i?.setAttribute("aria-valuenow",Math.round(window.blueWeb.progress.progress).toString()),window.blueWeb.progress.progress>=100&&clearInterval(b)}),200)}},stop:function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"blueWebProgress";const r=document.getElementById(e);r&&(window.blueWeb.progress.progress=100,setTimeout((()=>{r.remove()}),500))}},window.blueWeb.progress})();
|
package/dist/js/progress.js
CHANGED
|
@@ -20,20 +20,19 @@ window.blueWeb.progress = {
|
|
|
20
20
|
if (!progressEl) {
|
|
21
21
|
progressEl = document.createElement("div");
|
|
22
22
|
progressEl.id = id;
|
|
23
|
-
progressEl.className =
|
|
23
|
+
progressEl.className = `progress ${positionClass} rounded-0`;
|
|
24
24
|
progressEl.setAttribute("style", "--bs-progress-height: 0.25rem");
|
|
25
25
|
progressEl.setAttribute("role", "progressbar");
|
|
26
26
|
progressEl.setAttribute("aria-label", ariaLabel);
|
|
27
27
|
progressEl.setAttribute("aria-valuemin", "0");
|
|
28
28
|
progressEl.setAttribute("aria-valuemax", "100");
|
|
29
|
-
progressEl.innerHTML = /*html
|
|
29
|
+
progressEl.innerHTML = /*html*/`<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 0%"></div>`;
|
|
30
30
|
parentEl.appendChild(progressEl);
|
|
31
31
|
}
|
|
32
32
|
const progressBar = progressEl.querySelector(".progress-bar");
|
|
33
33
|
if (!progressBar) return;
|
|
34
34
|
window.blueWeb.progress.progress = 0;
|
|
35
35
|
var interval = setInterval(function () {
|
|
36
|
-
var _progressEl;
|
|
37
36
|
// Simuliere einen natürlichen Anstieg
|
|
38
37
|
var increment = Math.random() * 5; // Zufälliger Anstieg zwischen 0 und 5
|
|
39
38
|
window.blueWeb.progress.progress += increment;
|
|
@@ -41,7 +40,7 @@ window.blueWeb.progress = {
|
|
|
41
40
|
|
|
42
41
|
// Aktualisiere die Progressbar
|
|
43
42
|
progressBar.style.width = window.blueWeb.progress.progress + "%";
|
|
44
|
-
|
|
43
|
+
progressEl?.setAttribute("aria-valuenow", Math.round(window.blueWeb.progress.progress).toString());
|
|
45
44
|
|
|
46
45
|
// Stoppe das Intervall, wenn 100% erreicht sind
|
|
47
46
|
if (window.blueWeb.progress.progress >= 100) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";
|
|
1
|
+
(()=>{"use strict";class t extends HTMLElement{startX=0;startY=0;constructor(){super(),this.attachShadow({mode:"open"})}static get observedAttributes(){return["disabled"]}connectedCallback(){this.render()}attributeChangedCallback(t,e,n){"disabled"===t&&this.updateDisabledState()}render(){this.shadowRoot&&(this.shadowRoot.innerHTML='\n <style>\n button {\n display: block;\n margin: 0;\n padding: 0;\n appearance: none;\n background-color: transparent;\n border: none;\n line-height: 1;\n outline: 0;\n }\n\n button:focus-visible + div {\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 25%);\n border-color: rgba(var(--bs-primary-rgb), 50%);\n }\n\n div {\n display: inline-block;\n box-sizing: border-box;\n width: auto;\n max-width: 100%;\n border-color: transparent;\n border-radius: var(--bs-border-radius-sm, 3px);\n border: 1px solid transparent;\n transition: background 0.2s;\n }\n\n div:hover {\n background-color: var(--bs-secondary-bg-subtle);\n }\n\n :host([disabled]) div {\n background-color: transparent;\n }\n </style>\n <button aria-label="Edit"></button>\n <div role="presentation">\n <slot></slot>\n </div>\n ',this.button=this.shadowRoot.querySelector("button"),this.container=this.shadowRoot.querySelector("div"),this.button.addEventListener("click",this.onEditRequested.bind(this)),this.container.addEventListener("click",this.onReadViewClick.bind(this)),this.container.addEventListener("mousedown",this.onMouseDown.bind(this)),this.updateDisabledState())}updateDisabledState(){const t=this.hasAttribute("disabled");this.button?.setAttribute("aria-disabled",String(t)),this.container?.setAttribute("aria-disabled",String(t))}onEditRequested(){this.hasAttribute("disabled")||this.dispatchEvent(new CustomEvent("EditRequested",{bubbles:!0,composed:!0}))}onMouseDown(t){this.hasAttribute("disabled")||(this.startX=t.clientX,this.startY=t.clientY)}mouseHasMovedAfterMouseDown(t){return Math.abs(this.startX-t.clientX)>=5||Math.abs(this.startY-t.clientY)>=5}onReadViewClick(t){this.hasAttribute("disabled")||"a"===t.target.tagName.toLowerCase()||this.mouseHasMovedAfterMouseDown(t)||(t.preventDefault(),this.onEditRequested())}}customElements.define("read-view",t)})();
|
package/dist/js/read-view.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Fires event "EditRequested" when the user clicks the read view.
|
|
4
4
|
* @element read-view
|
|
5
5
|
* @fires EditRequested
|
|
6
|
+
* @attr {boolean} disabled - Disables the component, preventing interactions and removing hover effects.
|
|
6
7
|
* @cssprop --bs-primary-rgb - The primary color as an RGB value.
|
|
7
8
|
* @cssprop --bs-secondary-bg-subtle - The subtle background color for the read view.
|
|
8
9
|
* @cssprop --bs-border-radius-sm - The border radius for the read view.
|
|
@@ -22,8 +23,11 @@ export declare class ReadView extends HTMLElement {
|
|
|
22
23
|
private startX;
|
|
23
24
|
private startY;
|
|
24
25
|
constructor();
|
|
26
|
+
static get observedAttributes(): string[];
|
|
25
27
|
connectedCallback(): void;
|
|
28
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
26
29
|
private render;
|
|
30
|
+
private updateDisabledState;
|
|
27
31
|
private onEditRequested;
|
|
28
32
|
private onMouseDown;
|
|
29
33
|
private mouseHasMovedAfterMouseDown;
|
package/dist/js/read-view.js
CHANGED
|
@@ -4,9 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.ReadView = void 0;
|
|
7
|
-
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
8
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
9
|
-
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
10
7
|
const DRAG_THRESHOLD = 5;
|
|
11
8
|
|
|
12
9
|
/**
|
|
@@ -14,6 +11,7 @@ const DRAG_THRESHOLD = 5;
|
|
|
14
11
|
* Fires event "EditRequested" when the user clicks the read view.
|
|
15
12
|
* @element read-view
|
|
16
13
|
* @fires EditRequested
|
|
14
|
+
* @attr {boolean} disabled - Disables the component, preventing interactions and removing hover effects.
|
|
17
15
|
* @cssprop --bs-primary-rgb - The primary color as an RGB value.
|
|
18
16
|
* @cssprop --bs-secondary-bg-subtle - The subtle background color for the read view.
|
|
19
17
|
* @cssprop --bs-border-radius-sm - The border radius for the read view.
|
|
@@ -28,33 +26,91 @@ const DRAG_THRESHOLD = 5;
|
|
|
28
26
|
* })
|
|
29
27
|
*/
|
|
30
28
|
class ReadView extends HTMLElement {
|
|
29
|
+
startX = 0;
|
|
30
|
+
startY = 0;
|
|
31
31
|
constructor() {
|
|
32
32
|
super();
|
|
33
|
-
_defineProperty(this, "startX", 0);
|
|
34
|
-
_defineProperty(this, "startY", 0);
|
|
35
33
|
this.attachShadow({
|
|
36
34
|
mode: "open"
|
|
37
35
|
});
|
|
38
36
|
}
|
|
37
|
+
static get observedAttributes() {
|
|
38
|
+
return ["disabled"];
|
|
39
|
+
}
|
|
39
40
|
connectedCallback() {
|
|
40
41
|
this.render();
|
|
41
42
|
}
|
|
43
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
44
|
+
if (name === "disabled") {
|
|
45
|
+
this.updateDisabledState();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
42
48
|
render() {
|
|
43
49
|
if (!this.shadowRoot) return;
|
|
44
|
-
this.shadowRoot.innerHTML = /* HTML
|
|
50
|
+
this.shadowRoot.innerHTML = /* HTML */`
|
|
51
|
+
<style>
|
|
52
|
+
button {
|
|
53
|
+
display: block;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: 0;
|
|
56
|
+
appearance: none;
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
border: none;
|
|
59
|
+
line-height: 1;
|
|
60
|
+
outline: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
button:focus-visible + div {
|
|
64
|
+
outline: 0;
|
|
65
|
+
box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 25%);
|
|
66
|
+
border-color: rgba(var(--bs-primary-rgb), 50%);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
div {
|
|
70
|
+
display: inline-block;
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
width: auto;
|
|
73
|
+
max-width: 100%;
|
|
74
|
+
border-color: transparent;
|
|
75
|
+
border-radius: var(--bs-border-radius-sm, 3px);
|
|
76
|
+
border: 1px solid transparent;
|
|
77
|
+
transition: background 0.2s;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
div:hover {
|
|
81
|
+
background-color: var(--bs-secondary-bg-subtle);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:host([disabled]) div {
|
|
85
|
+
background-color: transparent;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
88
|
+
<button aria-label="Edit"></button>
|
|
89
|
+
<div role="presentation">
|
|
90
|
+
<slot></slot>
|
|
91
|
+
</div>
|
|
92
|
+
`;
|
|
45
93
|
this.button = this.shadowRoot.querySelector("button");
|
|
46
94
|
this.container = this.shadowRoot.querySelector("div");
|
|
47
95
|
this.button.addEventListener("click", this.onEditRequested.bind(this));
|
|
48
96
|
this.container.addEventListener("click", this.onReadViewClick.bind(this));
|
|
49
97
|
this.container.addEventListener("mousedown", this.onMouseDown.bind(this));
|
|
98
|
+
this.updateDisabledState();
|
|
99
|
+
}
|
|
100
|
+
updateDisabledState() {
|
|
101
|
+
const isDisabled = this.hasAttribute("disabled");
|
|
102
|
+
this.button?.setAttribute("aria-disabled", String(isDisabled));
|
|
103
|
+
this.container?.setAttribute("aria-disabled", String(isDisabled));
|
|
50
104
|
}
|
|
51
105
|
onEditRequested() {
|
|
106
|
+
if (this.hasAttribute("disabled")) return;
|
|
52
107
|
this.dispatchEvent(new CustomEvent("EditRequested", {
|
|
53
108
|
bubbles: true,
|
|
54
109
|
composed: true
|
|
55
110
|
}));
|
|
56
111
|
}
|
|
57
112
|
onMouseDown(event) {
|
|
113
|
+
if (this.hasAttribute("disabled")) return;
|
|
58
114
|
this.startX = event.clientX;
|
|
59
115
|
this.startY = event.clientY;
|
|
60
116
|
}
|
|
@@ -62,6 +118,7 @@ class ReadView extends HTMLElement {
|
|
|
62
118
|
return Math.abs(this.startX - event.clientX) >= DRAG_THRESHOLD || Math.abs(this.startY - event.clientY) >= DRAG_THRESHOLD;
|
|
63
119
|
}
|
|
64
120
|
onReadViewClick(event) {
|
|
121
|
+
if (this.hasAttribute("disabled")) return;
|
|
65
122
|
const target = event.target;
|
|
66
123
|
if (target.tagName.toLowerCase() !== "a" && !this.mouseHasMovedAfterMouseDown(event)) {
|
|
67
124
|
event.preventDefault();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";class n extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.addEventListeners()}render(){if(!this.shadowRoot)return;const n=(document.documentElement.lang||navigator.language).startsWith("de")?"Seitenleiste umschalten":"Toggle sidebar";this.shadowRoot.innerHTML
|
|
1
|
+
(()=>{"use strict";class n extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.addEventListeners()}render(){if(!this.shadowRoot)return;const n=(document.documentElement.lang||navigator.language).startsWith("de")?"Seitenleiste umschalten":"Toggle sidebar";this.shadowRoot.innerHTML=`\n <style>\n :host {\n --spacing: 0.25rem;\n --drawer-side-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,\n rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,\n rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;\n --toggler-size: calc(\n var(--bs-btn-border-width, 1px) + var(--bs-btn-padding-y, 0.375rem) +\n (var(--bs-btn-font-size, 1rem) * var(--bs-btn-line-height, 1.5)) +\n var(--bs-btn-padding-y, 0.375rem) + var(--bs-btn-border-width, 1px)\n );\n --side-width: 18rem;\n --base-z-index: 0;\n }\n\n .root {\n position: relative;\n display: grid;\n height: 100%;\n grid-template-columns:\n 0 var(--toggler-size) calc(var(--side-width) - var(--toggler-size))\n auto;\n grid-template-rows: var(--toggler-size) auto;\n }\n\n .hidden-input {\n position: fixed;\n --size: 0;\n height: var(--size);\n width: var(--size);\n appearance: none;\n opacity: 0;\n }\n\n .toggler {\n grid-column-start: 2;\n }\n\n .hidden-input:focus-visible + .toggler ::slotted(*) {\n --trigger-box-shadow: var(--trigger-focus-box-shadow, inset 0 0 0.25rem);\n }\n\n @media (width < 64rem) {\n .toggler[for="layout-expand"] {\n display: none;\n }\n }\n\n @media (width >= 64rem) {\n .toggler[for="layout-drawer"] {\n display: none;\n }\n }\n\n .header {\n grid-column-start: 3;\n grid-column-end: 5;\n }\n\n .side {\n overflow: auto;\n }\n\n @media (width < 64rem) {\n .side {\n translate: -100% 0;\n height: 100%;\n transition: translate 0.2s ease;\n }\n\n #layout-drawer:checked ~ .side {\n position: fixed;\n top: 0;\n left: 0;\n z-index: calc(var(--base-z-index) + 1);\n translate: 0;\n width: calc(var(--spacing) * 80);\n box-shadow: var(--drawer-side-shadow);\n }\n }\n\n @media (width >= 64rem) {\n #layout-expand:checked ~ .side {\n grid-column-start: 2;\n grid-column-end: 4;\n }\n }\n\n .main {\n overflow: auto;\n grid-column-start: 2;\n grid-column-end: 5;\n }\n\n @media (width >= 64rem) {\n #layout-expand:checked ~ .main {\n grid-column-start: 4;\n }\n }\n\n .overlay {\n position: fixed;\n z-index: var(--base-z-index);\n inset: 0;\n display: none;\n }\n\n @media (width < 64rem) {\n #layout-drawer:checked ~ .overlay {\n display: block;\n }\n }\n </style>\n\n <div class="root">\n <input\n id="layout-expand"\n type="checkbox"\n class="hidden-input"\n ${localStorage.getItem("side-layout-shrink")?"":"checked"}\n />\n <label class="toggler" for="layout-expand" title="${n}" role="button">\n <slot name="expand-toggler">🍔</slot>\n </label>\n\n <input id="layout-drawer" type="checkbox" class="hidden-input" />\n <label class="toggler" for="layout-drawer" title="${n}" role="button">\n <slot name="drawer-toggler">🍔</slot>\n </label>\n\n <header class="header"><slot name="header"></slot></header>\n <div class="side"><slot name="side"></slot></div>\n <main class="main"><slot></slot></main>\n <label aria-label="Close sidebar" for="layout-drawer" class="overlay"\n ><slot name="overlay"></slot\n ></label>\n </div>\n `}addEventListeners(){this.shadowRoot&&this.shadowRoot.querySelector("#layout-expand").addEventListener("change",this.handleLayoutExpandChange.bind(this))}handleLayoutExpandChange(n){n.target.checked?localStorage.removeItem("side-layout-shrink"):localStorage.setItem("side-layout-shrink","true")}}customElements.define("side-layout",n)})();
|
package/dist/js/side-layout.js
CHANGED
|
@@ -19,7 +19,145 @@ class SideLayout extends HTMLElement {
|
|
|
19
19
|
if (!this.shadowRoot) return;
|
|
20
20
|
const language = document.documentElement.lang || navigator.language;
|
|
21
21
|
const toggleSidebarText = language.startsWith("de") ? "Seitenleiste umschalten" : "Toggle sidebar";
|
|
22
|
-
this.shadowRoot.innerHTML = /* HTML
|
|
22
|
+
this.shadowRoot.innerHTML = /* HTML */`
|
|
23
|
+
<style>
|
|
24
|
+
:host {
|
|
25
|
+
--spacing: 0.25rem;
|
|
26
|
+
--drawer-side-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,
|
|
27
|
+
rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,
|
|
28
|
+
rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
|
|
29
|
+
--toggler-size: calc(
|
|
30
|
+
var(--bs-btn-border-width, 1px) + var(--bs-btn-padding-y, 0.375rem) +
|
|
31
|
+
(var(--bs-btn-font-size, 1rem) * var(--bs-btn-line-height, 1.5)) +
|
|
32
|
+
var(--bs-btn-padding-y, 0.375rem) + var(--bs-btn-border-width, 1px)
|
|
33
|
+
);
|
|
34
|
+
--side-width: 18rem;
|
|
35
|
+
--base-z-index: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.root {
|
|
39
|
+
position: relative;
|
|
40
|
+
display: grid;
|
|
41
|
+
height: 100%;
|
|
42
|
+
grid-template-columns:
|
|
43
|
+
0 var(--toggler-size) calc(var(--side-width) - var(--toggler-size))
|
|
44
|
+
auto;
|
|
45
|
+
grid-template-rows: var(--toggler-size) auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.hidden-input {
|
|
49
|
+
position: fixed;
|
|
50
|
+
--size: 0;
|
|
51
|
+
height: var(--size);
|
|
52
|
+
width: var(--size);
|
|
53
|
+
appearance: none;
|
|
54
|
+
opacity: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.toggler {
|
|
58
|
+
grid-column-start: 2;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.hidden-input:focus-visible + .toggler ::slotted(*) {
|
|
62
|
+
--trigger-box-shadow: var(--trigger-focus-box-shadow, inset 0 0 0.25rem);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@media (width < 64rem) {
|
|
66
|
+
.toggler[for="layout-expand"] {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (width >= 64rem) {
|
|
72
|
+
.toggler[for="layout-drawer"] {
|
|
73
|
+
display: none;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.header {
|
|
78
|
+
grid-column-start: 3;
|
|
79
|
+
grid-column-end: 5;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.side {
|
|
83
|
+
overflow: auto;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@media (width < 64rem) {
|
|
87
|
+
.side {
|
|
88
|
+
translate: -100% 0;
|
|
89
|
+
height: 100%;
|
|
90
|
+
transition: translate 0.2s ease;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#layout-drawer:checked ~ .side {
|
|
94
|
+
position: fixed;
|
|
95
|
+
top: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
z-index: calc(var(--base-z-index) + 1);
|
|
98
|
+
translate: 0;
|
|
99
|
+
width: calc(var(--spacing) * 80);
|
|
100
|
+
box-shadow: var(--drawer-side-shadow);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@media (width >= 64rem) {
|
|
105
|
+
#layout-expand:checked ~ .side {
|
|
106
|
+
grid-column-start: 2;
|
|
107
|
+
grid-column-end: 4;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.main {
|
|
112
|
+
overflow: auto;
|
|
113
|
+
grid-column-start: 2;
|
|
114
|
+
grid-column-end: 5;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (width >= 64rem) {
|
|
118
|
+
#layout-expand:checked ~ .main {
|
|
119
|
+
grid-column-start: 4;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.overlay {
|
|
124
|
+
position: fixed;
|
|
125
|
+
z-index: var(--base-z-index);
|
|
126
|
+
inset: 0;
|
|
127
|
+
display: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@media (width < 64rem) {
|
|
131
|
+
#layout-drawer:checked ~ .overlay {
|
|
132
|
+
display: block;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
136
|
+
|
|
137
|
+
<div class="root">
|
|
138
|
+
<input
|
|
139
|
+
id="layout-expand"
|
|
140
|
+
type="checkbox"
|
|
141
|
+
class="hidden-input"
|
|
142
|
+
${!localStorage.getItem("side-layout-shrink") ? "checked" : ""}
|
|
143
|
+
/>
|
|
144
|
+
<label class="toggler" for="layout-expand" title="${toggleSidebarText}" role="button">
|
|
145
|
+
<slot name="expand-toggler">🍔</slot>
|
|
146
|
+
</label>
|
|
147
|
+
|
|
148
|
+
<input id="layout-drawer" type="checkbox" class="hidden-input" />
|
|
149
|
+
<label class="toggler" for="layout-drawer" title="${toggleSidebarText}" role="button">
|
|
150
|
+
<slot name="drawer-toggler">🍔</slot>
|
|
151
|
+
</label>
|
|
152
|
+
|
|
153
|
+
<header class="header"><slot name="header"></slot></header>
|
|
154
|
+
<div class="side"><slot name="side"></slot></div>
|
|
155
|
+
<main class="main"><slot></slot></main>
|
|
156
|
+
<label aria-label="Close sidebar" for="layout-drawer" class="overlay"
|
|
157
|
+
><slot name="overlay"></slot
|
|
158
|
+
></label>
|
|
159
|
+
</div>
|
|
160
|
+
`;
|
|
23
161
|
}
|
|
24
162
|
addEventListeners() {
|
|
25
163
|
if (!this.shadowRoot) return;
|
package/dist/js/utils.js
CHANGED
|
@@ -64,9 +64,9 @@ function setAlertMessage(message) {
|
|
|
64
64
|
if (alertElement) {
|
|
65
65
|
alertElement.style.display = "block";
|
|
66
66
|
alertElement.classList.add("alert-" + (alertClassName === "loading" ? "info" : alertClassName));
|
|
67
|
-
alertElement.querySelector(".alert-body").innerHTML =
|
|
67
|
+
alertElement.querySelector(".alert-body").innerHTML = `<h2>` + message + `</h2>`;
|
|
68
68
|
if (detailText) {
|
|
69
|
-
alertElement.querySelector(".alert-body").innerHTML +=
|
|
69
|
+
alertElement.querySelector(".alert-body").innerHTML += `<span>` + detailText + `</span>`;
|
|
70
70
|
}
|
|
71
71
|
const btnCloseElement = alertElement.querySelector(".btn-close");
|
|
72
72
|
if (close) {
|
|
@@ -112,7 +112,7 @@ function fetchData(input, init) {
|
|
|
112
112
|
}).catch(reason => {
|
|
113
113
|
if (reason.text) {
|
|
114
114
|
reason.text().then(errorMessage => {
|
|
115
|
-
setAlertMessage(
|
|
115
|
+
setAlertMessage(`${reason.status} - ${reason.statusText || httpStatusCodes[reason.status] || "Error"}`, "danger", true, showErrorDetail ? errorMessage.toString().replace(/(<style[\w\W]+style>)/g, "").replace(/<[^>]+>/g, "") : undefined);
|
|
116
116
|
if (onError) {
|
|
117
117
|
onError(errorMessage, reason);
|
|
118
118
|
}
|