custom_components/bahmcloud_store/panel/panel.js aktualisiert
This commit is contained in:
@@ -40,6 +40,45 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Mobile navigation helpers ---
|
||||||
|
|
||||||
|
_toggleMenu() {
|
||||||
|
// Preferred: HA listens to these events in many builds
|
||||||
|
try {
|
||||||
|
window.dispatchEvent(new CustomEvent("hass-toggle-menu", { bubbles: true, composed: true }));
|
||||||
|
window.dispatchEvent(new CustomEvent("hass-toggle-drawer", { bubbles: true, composed: true }));
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback: try to find the drawer and toggle it (best-effort)
|
||||||
|
try {
|
||||||
|
const ha = document.querySelector("home-assistant");
|
||||||
|
const main = ha?.shadowRoot?.querySelector("home-assistant-main");
|
||||||
|
const drawerLayout =
|
||||||
|
main?.shadowRoot?.querySelector("app-drawer-layout") ||
|
||||||
|
main?.shadowRoot?.querySelector("ha-drawer") ||
|
||||||
|
main?.shadowRoot?.querySelector("ha-sidebar");
|
||||||
|
|
||||||
|
if (drawerLayout?.toggleDrawer) {
|
||||||
|
drawerLayout.toggleDrawer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// If nothing works, show a hint
|
||||||
|
this._error = "Unable to open the sidebar on this client. Use the browser back button.";
|
||||||
|
this._update();
|
||||||
|
}
|
||||||
|
|
||||||
|
_goBack() {
|
||||||
|
// Works even if HA chrome is hidden
|
||||||
|
try {
|
||||||
|
history.back();
|
||||||
|
} catch (_) {
|
||||||
|
// fallback
|
||||||
|
window.location.href = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _addCustomRepo() {
|
async _addCustomRepo() {
|
||||||
if (!this._hass) return;
|
if (!this._hass) return;
|
||||||
|
|
||||||
@@ -93,13 +132,66 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
<style>
|
<style>
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
/* Do NOT force viewport height on mobile.
|
|
||||||
Let Home Assistant handle layout (header/sidebar). */
|
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
--bcs-accent: #1E88E5; /* Bahmcloud Blue */
|
--bcs-accent: #1E88E5; /* Bahmcloud Blue */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile-safe top bar that replaces HA chrome if HA renders this panel fullscreen */
|
||||||
|
.mobilebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 50;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
|
||||||
|
background: var(--app-header-background-color, var(--card-background-color));
|
||||||
|
color: var(--app-header-text-color, var(--primary-text-color));
|
||||||
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobilebar .left,
|
||||||
|
.mobilebar .right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconbtn {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
background: color-mix(in srgb, var(--card-background-color) 80%, transparent);
|
||||||
|
color: inherit;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brandtitle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.brandtitle .t {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
.brandtitle .s {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.wrap {
|
.wrap {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
@@ -108,26 +200,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: 0.2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
font-size: 13px;
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -151,12 +223,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
box-shadow: 0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@@ -244,18 +310,23 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="wrap">
|
<!-- This bar ensures navigation on mobile even if HA renders fullscreen panels -->
|
||||||
<div class="topbar">
|
<div class="mobilebar">
|
||||||
<div>
|
<div class="left">
|
||||||
<div class="title">Bahmcloud Store</div>
|
<div class="iconbtn" id="menuBtn" title="Menu">☰</div>
|
||||||
<div class="subtitle" id="subtitle">BCS — loading…</div>
|
<div class="iconbtn" id="backBtn" title="Back">←</div>
|
||||||
</div>
|
<div class="brandtitle">
|
||||||
|
<div class="t">Bahmcloud Store</div>
|
||||||
<div class="actions">
|
<div class="s" id="subtitle">BCS — loading…</div>
|
||||||
<button id="refreshBtn">Refresh</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
<button id="refreshBtn">Refresh</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrap">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div class="tab" data-view="store">Store</div>
|
<div class="tab" data-view="store">Store</div>
|
||||||
<div class="tab" data-view="manage">Manage repositories</div>
|
<div class="tab" data-view="manage">Manage repositories</div>
|
||||||
@@ -268,6 +339,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
root.getElementById("refreshBtn").addEventListener("click", () => this._load());
|
root.getElementById("refreshBtn").addEventListener("click", () => this._load());
|
||||||
|
root.getElementById("menuBtn").addEventListener("click", () => this._toggleMenu());
|
||||||
|
root.getElementById("backBtn").addEventListener("click", () => this._goBack());
|
||||||
|
|
||||||
for (const tab of root.querySelectorAll(".tab")) {
|
for (const tab of root.querySelectorAll(".tab")) {
|
||||||
tab.addEventListener("click", () => {
|
tab.addEventListener("click", () => {
|
||||||
@@ -281,8 +354,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const root = this.shadowRoot;
|
const root = this.shadowRoot;
|
||||||
const content = root.getElementById("content");
|
const content = root.getElementById("content");
|
||||||
const err = root.getElementById("error");
|
const err = root.getElementById("error");
|
||||||
|
|
||||||
const subtitle = root.getElementById("subtitle");
|
const subtitle = root.getElementById("subtitle");
|
||||||
|
|
||||||
const v = this._data?.version ? String(this._data.version) : null;
|
const v = this._data?.version ? String(this._data.version) : null;
|
||||||
subtitle.textContent = v ? `BCS ${v}` : "BCS — loading…";
|
subtitle.textContent = v ? `BCS ${v}` : "BCS — loading…";
|
||||||
|
|
||||||
@@ -358,7 +431,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
<div><strong>${this._esc(r.name)}</strong></div>
|
<div><strong>${this._esc(r.name)}</strong></div>
|
||||||
<div class="muted">${this._esc(r.url)}</div>
|
<div class="muted">${this._esc(r.url)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div>
|
||||||
<button class="primary" data-remove="${this._esc(r.id)}">Remove</button>
|
<button class="primary" data-remove="${this._esc(r.id)}">Remove</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -382,7 +455,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
<input id="addName" placeholder="My Integration" value="${this._esc(this._customAddName)}" />
|
<input id="addName" placeholder="My Integration" value="${this._esc(this._customAddName)}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions">
|
<div>
|
||||||
<button id="addBtn" class="primary">Add repository</button>
|
<button id="addBtn" class="primary">Add repository</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user