mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
better list page
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: -8px;
|
top: -8px;
|
||||||
left: 56%;
|
left: 56%;
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,38 +24,44 @@
|
|||||||
Marketplace
|
Marketplace
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #list>
|
<ng-template #list>
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="4" sizeSm="3" sizeLg="3" sizeXl="2">
|
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="6" sizeSm="4" sizeLg="3">
|
||||||
<ion-card class="installed-card" [routerLink]="['/services', pkg.value.entry.manifest.id]">
|
<ion-card class="installed-card" [routerLink]="['/services', pkg.value.entry.manifest.id]">
|
||||||
|
<div
|
||||||
|
class="bulb"
|
||||||
|
[style.background-color]="connectionFailure ? 'var(--ion-color-dark)' : 'var(--ion-color-' + pkg.value.primaryRendering.color + ')'"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="launch-container" *ngIf="pkg.value.entry.manifest.interfaces | hasUi">
|
<div class="launch-container" *ngIf="pkg.value.entry.manifest.interfaces | hasUi">
|
||||||
<div class="launch-button-triangle" (click)="launchUi(pkg.value.entry, $event)" [class.launch-disabled]="!(pkg.value.entry.state | isLaunchable : pkg.value.entry.installed?.status.main.status : pkg.value.entry.manifest.interfaces)">
|
<div class="launch-button-triangle" (click)="launchUi(pkg.value.entry, $event)" [class.launch-disabled]="!(pkg.value.entry.state | isLaunchable : pkg.value.entry.installed?.status.main.status : pkg.value.entry.manifest.interfaces)">
|
||||||
<ion-icon name="open-outline"></ion-icon>
|
<ion-icon name="open-outline"></ion-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<img class="main-img" [src]="pkg.value.entry['static-files'].icon" alt="icon" />
|
||||||
<img style="position: absolute" class="main-img" [src]="pkg.value.entry['static-files'].icon" alt="icon" />
|
|
||||||
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
|
||||||
<img *ngIf="connectionFailure" class="bulb-off" src="assets/img/off-bulb.png" />
|
|
||||||
<img *ngIf="!connectionFailure" [class]="pkg.value.bulb.class" [src]="pkg.value.bulb.img" />
|
|
||||||
|
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<ion-grid class="status-grid">
|
<ion-card-title>
|
||||||
<ion-row class="ion-align-items-center">
|
{{ pkg.value.entry.manifest.title }}
|
||||||
<ion-col></ion-col>
|
</ion-card-title>
|
||||||
<ion-col>
|
|
||||||
<status *ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state" [disconnected]="connectionFailure" [rendering]="pkg.value.primaryRendering" size="calc(8px + .4vw)" weight="bold"></status>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col>
|
|
||||||
<ion-icon *ngIf="pkg.value.error" name="warning-outline" color="warning"></ion-icon>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
<p *ngIf="!!pkg.value.installProgress" class="main-status"><ion-text color="primary">{{ pkg.value.entry.state | titlecase }}...{{ pkg.value.installProgress.totalProgress }}%</ion-text></p>
|
|
||||||
<ion-card-title>{{ pkg.value.entry.manifest.title }}</ion-card-title>
|
|
||||||
</ion-card-header>
|
</ion-card-header>
|
||||||
|
<ion-card-content>
|
||||||
|
<ion-toolbar class="status-toolbar">
|
||||||
|
<ion-title>
|
||||||
|
<ion-text *ngIf="!!pkg.value.installProgress" color="primary">{{ pkg.value.entry.state | titlecase }}...{{ pkg.value.installProgress.totalProgress }}%</ion-text>
|
||||||
|
<status
|
||||||
|
*ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state"
|
||||||
|
[disconnected]="connectionFailure"
|
||||||
|
[rendering]="pkg.value.primaryRendering"
|
||||||
|
weight="bold"
|
||||||
|
size="calc(10px + .5vw)"
|
||||||
|
>
|
||||||
|
</status>
|
||||||
|
</ion-title>
|
||||||
|
<ion-icon *ngIf="pkg.value.error" name="warning-outline" color="warning"></ion-icon>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-card-content>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
|
|||||||
@@ -2,20 +2,16 @@
|
|||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background: linear-gradient(37deg, #333333, #131313);
|
background: linear-gradient(37deg, #333333, #131313);
|
||||||
border-radius: 10px;
|
border-radius: 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
ion-card-header {
|
ion-card-header {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|
||||||
status {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-card-title {
|
ion-card-title {
|
||||||
font-size: calc(10px + .4vw);
|
font-family: 'Montserrat';
|
||||||
color: var(--ion-color-dark);
|
font-size: calc(10px + .5vw);
|
||||||
margin: 10px 0;
|
margin-bottom: 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -24,41 +20,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-img {
|
.main-img {
|
||||||
width: 50%;
|
width: 40%;
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulb-on {
|
.bulb {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
left: -7px !important;
|
left: 10px !important;
|
||||||
top: -7px !important;
|
top: 10px !important;
|
||||||
height: 25px !important;
|
height: calc(10px + .5vw);
|
||||||
width: 25px !important;
|
width: calc(10px + .5vw);
|
||||||
margin: 9px;
|
border-radius: 100%;
|
||||||
}
|
box-shadow: 0 0 4px 4px rgba(255, 255, 255, 0.3)
|
||||||
|
|
||||||
.bulb-off {
|
|
||||||
position: absolute !important;
|
|
||||||
left: -1px !important;
|
|
||||||
top: -1px !important;
|
|
||||||
height: 13px !important;
|
|
||||||
width: 13px !important;
|
|
||||||
margin: 9px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.launch-button-triangle {
|
.launch-button-triangle {
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 22px;
|
border-width: 24px;
|
||||||
border-color: rgb(70 193 255 / 75%) rgb(70 193 255 / 75%) transparent transparent;
|
border-color: rgb(70 193 255 / 75%) rgb(70 193 255 / 75%) transparent transparent;
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: rgb(70 193 255) rgb(70 193 255) transparent transparent;
|
border-color: rgb(70 193 255) rgb(70 193 255) transparent transparent;
|
||||||
}
|
}
|
||||||
ion-icon {
|
ion-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 7px;
|
right: 8px;
|
||||||
top: 7px;
|
top: 8px;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,22 +67,13 @@
|
|||||||
right: 0px;
|
right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-status {
|
.status-toolbar {
|
||||||
font-size: calc(8px + .4vw);
|
--min-height: 42px;
|
||||||
font-weight: bold;
|
border-radius: 6px;
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-grid {
|
|
||||||
--ion-grid-padding: 0;
|
|
||||||
ion-row {
|
|
||||||
min-height: 22px;
|
|
||||||
}
|
|
||||||
ion-col {
|
|
||||||
--ion-grid-column-padding: 0
|
|
||||||
}
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
font-size: calc(12px + .4vw);
|
font-size: calc(10px + .5vw);
|
||||||
padding-top: 4px;
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: calc(2vh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,10 +58,6 @@ export class AppListPage {
|
|||||||
if (this.pkgs[id]) return
|
if (this.pkgs[id]) return
|
||||||
this.pkgs[id] = {
|
this.pkgs[id] = {
|
||||||
entry: pkgs[id],
|
entry: pkgs[id],
|
||||||
bulb: {
|
|
||||||
class: 'bulb-off',
|
|
||||||
img: 'assets/img/off-bulb.png',
|
|
||||||
},
|
|
||||||
primaryRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
primaryRendering: PrimaryRendering[renderPkgStatus(pkgs[id]).primary],
|
||||||
installProgress: !isEmptyObject(pkgs[id]['install-progress']) ? this.installPackageService.transform(pkgs[id]['install-progress']) : undefined,
|
installProgress: !isEmptyObject(pkgs[id]['install-progress']) ? this.installPackageService.transform(pkgs[id]['install-progress']) : undefined,
|
||||||
error: false,
|
error: false,
|
||||||
@@ -70,31 +66,10 @@ export class AppListPage {
|
|||||||
// subscribe to pkg
|
// subscribe to pkg
|
||||||
this.pkgs[id].sub = this.patch.watch$('package-data', id).subscribe(pkg => {
|
this.pkgs[id].sub = this.patch.watch$('package-data', id).subscribe(pkg => {
|
||||||
if (!pkg) return
|
if (!pkg) return
|
||||||
let bulbClass = 'bulb-on'
|
|
||||||
let img = ''
|
|
||||||
const statuses = renderPkgStatus(pkg)
|
const statuses = renderPkgStatus(pkg)
|
||||||
const primaryRendering = PrimaryRendering[statuses.primary]
|
const primaryRendering = PrimaryRendering[statuses.primary]
|
||||||
switch (primaryRendering.color) {
|
|
||||||
case 'danger':
|
|
||||||
img = 'assets/img/danger-bulb.png'
|
|
||||||
break
|
|
||||||
case 'success':
|
|
||||||
img = 'assets/img/success-bulb.png'
|
|
||||||
break
|
|
||||||
case 'warning':
|
|
||||||
img = 'assets/img/warning-bulb.png'
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
bulbClass = 'bulb-off',
|
|
||||||
img = 'assets/img/off-bulb.png'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this.pkgs[id].entry = pkg
|
this.pkgs[id].entry = pkg
|
||||||
this.pkgs[id].installProgress = !isEmptyObject(pkg['install-progress']) ? this.installPackageService.transform(pkg['install-progress']) : undefined
|
this.pkgs[id].installProgress = !isEmptyObject(pkg['install-progress']) ? this.installPackageService.transform(pkg['install-progress']) : undefined
|
||||||
this.pkgs[id].bulb = {
|
|
||||||
class: bulbClass,
|
|
||||||
img,
|
|
||||||
}
|
|
||||||
this.pkgs[id].primaryRendering = primaryRendering
|
this.pkgs[id].primaryRendering = primaryRendering
|
||||||
this.pkgs[id].error = [HealthStatus.NeedsConfig, HealthStatus.Failure].includes(statuses.health) || [DependencyStatus.Issue, DependencyStatus.Critical].includes(statuses.dependency)
|
this.pkgs[id].error = [HealthStatus.NeedsConfig, HealthStatus.Failure].includes(statuses.health) || [DependencyStatus.Issue, DependencyStatus.Critical].includes(statuses.dependency)
|
||||||
})
|
})
|
||||||
@@ -126,10 +101,6 @@ export class AppListPage {
|
|||||||
|
|
||||||
interface PkgInfo {
|
interface PkgInfo {
|
||||||
entry: PackageDataEntry
|
entry: PackageDataEntry
|
||||||
bulb: {
|
|
||||||
class: string
|
|
||||||
img: string
|
|
||||||
}
|
|
||||||
primaryRendering: StatusRendering
|
primaryRendering: StatusRendering
|
||||||
installProgress: ProgressData
|
installProgress: ProgressData
|
||||||
error: boolean
|
error: boolean
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
</ion-label>
|
</ion-label>
|
||||||
<ng-container *ngIf="pkg.state === PackageState.Installed && !connectionFailure">
|
<ng-container *ngIf="pkg.state === PackageState.Installed && !connectionFailure">
|
||||||
<ion-button slot="end" class="action-button" *ngIf="pkg.manifest.interfaces | hasUi" [disabled]="!(pkg.state | isLaunchable : pkg.installed.status.main.status : pkg.manifest.interfaces)" (click)="launchUi()">
|
<ion-button slot="end" class="action-button" *ngIf="pkg.manifest.interfaces | hasUi" [disabled]="!(pkg.state | isLaunchable : pkg.installed.status.main.status : pkg.manifest.interfaces)" (click)="launchUi()">
|
||||||
<ion-icon slot="start" name="open-outline"></ion-icon>
|
Launch UI
|
||||||
Open UI
|
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button slot="end" class="action-button" *ngIf="!pkg.installed.status.configured" (click)="presentModalConfig()">
|
<ion-button slot="end" class="action-button" *ngIf="!pkg.installed.status.configured" (click)="presentModalConfig()">
|
||||||
Configure
|
Configure
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ ion-card-title {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ion-item {
|
ion-item {
|
||||||
--border-radius: 4px;
|
--border-radius: 6px;
|
||||||
--border-style: solid;
|
--border-style: solid;
|
||||||
--border-width: 1px;
|
--border-width: 1px;
|
||||||
--border-color: var(--ion-color-light);
|
--border-color: var(--ion-color-light);
|
||||||
|
|||||||
@@ -234,10 +234,6 @@ ion-button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-modal {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-slides {
|
ion-slides {
|
||||||
.slider-wrapper {
|
.slider-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -255,7 +251,7 @@ ion-item-divider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ion-item {
|
ion-item {
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-label {
|
ion-label {
|
||||||
@@ -278,7 +274,7 @@ ion-loading {
|
|||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-style: groove;
|
border-style: groove;
|
||||||
border-color: dimgrey;
|
border-color: dimgrey;
|
||||||
border-radius: 10px;
|
border-radius: 6px;
|
||||||
box-shadow: 4px 4px 16px var(--ion-color-primary);
|
box-shadow: 4px 4px 16px var(--ion-color-primary);
|
||||||
--padding-start: 10px;
|
--padding-start: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user