@@ -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.25);
background: rgba(0,0,0,0.18);
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{
@@ -346,10 +348,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 +361,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 +403,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 +413,9 @@ class BahmcloudStorePanel extends HTMLElement {
line-height: 1.4;
line-height: 1.4;
}
}
.md{ overflow-wrap:anywhere; word-break:break-word; }
.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;
@@ -456,6 +434,7 @@ class BahmcloudStorePanel extends HTMLElement {
border-collapse: collapse;
border-collapse: collapse;
overflow:auto;
overflow:auto;
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);
@@ -488,7 +467,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 +507,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 +515,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 +530,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 +881,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 : [ ] ;