9 Commits
0.5.6 ... 0.5.8

Author SHA1 Message Date
b2d3d940f2 add 0.5.8 2026-01-17 19:05:55 +00:00
8b1d828c59 add 0.5.8 2026-01-17 19:04:45 +00:00
824a9e5cad 0.5.8 2026-01-17 19:03:51 +00:00
1cbc204e88 Fix readme 2026-01-17 19:02:16 +00:00
561c323e67 Fix readme 2026-01-17 19:01:43 +00:00
5c604b40c6 bcs.yaml aktualisiert 2026-01-17 12:00:05 +00:00
cc8db6a034 Add 0.5.7 2026-01-17 11:01:14 +00:00
e0ad133221 0.5.7 2026-01-17 11:00:36 +00:00
0e27a03aaf Fix laxout mobile 2026-01-17 10:59:48 +00:00
5 changed files with 53 additions and 117 deletions

View File

@@ -11,6 +11,23 @@ Sections:
--- ---
## [0.5.8] - 2026-01-17
### Changed
- Mobile UI layout stabilized to prevent horizontal shifting.
- README rendering no longer expands the page width on mobile devices.
- Tables and code blocks inside README now scroll within their container.
- Floating action buttons removed to avoid UI overlap on small screens.
- Header icon buttons improved for better visibility in light and dark mode.
## [0.5.7] - 2026-01-17
### Changed
- Mobile UI improvements: removed floating action buttons to prevent overlay issues.
- Improved responsive layout to avoid horizontal overflow (badges, URLs, descriptions).
- README rendering on mobile is more stable (better wrapping and image scaling).
- Header icon buttons are more readable in both light and dark mode.
## [0.5.6] - 2026-01-17 ## [0.5.6] - 2026-01-17
### Added ### Added

View File

@@ -4,7 +4,7 @@ description: >
Supports GitHub, GitLab, Gitea and Bahmcloud repositories with Supports GitHub, GitLab, Gitea and Bahmcloud repositories with
a central index, UI panel and API, similar to HACS but independent. a central index, UI panel and API, similar to HACS but independent.
category: Store category: integration
author: Bahmcloud author: Bahmcloud
maintainer: Bahmcloud maintainer: Bahmcloud

View File

@@ -1,7 +1,7 @@
{ {
"domain": "bahmcloud_store", "domain": "bahmcloud_store",
"name": "Bahmcloud Store", "name": "Bahmcloud Store",
"version": "0.5.6", "version": "0.5.7",
"documentation": "https://git.bahmcloud.de/bahmcloud/bahmcloud_store", "documentation": "https://git.bahmcloud.de/bahmcloud/bahmcloud_store",
"platforms": ["update"], "platforms": ["update"],
"requirements": [], "requirements": [],

View File

@@ -302,7 +302,7 @@ class BahmcloudStorePanel extends HTMLElement {
root.innerHTML = ` root.innerHTML = `
<style> <style>
:host { display:block; min-height:100%; --bcs-accent:#1E88E5; } :host { display:block; min-height:100%; --bcs-accent:#1E88E5; max-width:100%; overflow-x:hidden; }
.mobilebar{ .mobilebar{
position:sticky; top:0; z-index:50; position:sticky; top:0; z-index:50;
@@ -317,13 +317,15 @@ class BahmcloudStorePanel extends HTMLElement {
.iconbtn{ .iconbtn{
width:40px; height:40px; border-radius:14px; width:40px; height:40px; border-radius:14px;
display:flex; align-items:center; justify-content:center; display:flex; align-items:center; justify-content:center;
border:1px solid var(--divider-color); /* Ensure icon visibility on app header (light & dark modes) */
background: var(--card-background-color); color: var(--app-header-text-color, var(--primary-text-color));
border: 1px solid rgba(255,255,255,0.35);
background: rgba(255,255,255,0.16);
cursor:pointer; user-select:none; cursor:pointer; user-select:none;
} }
.iconbtn:hover{ filter:brightness(0.98); } .iconbtn:hover{ filter:brightness(0.98); }
.wrap{ max-width:1200px; margin:0 auto; padding:16px; } .wrap{ max-width:1200px; margin:0 auto; padding:16px; overflow-x:hidden; }
.tabs{ display:flex; gap:10px; flex-wrap:wrap; margin:8px 0 16px; } .tabs{ display:flex; gap:10px; flex-wrap:wrap; margin:8px 0 16px; }
.tab{ .tab{
@@ -336,9 +338,12 @@ class BahmcloudStorePanel extends HTMLElement {
.grid{ display:grid; gap:12px; grid-template-columns: repeat(1, minmax(0, 1fr)); } .grid{ display:grid; gap:12px; grid-template-columns: repeat(1, minmax(0, 1fr)); }
@media (min-width: 900px){ .grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (min-width: 900px){ .grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Prevent grid children from forcing horizontal overflow (mobile) */
.grid > *{ min-width:0; }
.grid2{ display:grid; gap:12px; grid-template-columns: 1fr; } .grid2{ display:grid; gap:12px; grid-template-columns: 1fr; }
@media (min-width: 1024px){ .grid2{ grid-template-columns: 1.2fr .8fr; } } @media (min-width: 1024px){ .grid2{ grid-template-columns: 1.2fr .8fr; } }
.grid2 > *{ min-width:0; }
.card{ .card{
padding:14px 14px; padding:14px 14px;
@@ -346,10 +351,11 @@ class BahmcloudStorePanel extends HTMLElement {
background: var(--card-background-color); background: var(--card-background-color);
border:1px solid var(--divider-color); border:1px solid var(--divider-color);
box-shadow: 0 1px 0 rgba(0,0,0,.04); box-shadow: 0 1px 0 rgba(0,0,0,.04);
overflow:hidden;
} }
.row{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; } .row{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.muted{ color: var(--secondary-text-color); } .muted{ color: var(--secondary-text-color); overflow-wrap:anywhere; word-break:break-word; }
.small{ font-size: 12px; } .small{ font-size: 12px; }
.badge{ .badge{
padding:6px 10px; padding:6px 10px;
@@ -358,7 +364,10 @@ class BahmcloudStorePanel extends HTMLElement {
background: rgba(30,136,229,.06); background: rgba(30,136,229,.06);
color: var(--primary-text-color); color: var(--primary-text-color);
font-size: 12px; font-size: 12px;
white-space:nowrap; white-space:normal;
max-width:55%;
overflow:hidden;
text-overflow:ellipsis;
} }
.filters{ display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; } .filters{ display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
@@ -397,36 +406,6 @@ class BahmcloudStorePanel extends HTMLElement {
background: rgba(255, 82, 82, .08); background: rgba(255, 82, 82, .08);
} }
.fabs{
position: fixed;
right: 16px;
bottom: 16px;
display:flex;
flex-direction:column;
gap:10px;
z-index: 60;
}
.fabbtn{
width:54px; height:54px;
border-radius:18px;
border:1px solid var(--divider-color);
background: var(--card-background-color);
display:flex; align-items:center; justify-content:center;
cursor:pointer;
box-shadow: 0 8px 18px rgba(0,0,0,.12);
user-select:none;
font-size: 18px;
padding: 0;
}
.fabbtn.primary{
border-color: rgba(30,136,229,.35);
background: rgba(30,136,229,.10);
}
.fabbtn:disabled{
opacity: .55;
cursor: not-allowed;
}
pre.readme{ pre.readme{
padding: 12px; padding: 12px;
border-radius: 14px; border-radius: 14px;
@@ -437,7 +416,10 @@ class BahmcloudStorePanel extends HTMLElement {
line-height: 1.4; line-height: 1.4;
} }
/* Markdown can contain very wide content (tables/images). Keep it within the viewport. */
.md{ overflow-wrap:anywhere; word-break:break-word; max-width:100%; min-width:0; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.md :is(h1,h2,h3){ margin-top: 12px; } .md :is(h1,h2,h3){ margin-top: 12px; }
.md img{ max-width:100%; height:auto; }
.md code{ .md code{
padding: 2px 5px; padding: 2px 5px;
border-radius: 8px; border-radius: 8px;
@@ -454,13 +436,19 @@ class BahmcloudStorePanel extends HTMLElement {
.md table{ .md table{
width:100%; width:100%;
border-collapse: collapse; border-collapse: collapse;
overflow:auto; overflow-x:auto;
overflow-y:hidden;
-webkit-overflow-scrolling: touch;
display:block; display:block;
max-width:100%;
} }
.md th, .md td{ .md th, .md td{
border: 1px solid var(--divider-color); border: 1px solid var(--divider-color);
padding: 8px; padding: 8px;
text-align:left; text-align:left;
max-width:100%;
overflow-wrap:anywhere;
word-break:break-word;
} }
</style> </style>
@@ -488,7 +476,7 @@ class BahmcloudStorePanel extends HTMLElement {
<div id="content"></div> <div id="content"></div>
</div> </div>
<div id="fabs"></div>
`; `;
root.getElementById("menuBtn").addEventListener("click", () => this._toggleMenu()); root.getElementById("menuBtn").addEventListener("click", () => this._toggleMenu());
@@ -528,8 +516,7 @@ class BahmcloudStorePanel extends HTMLElement {
setActive("tabAbout", this._view === "about"); setActive("tabAbout", this._view === "about");
const content = root.getElementById("content"); const content = root.getElementById("content");
const fabs = root.getElementById("fabs"); if (!content) return;
if (!content || !fabs) return;
const err = this._error const err = this._error
? `<div class="err"><strong>Error:</strong> ${this._esc(this._error)}</div>` ? `<div class="err"><strong>Error:</strong> ${this._esc(this._error)}</div>`
@@ -537,13 +524,11 @@ class BahmcloudStorePanel extends HTMLElement {
if (this._loading) { if (this._loading) {
content.innerHTML = `${err}<div class="card">Loading…</div>`; content.innerHTML = `${err}<div class="card">Loading…</div>`;
fabs.innerHTML = "";
return; return;
} }
if (!this._data?.ok) { if (!this._data?.ok) {
content.innerHTML = `${err}<div class="card">No data. Please refresh.</div>`; content.innerHTML = `${err}<div class="card">No data. Please refresh.</div>`;
fabs.innerHTML = "";
return; return;
} }
@@ -554,13 +539,11 @@ class BahmcloudStorePanel extends HTMLElement {
else if (this._view === "detail") html = this._renderDetail(); else if (this._view === "detail") html = this._renderDetail();
content.innerHTML = `${err}${html}`; content.innerHTML = `${err}${html}`;
fabs.innerHTML = this._view === "detail" ? this._renderFabs() : "";
if (this._view === "store") this._wireStore(); if (this._view === "store") this._wireStore();
if (this._view === "manage") this._wireManage(); if (this._view === "manage") this._wireManage();
if (this._view === "detail") { if (this._view === "detail") {
this._wireDetail(); // now always wires buttons this._wireDetail(); // now always wires buttons
this._wireFabs();
} }
} }
@@ -907,75 +890,6 @@ class BahmcloudStorePanel extends HTMLElement {
} catch (_) {} } catch (_) {}
} }
_renderFabs() {
const r = this._detailRepo;
if (!r) return "";
const repoId = this._safeId(r?.id);
const installed = this._asBoolStrict(r?.installed);
const latest = this._safeText(r?.latest_version);
const installedVersion = this._safeText(r?.installed_version);
const busy = this._installingRepoId === repoId || this._updatingRepoId === repoId || this._uninstallingRepoId === repoId;
const updateAvailable = installed && !!latest && (!installedVersion || latest !== installedVersion);
const installDisabled = installed || busy;
const updateDisabled = !updateAvailable || busy;
const uninstallDisabled = !installed || busy;
return `
<div class="fabs">
<button class="fabbtn primary" id="fabOpen" title="Open repository">↗</button>
<button class="fabbtn" id="fabReload" title="Reload README">⟳</button>
<button class="fabbtn" id="fabInstall" title="${installDisabled ? (installed ? "Already installed" : "Installing…") : "Install"}" ${installDisabled ? "disabled" : ""}></button>
<button class="fabbtn" id="fabUpdate" title="${updateDisabled ? (!installed ? "Not installed" : "No update available") : "Update"}" ${updateDisabled ? "disabled" : ""}>↑</button>
<button class="fabbtn" id="fabUninstall" title="${uninstallDisabled ? (!installed ? "Not installed" : "Busy") : "Uninstall"}" ${uninstallDisabled ? "disabled" : ""}>✕</button>
<button class="fabbtn" id="fabInfo" title="About">i</button>
</div>
`;
}
_wireFabs() {
const root = this.shadowRoot;
const r = this._detailRepo;
if (!r) return;
const url = this._safeText(r?.url);
const repoId = this._safeId(r?.id);
const open = root.getElementById("fabOpen");
const reload = root.getElementById("fabReload");
const install = root.getElementById("fabInstall");
const update = root.getElementById("fabUpdate");
const uninstall = root.getElementById("fabUninstall");
const info = root.getElementById("fabInfo");
if (open) open.addEventListener("click", () => url && window.open(url, "_blank", "noreferrer"));
if (reload) reload.addEventListener("click", () => this._detailRepoId && this._loadReadme(this._detailRepoId));
if (install) {
install.addEventListener("click", () => {
if (install.disabled) return;
this._installRepo(repoId);
});
}
if (update) {
update.addEventListener("click", () => {
if (update.disabled) return;
this._updateRepo(repoId);
});
}
if (uninstall) {
uninstall.addEventListener("click", () => {
if (uninstall.disabled) return;
this._uninstallRepo(repoId);
});
}
if (info) info.addEventListener("click", () => { this._view = "about"; this._update(); });
}
_renderManage() { _renderManage() {
const repos = Array.isArray(this._data.repos) ? this._data.repos : []; const repos = Array.isArray(this._data.repos) ? this._data.repos : [];

View File

@@ -1,10 +1,15 @@
body { font-family: system-ui, sans-serif; margin:0; } body { font-family: system-ui, sans-serif; margin:0; }
.wrap { padding: 16px; max-width: 1000px; margin: 0 auto; } .wrap { padding: 16px; max-width: 1000px; margin: 0 auto; }
.card { border: 1px solid #ddd; border-radius: 10px; padding: 12px; margin: 10px 0; } .card { border: 1px solid #ddd; border-radius: 10px; padding: 12px; margin: 10px 0; }
.row { display:flex; justify-content:space-between; gap: 12px; align-items: flex-start; } .row { display:flex; justify-content:space-between; gap: 12px; align-items: flex-start; flex-wrap: wrap; min-width:0; }
.badge { border: 1px solid #bbb; border-radius: 999px; padding: 2px 8px; font-size: 12px; height: fit-content; } .badge { border: 1px solid #bbb; border-radius: 999px; padding: 2px 8px; font-size: 12px; height: fit-content; }
.muted { color: #666; font-size: 13px; margin-top: 4px; } .muted { color: #666; font-size: 13px; margin-top: 4px; }
.actions { display:flex; gap: 8px; margin-top: 10px; } .actions { display:flex; gap: 8px; margin-top: 10px; }
button { padding: 8px 12px; cursor:pointer; } button { padding: 8px 12px; cursor:pointer; }
button[disabled] { opacity: 0.6; cursor: not-allowed; } button[disabled] { opacity: 0.6; cursor: not-allowed; }
a { color: inherit; } a { color: inherit; }
/* Basic markdown safety (in case styles.css is used by older panels) */
.md { max-width: 100%; overflow-x: auto; }
.md table { display:block; max-width:100%; overflow-x:auto; }
.md img { max-width: 100%; height: auto; }