custom_components/bahmcloud_store/panel/panel.js aktualisiert

This commit is contained in:
2026-01-15 07:59:28 +00:00
parent b40e509362
commit 30a4daa884

View File

@@ -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>