mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Feature/marketplace redesign (#2395)
* wip * update marketplace categories styling * update logo icons * add sort pipe * update search component styling * clean up categories component * cleanup and remove unnecessary sort pipe * query packages in selected category * fix search styling * add reg icon and font, adjust category styles * fix build from rebasing integration/refactors * adjust marketplace types for icon with store data, plus formatting * formatting * update categories and search * hover styling for categories * category styling * refactor for category as a behavior subject * more category styling * base functionality with new marketplace components * styling cleanup * misc style fixes and fix category selection from package page * fixes from review feedback * add and style additional details * implement release notes modal * fix menu when on service show page mobile to display change marketplace * style and responsiveness fixes * rename header to sidebar * input icon config to sidebar * add mime type pipe and type fn * review feedback fixes * skeleton text, more abstraction * reorder categories, clean up a little * audit sidebar, categories, store-icon, marketplace-sidebar, search * finish code cleanup and fix few bugs * misc fixes and cleanup * fix broken styles and markdown * bump shared marketplace version * more cleanup * sync package lock * rename sidebar component to menu * wip preview sidebar * sync package lock * breakout package show elements into components * link to brochure in preview; custom taiga button styles * move marketplace preview component into ui; open preview when viewing service in marketplace * sync changes post file struture rename * further cleanup * create service for sidebar toggle and cleanup marketplace components * bump shared marketplace version * bump shared for new images needed for brochure marketplace * cleanup --------- Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
145
web/projects/marketplace/src/components/menu/menu.component.html
Normal file
145
web/projects/marketplace/src/components/menu/menu.component.html
Normal file
@@ -0,0 +1,145 @@
|
||||
<header
|
||||
class="z-50 overflow-hidden w-full fixed sm:w-[34vw] md:w-[28vw] lg:w-[22vw] 2xl:w-[280px] sm:bg-zinc-700/90 sm:backdrop-blur-2xl sm:min-h-screen overflow-y-auto flex flex-col sm:py-6 sm:after:block sm:after:absolute sm:after:top-0 sm:after:bottom-0 sm:after:right-0 sm:after:w-0.5 after:h-[calc(100vh - 20px)] sm:after:bg-gradient-to-b from-zinc-700 to-zinc-400"
|
||||
>
|
||||
<ng-container *tuiLet="store$ | async as store">
|
||||
<div class="hidden sm:flex flex-col mx-6 pb-3 items-center">
|
||||
<div
|
||||
class="mb-3 rounded-full"
|
||||
[class.tui-skeleton]="!store"
|
||||
[class.tui-skeleton_rounded]="!store"
|
||||
>
|
||||
<store-icon
|
||||
size="64px"
|
||||
[url]="store?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
></store-icon>
|
||||
</div>
|
||||
<h1
|
||||
class="font-semibold text-2xl text-zinc-100 text-center mb-3"
|
||||
[class.tui-skeleton]="!store"
|
||||
>
|
||||
{{ store?.info?.name || 'Loading store' }}
|
||||
</h1>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=desktop]"></ng-content>
|
||||
</div>
|
||||
<!-- mobile nav -->
|
||||
<div class="sm:hidden bg-zinc-700/90 backdrop-blur-3xl">
|
||||
<div class="flex justify-between items-center py-4 px-4 w-[100vw]">
|
||||
<!-- mobile search -->
|
||||
<marketplace-search
|
||||
class="max-w-fit"
|
||||
[(query)]="query"
|
||||
(queryChange)="onQueryChange($event)"
|
||||
></marketplace-search>
|
||||
<button
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="flat"
|
||||
[pseudoActive]="false"
|
||||
(click)="toggleMenu(true)"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
[style.--tui-padding]="'1rem'"
|
||||
>
|
||||
<store-icon
|
||||
size="48px"
|
||||
[url]="store?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
class="rounded-full"
|
||||
[class.tui-skeleton]="!store"
|
||||
[class.tui-skeleton_rounded]="!store"
|
||||
></store-icon>
|
||||
<nav
|
||||
*tuiSidebar="open; direction: 'right'; autoWidth: true"
|
||||
class="bg-zinc-700/90 h-screen w-[70vw]"
|
||||
>
|
||||
<div class="flex flex-col divide-y divide-zinc-500 h-full">
|
||||
<div class="flex items-center p-4">
|
||||
<h1
|
||||
class="font-semibold text-xl text-zinc-200 flex-grow"
|
||||
[class.tui-skeleton]="!store"
|
||||
>
|
||||
{{ store?.info?.name }}
|
||||
</h1>
|
||||
<button
|
||||
[style.--tui-padding]="0"
|
||||
class="place-self-end"
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="icon"
|
||||
icon="tuiIconClose"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
(click)="toggleMenu(false)"
|
||||
></button>
|
||||
</div>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=mobile]"></ng-content>
|
||||
<div
|
||||
class="flex flex-col justify-between divide-y divide-zinc-500 h-full"
|
||||
>
|
||||
<marketplace-categories
|
||||
[categories]="store?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event); toggleMenu(false)"
|
||||
class="grow pt-5 pl-5 pr-5"
|
||||
></marketplace-categories>
|
||||
<a
|
||||
class="flex relative gap-2 hover:no-underline p-5"
|
||||
target="_blank"
|
||||
href="https://github.com/Start9Labs/service-pipeline#readme"
|
||||
>
|
||||
<img
|
||||
alt="Launch icon"
|
||||
width="24"
|
||||
height="24"
|
||||
class="opacity-70 invert"
|
||||
src="svg/rocket-outline.svg"
|
||||
/>
|
||||
<span
|
||||
class="text-base text-zinc-50 text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
Launch your project
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- desktop nav -->
|
||||
<nav class="hidden sm:flex grow flex-col py-3 px-4">
|
||||
<!-- desktop search -->
|
||||
<marketplace-search
|
||||
class="place-self-center md:pb-8"
|
||||
[query]="query"
|
||||
(queryChange)="onQueryChange($event)"
|
||||
></marketplace-search>
|
||||
<div class="flex grow flex-col justify-between">
|
||||
<marketplace-categories
|
||||
[categories]="store?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event)"
|
||||
></marketplace-categories>
|
||||
<a
|
||||
class="flex gap-2 p-2 hover:no-underline sm:hover:bg-[#222428] hover:cursor-pointer sm:w-[120%] z-50 rounded-l-lg ease-in-out delay-75 duration-300"
|
||||
target="_blank"
|
||||
href="https://github.com/Start9Labs/service-pipeline#readme"
|
||||
>
|
||||
<img
|
||||
alt="Rocket Icon"
|
||||
width="24"
|
||||
height="24"
|
||||
class="opacity-70 invert"
|
||||
src="svg/rocket-outline.svg"
|
||||
/>
|
||||
<span
|
||||
class="text-base text-zinc-50 text-ellipsis overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
Launch your project
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</ng-container>
|
||||
</header>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { NgModule } from '@angular/core'
|
||||
import { SharedPipesModule } from '@start9labs/shared'
|
||||
|
||||
import { MenuComponent } from './menu.component'
|
||||
import { TuiButtonModule, TuiLoaderModule } from '@taiga-ui/core'
|
||||
import { TuiActiveZoneModule, TuiLetModule } from '@taiga-ui/cdk'
|
||||
import { TuiSidebarModule } from '@taiga-ui/addon-mobile'
|
||||
import { SearchModule } from '../../pages/list/search/search.module'
|
||||
import { CategoriesModule } from '../../pages/list/categories/categories.module'
|
||||
import { StoreIconComponentModule } from '../store-icon/store-icon.component.module'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedPipesModule,
|
||||
SearchModule,
|
||||
CategoriesModule,
|
||||
TuiActiveZoneModule,
|
||||
TuiSidebarModule,
|
||||
TuiLoaderModule,
|
||||
TuiButtonModule,
|
||||
CategoriesModule,
|
||||
StoreIconComponentModule,
|
||||
TuiLetModule,
|
||||
],
|
||||
declarations: [MenuComponent],
|
||||
exports: [MenuComponent],
|
||||
})
|
||||
export class MenuModule {}
|
||||
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
} from '@angular/core'
|
||||
import { combineLatest, map, Subject, takeUntil } from 'rxjs'
|
||||
import { StoreIdentity } from '../../types'
|
||||
import { AbstractMarketplaceService } from '../../services/marketplace.service'
|
||||
import { AbstractCategoryService } from '../../services/category.service'
|
||||
import { Router } from '@angular/router'
|
||||
import { MarketplaceConfig } from '@start9labs/shared'
|
||||
|
||||
@Component({
|
||||
selector: 'menu',
|
||||
templateUrl: './menu.component.html',
|
||||
styleUrls: ['./menu.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MenuComponent implements OnDestroy {
|
||||
@Input({ required: true })
|
||||
iconConfig!: MarketplaceConfig
|
||||
|
||||
constructor(private readonly router: Router) {}
|
||||
|
||||
private destroy$ = new Subject<void>()
|
||||
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||
private readonly categoryService = inject(AbstractCategoryService)
|
||||
readonly store$ = this.marketplaceService.getSelectedStoreWithCategories$()
|
||||
readonly alt$ = combineLatest([
|
||||
this.marketplaceService.getKnownHosts$(),
|
||||
this.marketplaceService.getSelectedHost$(),
|
||||
]).pipe(
|
||||
map(([stores, selected]) =>
|
||||
stores.filter(({ url }) => url != selected.url),
|
||||
),
|
||||
)
|
||||
private hosts?: StoreIdentity[]
|
||||
category = ''
|
||||
query = ''
|
||||
open = false
|
||||
|
||||
ngOnInit() {
|
||||
this.categoryService
|
||||
.getQuery$()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(val => {
|
||||
this.query = val
|
||||
})
|
||||
|
||||
this.categoryService
|
||||
.getCategory$()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(val => {
|
||||
this.category = val
|
||||
})
|
||||
|
||||
this.marketplaceService
|
||||
.getKnownHosts$()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(hosts => {
|
||||
this.hosts = hosts
|
||||
})
|
||||
}
|
||||
|
||||
onCategoryChange(category: string): void {
|
||||
this.category = category
|
||||
this.query = ''
|
||||
this.categoryService.resetQuery()
|
||||
this.categoryService.changeCategory(category)
|
||||
this.router.navigate(['/marketplace'], { replaceUrl: true })
|
||||
}
|
||||
|
||||
onQueryChange(query: string): void {
|
||||
this.query = query
|
||||
this.categoryService.setQuery(query)
|
||||
this.router.navigate(['/marketplace'], { replaceUrl: true })
|
||||
}
|
||||
|
||||
toggleMenu(open: boolean): void {
|
||||
this.open = open
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next()
|
||||
this.destroy$.complete()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<img
|
||||
*ngIf="icon; else noIcon"
|
||||
class="rounded-full"
|
||||
[style.max-width]="size || '100%'"
|
||||
[src]="icon"
|
||||
alt="Service Icon"
|
||||
|
||||
Reference in New Issue
Block a user