mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
fixes and backwards compatability with new registry types
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@start9labs/marketplace",
|
"name": "@start9labs/marketplace",
|
||||||
"version": "0.3.25",
|
"version": "0.3.26",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/common": ">=13.2.0",
|
"@angular/common": ">=13.2.0",
|
||||||
"@angular/core": ">=13.2.0",
|
"@angular/core": ">=13.2.0",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ header {
|
|||||||
1;
|
1;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
border-right: 0.125rem solid;
|
border-right: 0.125rem solid;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1536px) {
|
@media screen and (min-width: 1536px) {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export class MenuComponent implements OnDestroy {
|
|||||||
this.query = ''
|
this.query = ''
|
||||||
this.categoryService.resetQuery()
|
this.categoryService.resetQuery()
|
||||||
this.categoryService.changeCategory(category)
|
this.categoryService.changeCategory(category)
|
||||||
|
this.categoryService.handleNavigation()
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueryChange(query: string): void {
|
onQueryChange(query: string): void {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
@media (min-width: 640px) {
|
||||||
width: 120%;
|
width: 108%;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class CategoriesComponent {
|
|||||||
case 'all':
|
case 'all':
|
||||||
return 'tuiIconGridLarge'
|
return 'tuiIconGridLarge'
|
||||||
case 'bitcoin':
|
case 'bitcoin':
|
||||||
return 'tuiIconBitcoin'
|
return 'assets/img/icons/logo-bitcoin.svg'
|
||||||
case 'messaging':
|
case 'messaging':
|
||||||
case 'communications':
|
case 'communications':
|
||||||
return 'tuiIconMessageCircleLarge'
|
return 'tuiIconMessageCircleLarge'
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
<div class="item-container box-shadow-lg">
|
<div
|
||||||
|
class="item-container box-shadow-lg"
|
||||||
|
*tuiLet="marketplace$ | async as marketplace"
|
||||||
|
>
|
||||||
<!-- color background -->
|
<!-- color background -->
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<img [src]="pkg.icon" alt="{{ pkg.manifest.title }} Icon" />
|
<img
|
||||||
|
[src]="determineIcon(marketplace)"
|
||||||
|
alt="{{ pkg.manifest.title }} Icon"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- darkening overlay -->
|
<!-- darkening overlay -->
|
||||||
<div class="overlay"></div>
|
<div class="overlay"></div>
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<img
|
<img
|
||||||
[src]="pkg.icon"
|
[src]="determineIcon(marketplace)"
|
||||||
class="icon box-shadow-lg"
|
class="icon"
|
||||||
alt="{{ pkg.manifest.title }} Icon"
|
alt="{{ pkg.manifest.title }} Icon"
|
||||||
/>
|
/>
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
.item-container {
|
.item-container {
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 300px;
|
|
||||||
border-radius: 1.5rem;
|
border-radius: 1.5rem;
|
||||||
padding: 5rem 2rem 2rem 2.5rem;
|
padding: 5rem 2rem 2rem 2.5rem;
|
||||||
gap: 1rem;
|
|
||||||
transition-property: transform;
|
transition-property: transform;
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
transition-duration: 500ms;
|
transition-duration: 500ms;
|
||||||
@@ -56,8 +53,6 @@
|
|||||||
top: -2.5rem;
|
top: -2.5rem;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
backdrop-filter: blur(24px);
|
|
||||||
background-color: rgb(0 0 0 / 0.5);
|
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +66,7 @@
|
|||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
will-change: transform, text-indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-description {
|
&-description {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
import {
|
||||||
import { MarketplacePkg } from '../../../types'
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
inject,
|
||||||
|
} from '@angular/core'
|
||||||
|
import { MarketplacePkg, StoreIdentity } from '../../../types'
|
||||||
|
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-item',
|
selector: 'marketplace-item',
|
||||||
@@ -10,4 +16,16 @@ import { MarketplacePkg } from '../../../types'
|
|||||||
export class ItemComponent {
|
export class ItemComponent {
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
pkg!: MarketplacePkg
|
pkg!: MarketplacePkg
|
||||||
|
|
||||||
|
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||||
|
readonly marketplace$ = this.marketplaceService.getSelectedHost$()
|
||||||
|
|
||||||
|
determineIcon(marketplace: StoreIdentity | null): string {
|
||||||
|
try {
|
||||||
|
const iconUrl = new URL(this.pkg.icon)
|
||||||
|
return iconUrl.href
|
||||||
|
} catch (e) {
|
||||||
|
return `${marketplace?.url}package/v0/icon/${this.pkg.manifest.id}`
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,17 @@ import { NgModule } from '@angular/core'
|
|||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { SharedPipesModule, TickerModule } from '@start9labs/shared'
|
import { SharedPipesModule, TickerModule } from '@start9labs/shared'
|
||||||
import { ItemComponent } from './item.component'
|
import { ItemComponent } from './item.component'
|
||||||
|
import { TuiLetModule } from '@taiga-ui/cdk'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [ItemComponent],
|
declarations: [ItemComponent],
|
||||||
exports: [ItemComponent],
|
exports: [ItemComponent],
|
||||||
imports: [CommonModule, RouterModule, SharedPipesModule, TickerModule],
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule,
|
||||||
|
SharedPipesModule,
|
||||||
|
TickerModule,
|
||||||
|
TuiLetModule,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class ItemModule {}
|
export class ItemModule {}
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
import { CommonModule, KeyValue } from '@angular/common'
|
import { CommonModule, KeyValue } from '@angular/common'
|
||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
inject,
|
||||||
|
} from '@angular/core'
|
||||||
import { EmverPipesModule } from '@start9labs/shared'
|
import { EmverPipesModule } from '@start9labs/shared'
|
||||||
import { Dependency, MarketplacePkg } from '../../../types'
|
import { Dependency, MarketplacePkg, StoreIdentity } from '../../../types'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { TuiAvatarModule, TuiLineClampModule } from '@taiga-ui/kit'
|
import { TuiAvatarModule, TuiLineClampModule } from '@taiga-ui/kit'
|
||||||
|
import { TuiLetModule } from '@taiga-ui/cdk'
|
||||||
|
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-dep-item',
|
selector: 'marketplace-dep-item',
|
||||||
template: `
|
template: `
|
||||||
<div class="outer-container">
|
<div class="outer-container" *tuiLet="marketplace$ | async as marketplace">
|
||||||
<tui-avatar
|
<tui-avatar
|
||||||
class="dep-img"
|
class="dep-img"
|
||||||
[rounded]="true"
|
[rounded]="true"
|
||||||
[size]="'l'"
|
[size]="'l'"
|
||||||
[avatarUrl]="getImage(dep.key)"
|
[avatarUrl]="getImage(dep.key, marketplace)"
|
||||||
></tui-avatar>
|
></tui-avatar>
|
||||||
<div>
|
<div>
|
||||||
<tui-line-clamp
|
<tui-line-clamp
|
||||||
@@ -103,6 +110,7 @@ import { TuiAvatarModule, TuiLineClampModule } from '@taiga-ui/kit'
|
|||||||
TuiAvatarModule,
|
TuiAvatarModule,
|
||||||
EmverPipesModule,
|
EmverPipesModule,
|
||||||
TuiLineClampModule,
|
TuiLineClampModule,
|
||||||
|
TuiLetModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class MarketplaceDepItemComponent {
|
export class MarketplaceDepItemComponent {
|
||||||
@@ -112,11 +120,22 @@ export class MarketplaceDepItemComponent {
|
|||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
dep!: KeyValue<string, Dependency>
|
dep!: KeyValue<string, Dependency>
|
||||||
|
|
||||||
getImage(key: string): string {
|
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||||
|
readonly marketplace$ = this.marketplaceService.getSelectedHost$()
|
||||||
|
|
||||||
|
getImage(key: string, marketplace: StoreIdentity | null) {
|
||||||
const icon = this.pkg.dependencyMetadata[key]?.icon
|
const icon = this.pkg.dependencyMetadata[key]?.icon
|
||||||
// @TODO fix when registry api is updated to include mimetype in icon url
|
|
||||||
// return icon ? `data:image/png;base64,${icon}` : key.substring(0, 2)
|
if (icon) {
|
||||||
return icon ? icon : key.substring(0, 2)
|
try {
|
||||||
|
const iconUrl = new URL(icon)
|
||||||
|
return iconUrl.href
|
||||||
|
} catch (e) {
|
||||||
|
return `${marketplace?.url}package/v0/icon/${key}`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return key.substring(0, 2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitle(key: string): string {
|
getTitle(key: string): string {
|
||||||
|
|||||||
@@ -1,23 +1,30 @@
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
inject,
|
||||||
|
} from '@angular/core'
|
||||||
import { SharedPipesModule, TickerModule } from '@start9labs/shared'
|
import { SharedPipesModule, TickerModule } from '@start9labs/shared'
|
||||||
import { MarketplacePkg } from '../../../types'
|
import { MarketplacePkg, StoreIdentity } from '../../../types'
|
||||||
|
import { TuiLetModule } from '@taiga-ui/cdk'
|
||||||
|
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-package-hero',
|
selector: 'marketplace-package-hero',
|
||||||
template: `
|
template: `
|
||||||
<div class="outer-container">
|
<div class="outer-container" *tuiLet="marketplace$ | async as marketplace">
|
||||||
<div class="inner-container box-shadow-lg">
|
<div class="inner-container box-shadow-lg">
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<img
|
<img
|
||||||
[src]="pkg.icon | trustUrl"
|
[src]="determineIcon(marketplace) | trustUrl"
|
||||||
class="box-shadow-lg"
|
class="box-shadow-lg"
|
||||||
alt="{{ pkg.manifest.title }} Icon"
|
alt="{{ pkg.manifest.title }} Icon"
|
||||||
/>
|
/>
|
||||||
<!-- color background -->
|
<!-- color background -->
|
||||||
<div class="color-background">
|
<div class="color-background">
|
||||||
<img
|
<img
|
||||||
[src]="pkg.icon | trustUrl"
|
[src]="determineIcon(marketplace) | trustUrl"
|
||||||
alt="{{ pkg.manifest.title }} background image"
|
alt="{{ pkg.manifest.title }} background image"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,11 +68,11 @@ import { MarketplacePkg } from '../../../types'
|
|||||||
padding: 4rem 2rem 0 2rem;
|
padding: 4rem 2rem 0 2rem;
|
||||||
|
|
||||||
@media (min-width: 376px) {
|
@media (min-width: 376px) {
|
||||||
min-height: 26vh;
|
min-height: 20vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
min-height: 14rem;
|
min-height: 11rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -157,9 +164,21 @@ import { MarketplacePkg } from '../../../types'
|
|||||||
],
|
],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, SharedPipesModule, TickerModule],
|
imports: [CommonModule, SharedPipesModule, TickerModule, TuiLetModule],
|
||||||
})
|
})
|
||||||
export class MarketplacePackageHeroComponent {
|
export class MarketplacePackageHeroComponent {
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
pkg!: MarketplacePkg
|
pkg!: MarketplacePkg
|
||||||
|
|
||||||
|
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||||
|
readonly marketplace$ = this.marketplaceService.getSelectedHost$()
|
||||||
|
|
||||||
|
determineIcon(marketplace: StoreIdentity | null) {
|
||||||
|
try {
|
||||||
|
const iconUrl = new URL(this.pkg.icon)
|
||||||
|
return iconUrl.href
|
||||||
|
} catch (e) {
|
||||||
|
return `${marketplace?.url}package/v0/icon/${this.pkg.manifest.id}`
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ export abstract class AbstractCategoryService {
|
|||||||
abstract getQuery$(): Observable<string>
|
abstract getQuery$(): Observable<string>
|
||||||
|
|
||||||
abstract resetQuery(): void
|
abstract resetQuery(): void
|
||||||
|
|
||||||
|
abstract handleNavigation(): void
|
||||||
}
|
}
|
||||||
|
|||||||
1
web/projects/shared/assets/img/icons/logo-bitcoin.svg
Normal file
1
web/projects/shared/assets/img/icons/logo-bitcoin.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M410.47 279.2c-5-11.5-12.7-21.6-28.1-30.1a98.15 98.15 0 00-25.4-10 62.22 62.22 0 0016.3-11 56.37 56.37 0 0015.6-23.3 77.11 77.11 0 003.5-28.2c-1.1-16.8-4.4-33.1-13.2-44.8s-21.2-20.7-37.6-27c-12.6-4.8-25.5-7.8-45.5-8.9V32h-40v64h-32V32h-41v64H96v48h27.87c8.7 0 14.6.8 17.6 2.3a13.22 13.22 0 016.5 6c1.3 2.5 1.9 8.4 1.9 17.5V343c0 9-.6 14.8-1.9 17.4s-2 4.9-5.1 6.3-3.2 1.3-11.8 1.3h-26.4L96 416h87v64h41v-64h32v64h40v-64.4c26-1.3 44.5-4.7 59.4-10.3 19.3-7.2 34.1-17.7 44.7-31.5s14-34.9 14.93-51.2c.67-14.5-.03-33.2-4.56-43.4zM224 150h32v74h-32zm0 212v-90h32v90zm72-208.1c6 2.5 9.9 7.5 13.8 12.7 4.3 5.7 6.5 13.3 6.5 21.4 0 7.8-2.9 14.5-7.5 20.5-3.8 4.9-6.8 8.3-12.8 11.1zm28.8 186.7c-7.8 6.9-12.3 10.1-22.1 13.8a56.06 56.06 0 01-6.7 1.9v-82.8a40.74 40.74 0 0111.3 3.4c7.8 3.3 15.2 6.9 19.8 13.2a43.82 43.82 0 018 24.7c-.03 10.9-2.83 19.2-10.33 25.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 943 B |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@start9labs/shared",
|
"name": "@start9labs/shared",
|
||||||
"version": "0.3.12",
|
"version": "0.3.13",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/common": "^17.0.6",
|
"@angular/common": "^17.0.6",
|
||||||
"@angular/core": "^17.0.6",
|
"@angular/core": "^17.0.6",
|
||||||
|
|||||||
@@ -101,8 +101,7 @@ import { TuiScrollbarModule } from '@taiga-ui/core'
|
|||||||
&-list {
|
&-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
gap: 4rem;
|
gap: 4rem 3rem;
|
||||||
list-style-type: none;
|
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
@@ -111,9 +110,12 @@ import { TuiScrollbarModule } from '@taiga-ui/core'
|
|||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
@media (min-width: 1536px) {
|
@media (min-width: 1280px) {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
@media (min-width: 1536px) {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.tile-wrapper {
|
.tile-wrapper {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ import { Router } from '@angular/router'
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
place-self: center;
|
place-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
marketplace-additional {
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
],
|
],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable, inject } from '@angular/core'
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import { AbstractCategoryService } from '@start9labs/marketplace'
|
import { AbstractCategoryService } from '@start9labs/marketplace'
|
||||||
|
import { Router } from '@angular/router'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CategoryService extends AbstractCategoryService {
|
export class CategoryService extends AbstractCategoryService {
|
||||||
|
private readonly router = inject(Router)
|
||||||
|
|
||||||
getCategory$(): Observable<string> {
|
getCategory$(): Observable<string> {
|
||||||
return this.category$
|
return this.category$
|
||||||
}
|
}
|
||||||
@@ -23,4 +26,8 @@ export class CategoryService extends AbstractCategoryService {
|
|||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.query$.next('')
|
this.query$.next('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleNavigation() {
|
||||||
|
this.router.navigate([])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-variable": true,
|
|
||||||
"no-unused-expression": true,
|
"no-unused-expression": true,
|
||||||
"semicolon": [true, "never"],
|
"semicolon": [true, "never"],
|
||||||
"no-trailing-whitespace": true,
|
"no-trailing-whitespace": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user