custom_components/bahmcloud_store/panel/panel.js aktualisiert
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last resort
|
||||||
|
mount.innerHTML = `<div class="muted">Markdown renderer not available on this client. Use “Show raw Markdown”.</div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last resort: show nothing here (raw is still available via details)
|
// No readme text loaded
|
||||||
mount.innerHTML = `<div class="muted">Unable to render Markdown on this client.</div>`;
|
mount.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderFabs() {
|
_renderFabs() {
|
||||||
|
|||||||
Reference in New Issue
Block a user