custom_components/bahmcloud_store/panel/panel.js aktualisiert

This commit is contained in:
2026-01-15 11:36:15 +00:00
parent 236099e562
commit b5e98898e0

View File

@@ -21,7 +21,7 @@ class BahmcloudStorePanel extends HTMLElement {
this._readmeLoading = false; this._readmeLoading = false;
this._readmeText = null; this._readmeText = null;
this._readmeHtml = null; // backend may provide; we don't rely on it anymore this._readmeHtml = null; // backend may provide; client renderer does not rely on it
this._readmeError = null; this._readmeError = null;
} }
@@ -331,10 +331,17 @@ class BahmcloudStorePanel extends HTMLElement {
details{ margin-top: 10px; } details{ margin-top: 10px; }
summary{ cursor:pointer; color: var(--bcs-accent); font-weight: 900; } summary{ cursor:pointer; color: var(--bcs-accent); font-weight: 900; }
/* Pretty Markdown container spacing (ha-markdown renders inside) */ /* Pretty Markdown container */
.md { line-height: 1.65; font-size: 14px; } .md { line-height: 1.65; font-size: 14px; }
.md :is(h1,h2,h3){ margin: 18px 0 10px; } .md :is(h1,h2,h3){ margin: 18px 0 10px; }
.md :is(p,ul,ol,pre,blockquote,table){ margin: 10px 0; } .md :is(p,ul,ol,pre,blockquote,table){ margin: 10px 0; }
.md pre { overflow:auto; padding:12px; border-radius:14px; border:1px solid var(--divider-color); }
.md code { padding:2px 6px; border-radius:8px; border:1px solid var(--divider-color); }
.md blockquote { border-left:4px solid var(--bcs-accent); padding:8px 12px; border-radius:12px;
background: color-mix(in srgb, var(--bcs-accent) 8%, var(--card-background-color)); }
.md table{ width:100%; border-collapse: collapse; }
.md th,.md td{ border:1px solid var(--divider-color); padding:8px; text-align:left; }
.md img{ max-width:100%; height:auto; border-radius:12px; }
</style> </style>
<div class="mobilebar"> <div class="mobilebar">
@@ -659,45 +666,79 @@ class BahmcloudStorePanel extends HTMLElement {
`; `;
} }
_mdToHtml(markdown) {
const md = String(markdown || "");
if (!md.trim()) return "";
// Prefer HA's frontend libs if present
const markedObj = window.marked;
const domPurify = window.DOMPurify;
let html = "";
try {
// marked can be a function or an object with parse()
if (markedObj && typeof markedObj.parse === "function") {
html = markedObj.parse(md, { breaks: true, gfm: true });
} else if (typeof markedObj === "function") {
html = markedObj(md);
} else {
return "";
}
} catch (_) {
return "";
}
try {
if (domPurify && typeof domPurify.sanitize === "function") {
html = domPurify.sanitize(html);
}
} catch (_) {}
return html;
}
_postprocessRenderedMarkdown(container) {
if (!container) return;
// Make links open in new tab
try {
const links = container.querySelectorAll("a[href]");
links.forEach((a) => {
a.setAttribute("target", "_blank");
a.setAttribute("rel", "noreferrer noopener");
});
} catch (_) {}
}
_wireDetail() { _wireDetail() {
const root = this.shadowRoot; const root = this.shadowRoot;
const mount = root.getElementById("readmePretty"); const mount = root.getElementById("readmePretty");
if (!mount) return; if (!mount) return;
// Always prefer HA's frontend markdown renderer to get a professional look.
// This uses the same renderer concept as HA's Markdown card (Marked.js). :contentReference[oaicite:1]{index=1}
if (this._readmeText) { if (this._readmeText) {
try { const html = this._mdToHtml(this._readmeText);
mount.innerHTML = "";
const el = document.createElement("ha-markdown"); if (html) {
// Ensure it has access to HA context (themes, link handling, etc.) mount.innerHTML = html;
el.hass = this._hass; this._postprocessRenderedMarkdown(mount);
// Different HA versions use either "content" or "markdown" internally;
// setting both is harmless and maximizes compatibility.
el.content = this._readmeText;
el.markdown = this._readmeText;
// Some versions support these flags; safe to set even if ignored.
el.allowHtml = false;
el.breaks = true;
mount.appendChild(el);
return; return;
} catch (_) {
// fall through to html/raw fallback
}
} }
// Fallback: if backend provided sanitized HTML, use it // Fallback: if backend provided sanitized HTML, use it
if (this._readmeHtml) { if (this._readmeHtml) {
mount.innerHTML = this._readmeHtml; mount.innerHTML = this._readmeHtml;
this._postprocessRenderedMarkdown(mount);
return; return;
} }
// Last resort: show nothing here (raw is still available via details) // Last resort
mount.innerHTML = `<div class="muted">Unable to render Markdown on this client.</div>`; mount.innerHTML = `<div class="muted">Markdown renderer not available on this client. Use “Show raw Markdown”.</div>`;
return;
}
// No readme text loaded
mount.innerHTML = "";
} }
_renderFabs() { _renderFabs() {