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:
Lucy
2023-12-08 15:12:38 -05:00
committed by GitHub
parent ad13b5eb4e
commit 0469aab433
115 changed files with 6434 additions and 5051 deletions

View 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>

View File

@@ -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 {}

View File

@@ -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()
}
}

View File

@@ -1,5 +1,6 @@
<img
*ngIf="icon; else noIcon"
class="rounded-full"
[style.max-width]="size || '100%'"
[src]="icon"
alt="Service Icon"