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() {
// 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;
}
_toggleMenu() {
// On desktop the sidebar is usually always visible; do nothing.
if (this._isDesktop()) return;
// Primary: dispatch the standard HA event from THIS element so it bubbles.
try {
const ev = new Event("hass-toggle-menu", { bubbles: true, composed: true });
this.dispatchEvent(ev);
return; // often enough on mobile
return;
} catch (_) {}
// Secondary: try again via host/root
try {
const host = this.shadowRoot?.host;
if (host) {
@@ -69,44 +62,6 @@ class BahmcloudStorePanel extends HTMLElement {
}
} 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._update();
}
@@ -170,189 +125,98 @@ class BahmcloudStorePanel extends HTMLElement {
root.innerHTML = `
<style>
:host {
display: block;
height: auto;
min-height: 100%;
--bcs-accent: #1E88E5;
}
:host { display:block; min-height:100%; --bcs-accent:#1E88E5; }
.mobilebar {
position: sticky;
top: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
.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);
border-bottom:1px solid var(--divider-color);
}
.mobilebar .left, .mobilebar .right { display:flex; align-items:center; gap:8px; }
.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);
.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;
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;
}
@media (min-width: 1024px) { .iconbtn.menu { display:none; } }
.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{
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 */
@media (min-width: 1024px) {
.iconbtn.menu {
display: none;
}
.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);
}
.brandtitle {
display: flex;
flex-direction: column;
line-height: 1.2;
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;
}
.brandtitle .t {
font-size: 16px;
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);
button.primary{
border-color:var(--bcs-accent);
background: color-mix(in srgb, var(--bcs-accent) 16%, var(--card-background-color));
}
.card {
border: 1px solid var(--divider-color);
background: var(--card-background-color);
border-radius: 16px;
padding: 12px;
margin: 10px 0;
.card{
border:1px solid var(--divider-color);
background:var(--card-background-color);
border-radius:16px; 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 {
display: flex;
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; }
a{ color:var(--bcs-accent); text-decoration:none; }
a:hover{ text-decoration:underline; }
</style>
<div class="mobilebar">
@@ -364,7 +228,6 @@ class BahmcloudStorePanel extends HTMLElement {
<div class="s" id="subtitle">BCS — loading…</div>
</div>
</div>
<div class="right">
<button id="refreshBtn">Refresh</button>
</div>
@@ -441,9 +304,14 @@ class BahmcloudStorePanel extends HTMLElement {
? `<span class="badge custom">Custom</span>`
: `<span class="badge">Index</span>`;
const owner = r.owner ? `Owner: ${this._esc(r.owner)}` : "Owner: -";
const provider = r.provider ? `Provider: ${this._esc(r.provider)}` : "Provider: -";
const desc = r.description || "No description available.";
const desc = r.meta_description || r.provider_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 `
<div class="card">
@@ -451,7 +319,7 @@ class BahmcloudStorePanel extends HTMLElement {
<div>
<div><strong>${this._esc(r.name)}</strong></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>
${badge}