custom_components/bahmcloud_store/panel/panel.js aktualisiert
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
Reference in New Issue
Block a user