custom_components/bahmcloud_store/panel/panel.js aktualisiert

This commit is contained in:
2026-01-15 08:34:01 +00:00
parent 9d04aeaa58
commit 95a7a0689b

View File

@@ -40,26 +40,19 @@ class BahmcloudStorePanel extends HTMLElement {
} }
} }
// --- Mobile navigation helpers ---
_isDesktop() { _isDesktop() {
// If the viewport is wide enough, HA typically shows the sidebar permanently.
// We treat this as "desktop" and hide/disable the menu toggle.
return window.matchMedia && window.matchMedia("(min-width: 1024px)").matches; return window.matchMedia && window.matchMedia("(min-width: 1024px)").matches;
} }
_toggleMenu() { _toggleMenu() {
// On desktop the sidebar is usually always visible; do nothing.
if (this._isDesktop()) return; if (this._isDesktop()) return;
// Primary: dispatch the standard HA event from THIS element so it bubbles.
try { try {
const ev = new Event("hass-toggle-menu", { bubbles: true, composed: true }); const ev = new Event("hass-toggle-menu", { bubbles: true, composed: true });
this.dispatchEvent(ev); this.dispatchEvent(ev);
return; // often enough on mobile return;
} catch (_) {} } catch (_) {}
// Secondary: try again via host/root
try { try {
const host = this.shadowRoot?.host; const host = this.shadowRoot?.host;
if (host) { if (host) {
@@ -69,44 +62,6 @@ class BahmcloudStorePanel extends HTMLElement {
} }
} catch (_) {} } catch (_) {}
// Fallback DOM attempts
try {
const ha = document.querySelector("home-assistant");
const haRoot = ha?.shadowRoot;
const main =
haRoot?.querySelector("home-assistant-main") ||
haRoot?.querySelector("home-assistant-main#main");
const mainRoot = main?.shadowRoot;
const drawer =
mainRoot?.querySelector("mwc-drawer") ||
mainRoot?.querySelector("ha-drawer") ||
mainRoot?.querySelector("app-drawer-layout");
if (drawer) {
if ("open" in drawer) {
drawer.open = true;
return;
}
if (typeof drawer.toggleDrawer === "function") {
drawer.toggleDrawer();
return;
}
}
const layout =
mainRoot?.querySelector("ha-panel-lovelace") ||
mainRoot?.querySelector("ha-panel");
if (layout && typeof layout.toggleMenu === "function") {
layout.toggleMenu();
return;
}
} catch (_) {}
// Only show an error on mobile if everything failed.
this._error = "Unable to open the sidebar on this client. Use the back button."; this._error = "Unable to open the sidebar on this client. Use the back button.";
this._update(); this._update();
} }
@@ -170,189 +125,98 @@ class BahmcloudStorePanel extends HTMLElement {
root.innerHTML = ` root.innerHTML = `
<style> <style>
:host { :host { display:block; min-height:100%; --bcs-accent:#1E88E5; }
display: block;
height: auto;
min-height: 100%;
--bcs-accent: #1E88E5;
}
.mobilebar { .mobilebar{
position: sticky; position:sticky; top:0; z-index:50;
top: 0; display:flex; align-items:center; justify-content:space-between;
z-index: 50; gap:8px; padding:10px 12px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
background: var(--app-header-background-color, var(--card-background-color)); background: var(--app-header-background-color, var(--card-background-color));
color: var(--app-header-text-color, var(--primary-text-color)); color: var(--app-header-text-color, var(--primary-text-color));
border-bottom: 1px solid var(--divider-color); border-bottom:1px solid var(--divider-color);
} }
.mobilebar .left, .mobilebar .right { display:flex; align-items:center; gap:8px; }
.mobilebar .left, .iconbtn{
.mobilebar .right { width:40px; height:40px; border-radius:12px;
display: flex; border:1px solid var(--divider-color);
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); background: color-mix(in srgb, var(--card-background-color) 80%, transparent);
color: inherit; color:inherit; display:inline-flex; align-items:center; justify-content:center;
display: inline-flex; cursor:pointer; user-select:none; font-weight:900; font-size:18px; line-height:1;
align-items: center; }
justify-content: center; @media (min-width: 1024px) { .iconbtn.menu { display:none; } }
cursor: pointer;
user-select: none; .brandtitle{ display:flex; flex-direction:column; line-height:1.2; }
font-weight: 900; .brandtitle .t{ font-size:16px; font-weight:900; }
font-size: 18px; .brandtitle .s{ font-size:12px; color:var(--secondary-text-color); margin-top:2px; }
line-height: 1;
.wrap{
padding:16px; max-width:1100px; margin:0 auto;
font-family: system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
color:var(--primary-text-color);
} }
/* Hide the menu button on desktop where the sidebar is already visible */ .tabs{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
@media (min-width: 1024px) { .tab{
.iconbtn.menu { border:1px solid var(--divider-color);
display: none; background:var(--card-background-color);
color:var(--primary-text-color);
padding:8px 12px; border-radius:999px;
cursor:pointer; font-weight:600; font-size:13px;
} }
.tab.active{
border-color:var(--bcs-accent);
box-shadow:0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
} }
.brandtitle { button{
display: flex; padding:9px 12px; border-radius:12px;
flex-direction: column; border:1px solid var(--divider-color);
line-height: 1.2; background:var(--card-background-color);
color:var(--primary-text-color);
cursor:pointer; font-weight:700;
} }
.brandtitle .t { button.primary{
font-size: 16px; border-color:var(--bcs-accent);
font-weight: 900;
}
.brandtitle .s {
font-size: 12px;
color: var(--secondary-text-color);
margin-top: 2px;
}
.wrap {
padding: 16px;
max-width: 1100px;
margin: 0 auto;
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
color: var(--primary-text-color);
}
.tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.tab {
border: 1px solid var(--divider-color);
background: var(--card-background-color);
color: var(--primary-text-color);
padding: 8px 12px;
border-radius: 999px;
cursor: pointer;
font-weight: 600;
font-size: 13px;
}
.tab.active {
border-color: var(--bcs-accent);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
}
button {
padding: 9px 12px;
border-radius: 12px;
border: 1px solid var(--divider-color);
background: var(--card-background-color);
color: var(--primary-text-color);
cursor: pointer;
font-weight: 700;
}
button.primary {
border-color: var(--bcs-accent);
background: color-mix(in srgb, var(--bcs-accent) 16%, var(--card-background-color)); background: color-mix(in srgb, var(--bcs-accent) 16%, var(--card-background-color));
} }
.card { .card{
border: 1px solid var(--divider-color); border:1px solid var(--divider-color);
background: var(--card-background-color); background:var(--card-background-color);
border-radius: 16px; border-radius:16px; padding:12px; margin:10px 0;
padding: 12px; }
margin: 10px 0; .row{ display:flex; justify-content:space-between; gap:10px; align-items:flex-start; }
.muted{ color:var(--secondary-text-color); font-size:13px; margin-top:4px; }
.small{ font-size:12px; }
.badge{
border:1px solid var(--divider-color);
border-radius:999px; padding:2px 10px;
font-size:12px; font-weight:700; height:fit-content;
}
.badge.custom{ border-color:var(--bcs-accent); color:var(--bcs-accent); }
.error{ color:#b00020; white-space:pre-wrap; margin-top:10px; }
.grid{ display:grid; grid-template-columns:1fr; gap:10px; }
.field{ display:grid; gap:6px; }
input{
padding:10px 12px; border-radius:12px;
border:1px solid var(--divider-color);
background:var(--card-background-color);
color:var(--primary-text-color);
outline:none;
}
input:focus{
border-color:var(--bcs-accent);
box-shadow:0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
} }
.row { a{ color:var(--bcs-accent); text-decoration:none; }
display: flex; a:hover{ text-decoration:underline; }
justify-content: space-between;
gap: 10px;
align-items: flex-start;
}
.muted {
color: var(--secondary-text-color);
font-size: 13px;
margin-top: 4px;
}
.badge {
border: 1px solid var(--divider-color);
border-radius: 999px;
padding: 2px 10px;
font-size: 12px;
font-weight: 700;
height: fit-content;
}
.badge.custom {
border-color: var(--bcs-accent);
color: var(--bcs-accent);
}
.error {
color: #b00020;
white-space: pre-wrap;
margin-top: 10px;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
}
.field {
display: grid;
gap: 6px;
}
input {
padding: 10px 12px;
border-radius: 12px;
border: 1px solid var(--divider-color);
background: var(--card-background-color);
color: var(--primary-text-color);
outline: none;
}
input:focus {
border-color: var(--bcs-accent);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--bcs-accent) 20%, transparent);
}
.small { font-size: 12px; }
a { color: var(--bcs-accent); text-decoration: none; }
a:hover { text-decoration: underline; }
</style> </style>
<div class="mobilebar"> <div class="mobilebar">
@@ -364,7 +228,6 @@ class BahmcloudStorePanel extends HTMLElement {
<div class="s" id="subtitle">BCS — loading…</div> <div class="s" id="subtitle">BCS — loading…</div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<button id="refreshBtn">Refresh</button> <button id="refreshBtn">Refresh</button>
</div> </div>
@@ -441,9 +304,14 @@ class BahmcloudStorePanel extends HTMLElement {
? `<span class="badge custom">Custom</span>` ? `<span class="badge custom">Custom</span>`
: `<span class="badge">Index</span>`; : `<span class="badge">Index</span>`;
const owner = r.owner ? `Owner: ${this._esc(r.owner)}` : "Owner: -"; const desc = r.meta_description || r.provider_description || "No description available.";
const provider = r.provider ? `Provider: ${this._esc(r.provider)}` : "Provider: -";
const desc = r.description || "No description available."; const creator = r.owner ? `Creator: ${this._esc(r.owner)}` : "Creator: -";
const author = r.meta_author ? `Author: ${this._esc(r.meta_author)}` : null;
const maint = r.meta_maintainer ? `Maintainer: ${this._esc(r.meta_maintainer)}` : null;
const metaSrc = r.meta_source ? `Meta: ${this._esc(r.meta_source)}` : null;
const lineBits = [creator, author, maint, metaSrc].filter(Boolean);
return ` return `
<div class="card"> <div class="card">
@@ -451,7 +319,7 @@ class BahmcloudStorePanel extends HTMLElement {
<div> <div>
<div><strong>${this._esc(r.name)}</strong></div> <div><strong>${this._esc(r.name)}</strong></div>
<div class="muted">${this._esc(desc)}</div> <div class="muted">${this._esc(desc)}</div>
<div class="muted small">${owner} · ${provider}</div> <div class="muted small">${lineBits.map(x => this._esc(x)).join(" · ")}</div>
<div class="muted small"><a href="${this._esc(r.url)}" target="_blank" rel="noreferrer">Open repository</a></div> <div class="muted small"><a href="${this._esc(r.url)}" target="_blank" rel="noreferrer">Open repository</a></div>
</div> </div>
${badge} ${badge}