Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2d3d940f2 | |||
| 8b1d828c59 | |||
| 824a9e5cad | |||
| 1cbc204e88 | |||
| 561c323e67 | |||
| 5c604b40c6 | |||
| cc8db6a034 | |||
| e0ad133221 | |||
| 0e27a03aaf |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -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
|
||||
|
||||
### Added
|
||||
|
||||
2
bcs.yaml
2
bcs.yaml
@@ -4,7 +4,7 @@ description: >
|
||||
Supports GitHub, GitLab, Gitea and Bahmcloud repositories with
|
||||
a central index, UI panel and API, similar to HACS but independent.
|
||||
|
||||
category: Store
|
||||
category: integration
|
||||
|
||||
author: Bahmcloud
|
||||
maintainer: Bahmcloud
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "bahmcloud_store",
|
||||
"name": "Bahmcloud Store",
|
||||
"version": "0.5.6",
|
||||
"version": "0.5.7",
|
||||
"documentation": "https://git.bahmcloud.de/bahmcloud/bahmcloud_store",
|
||||
"platforms": ["update"],
|
||||
"requirements": [],
|
||||
|
||||
@@ -302,7 +302,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
root.innerHTML = `
|
||||
<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{
|
||||
position:sticky; top:0; z-index:50;
|
||||
@@ -317,13 +317,15 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
.iconbtn{
|
||||
width:40px; height:40px; border-radius:14px;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
border:1px solid var(--divider-color);
|
||||
background: var(--card-background-color);
|
||||
/* Ensure icon visibility on app header (light & dark modes) */
|
||||
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;
|
||||
}
|
||||
.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; }
|
||||
.tab{
|
||||
@@ -336,9 +338,12 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
.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)); } }
|
||||
/* Prevent grid children from forcing horizontal overflow (mobile) */
|
||||
.grid > *{ min-width:0; }
|
||||
|
||||
.grid2{ display:grid; gap:12px; grid-template-columns: 1fr; }
|
||||
@media (min-width: 1024px){ .grid2{ grid-template-columns: 1.2fr .8fr; } }
|
||||
.grid2 > *{ min-width:0; }
|
||||
|
||||
.card{
|
||||
padding:14px 14px;
|
||||
@@ -346,10 +351,11 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
background: var(--card-background-color);
|
||||
border:1px solid var(--divider-color);
|
||||
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; }
|
||||
.muted{ color: var(--secondary-text-color); }
|
||||
.row{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap; }
|
||||
.muted{ color: var(--secondary-text-color); overflow-wrap:anywhere; word-break:break-word; }
|
||||
.small{ font-size: 12px; }
|
||||
.badge{
|
||||
padding:6px 10px;
|
||||
@@ -358,7 +364,10 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
background: rgba(30,136,229,.06);
|
||||
color: var(--primary-text-color);
|
||||
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; }
|
||||
@@ -397,36 +406,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
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{
|
||||
padding: 12px;
|
||||
border-radius: 14px;
|
||||
@@ -437,7 +416,10 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
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 img{ max-width:100%; height:auto; }
|
||||
.md code{
|
||||
padding: 2px 5px;
|
||||
border-radius: 8px;
|
||||
@@ -454,13 +436,19 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
.md table{
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
overflow:auto;
|
||||
overflow-x:auto;
|
||||
overflow-y:hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
display:block;
|
||||
max-width:100%;
|
||||
}
|
||||
.md th, .md td{
|
||||
border: 1px solid var(--divider-color);
|
||||
padding: 8px;
|
||||
text-align:left;
|
||||
max-width:100%;
|
||||
overflow-wrap:anywhere;
|
||||
word-break:break-word;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -488,7 +476,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
|
||||
<div id="fabs"></div>
|
||||
|
||||
`;
|
||||
|
||||
root.getElementById("menuBtn").addEventListener("click", () => this._toggleMenu());
|
||||
@@ -528,8 +516,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
setActive("tabAbout", this._view === "about");
|
||||
|
||||
const content = root.getElementById("content");
|
||||
const fabs = root.getElementById("fabs");
|
||||
if (!content || !fabs) return;
|
||||
if (!content) return;
|
||||
|
||||
const err = this._error
|
||||
? `<div class="err"><strong>Error:</strong> ${this._esc(this._error)}</div>`
|
||||
@@ -537,13 +524,11 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
if (this._loading) {
|
||||
content.innerHTML = `${err}<div class="card">Loading…</div>`;
|
||||
fabs.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._data?.ok) {
|
||||
content.innerHTML = `${err}<div class="card">No data. Please refresh.</div>`;
|
||||
fabs.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -554,13 +539,11 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
else if (this._view === "detail") html = this._renderDetail();
|
||||
|
||||
content.innerHTML = `${err}${html}`;
|
||||
fabs.innerHTML = this._view === "detail" ? this._renderFabs() : "";
|
||||
|
||||
if (this._view === "store") this._wireStore();
|
||||
if (this._view === "manage") this._wireManage();
|
||||
if (this._view === "detail") {
|
||||
this._wireDetail(); // now always wires buttons
|
||||
this._wireFabs();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,75 +890,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
} 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() {
|
||||
const repos = Array.isArray(this._data.repos) ? this._data.repos : [];
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
body { font-family: system-ui, sans-serif; margin:0; }
|
||||
.wrap { padding: 16px; max-width: 1000px; margin: 0 auto; }
|
||||
.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; }
|
||||
.muted { color: #666; font-size: 13px; margin-top: 4px; }
|
||||
.actions { display:flex; gap: 8px; margin-top: 10px; }
|
||||
button { padding: 8px 12px; cursor:pointer; }
|
||||
button[disabled] { opacity: 0.6; cursor: not-allowed; }
|
||||
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; }
|
||||
|
||||
Reference in New Issue
Block a user