Update/marketplace (#2575)

* make category link generic

* fix ai category display and svg icons

* fix markdown display and ansi module; cleanup

* convert tailwindcss to scss in marketplace menu component

* convert tailwindcss to scss in marketplace categories component

* convert tailwindcss to scss in marketplace item component

* update launch icon to taiga icon

* convert tailwindcss to scss in marketplace search component + cleanup

* convert tailwindcss to scss in marketplace release notes component + cleanup

* convert tailwindcss to scss in marketplace about component + cleanup

* convert tailwindcss to scss in marketplace additional component

* convert tailwindcss to scss in marketplace dependencies component + misc style fixes

* convert tailwindcss to scss in marketplace hero component + misc style fixes

* convert tailwindcss to scss in marketplace screenshots component

* convert tailwindcss to scss in portal marketplace components

* remove the rest of tailwindscss and fix reset styles

* bump shared and marketplace package versions

* misc style + build fixes

* sync package lock

* fix markdown + cleanup

* fix markdown margins and git hash size

* fix mobile zindex for hero and mobile changing categories routing link
This commit is contained in:
Lucy
2024-03-21 14:23:28 -04:00
committed by GitHub
parent 5e6a7e134f
commit 2021431e2f
48 changed files with 1606 additions and 839 deletions

View File

@@ -1,34 +1,24 @@
<header
class="header 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"
>
<header>
<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"
<div class="title">
<store-icon
[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"
>
size="64px"
[url]="store?.url || ''"
[marketplace]="iconConfig"
></store-icon>
<h1 [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]">
<div class="nav-mobile">
<div class="nav-mobile-bar">
<!-- mobile search -->
<marketplace-search
class="max-w-fit"
[(query)]="query"
(queryChange)="onQueryChange($event)"
></marketplace-search>
@@ -43,101 +33,78 @@
>
<store-icon
size="48px"
[style.height]="'48px'"
[style.border-radius]="'100%'"
[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]"
class="nav-mobile-sidebar divide-bar"
>
<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"
<div class="nav-mobile-sidebar-top">
<h1 [class.tui-skeleton]="!store">
{{ store?.info?.name }}
</h1>
<button
[style.--tui-padding]="0"
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="nav-mobile-sidebar-bottom divide-bar">
<marketplace-categories
[categories]="store?.info?.categories"
[category]="query ? '' : category"
(categoryChange)="onCategoryChange($event); toggleMenu(false)"
></marketplace-categories>
<a
target="_blank"
href="https://github.com/Start9Labs/service-pipeline#readme"
>
<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>
<!-- @TODO need rocket icon -->
<tui-icon
tuiAppearance="icon"
icon="tuiIconExternalLinkLarge"
></tui-icon>
<span>Launch your project</span>
</a>
</div>
</nav>
</button>
</div>
</div>
<!-- desktop nav -->
<nav class="hidden sm:flex grow flex-col py-3 px-4">
<nav class="nav-desktop">
<!-- 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">
<div class="nav-desktop-container">
<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>
<!-- @TODO need rocket icon -->
<tui-icon
tuiAppearance="icon"
icon="tuiIconExternalLinkLarge"
></tui-icon>
<span>Launch your project</span>
</a>
</div>
</nav>

View File

@@ -9,6 +9,7 @@ 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'
import { TuiAppearanceModule, TuiIconModule } from '@taiga-ui/experimental'
@NgModule({
imports: [
@@ -23,6 +24,8 @@ import { StoreIconComponentModule } from '../store-icon/store-icon.component.mod
CategoriesModule,
StoreIconComponentModule,
TuiLetModule,
TuiAppearanceModule,
TuiIconModule,
],
declarations: [MenuComponent],
exports: [MenuComponent],

View File

@@ -1,13 +1,229 @@
@import '@taiga-ui/core/styles/taiga-ui-local';
.header {
header {
@include scrollbar-hidden();
max-height: 100%;
// TODO: Theme
background: #373a3f;
overflow: hidden;
width: 100%;
position: fixed;
overflow-y: auto;
display: flex;
flex-direction: column;
z-index: 10;
@media screen and (min-width: 640px) {
width: 15rem;
background-color: rgb(var(--tw-color-zinc-700) / 0.9);
backdrop-filter: blur(40px);
min-height: calc(100vh - var(--portal-header-height));
padding: 1.5rem 0;
&::after {
display: block;
position: absolute;
top: 0px;
bottom: 0px;
right: 0px;
width: 0.125rem;
content: '';
background-image: linear-gradient(
to bottom,
rgb(var(--tw-color-zinc-700)),
rgb(var(--tw-color-zinc-400))
);
}
}
}
.title {
display: none;
@media (min-width: 640px) {
display: flex;
flex-direction: column;
align-items: center;
margin-left: 1.5rem;
margin-right: 1.5rem;
padding-bottom: 0.75rem;
}
store-icon {
margin-bottom: 0.75rem;
border-radius: 100%;
height: 64px;
}
h1 {
font-weight: 600;
font-size: 1.5rem;
line-height: 2rem;
color: rgb(244 244 245);
text-align: center;
margin-bottom: 0.75rem;
}
}
.nav {
&-desktop {
display: none;
padding: 0.75rem 1rem;
marketplace-search {
place-self: center;
padding-bottom: 2rem;
}
@media (min-width: 640px) {
display: flex;
flex-grow: 1;
flex-direction: column;
}
&-container {
display: flex;
flex-grow: 1;
flex-direction: column;
justify-content: space-between;
a {
display: flex;
gap: 0.5rem;
padding: 0.5rem;
z-index: 50;
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: 75ms;
transition-duration: 300ms;
&:hover {
text-decoration-line: none;
cursor: pointer;
}
img {
opacity: 0.7;
filter: invert(100%);
}
span {
font-size: 1rem;
line-height: 1.5rem;
color: rgb(250 250 250);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
@media (min-width: 640px) {
width: 120%;
&:hover {
background-color: rgb(34 36 40);
}
}
}
}
}
&-mobile {
@media (min-width: 640px) {
display: none;
}
&-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
width: 100vw;
marketplace-search {
max-width: fit-content;
}
}
&-sidebar {
background-color: rgb(var(--tw-color-zinc-700) / 0.9);
height: calc(100vh - var(--portal-header-height));
width: 70vw;
display: flex;
flex-direction: column;
height: 100%;
&-top {
display: flex;
align-items: center;
padding: 1rem;
border-bottom: 1px solid rgb(113 113 122);
h1 {
font-weight: 600;
font-size: 1.25rem;
line-height: 1.75rem;
color: rgb(228 228 231);
flex-grow: 1;
}
button {
place-self: end;
}
}
&-bottom {
display: flex;
flex-direction: column;
justify-content: space-between;
border-top: 1px solid rgb(113 113 122);
height: 100%;
marketplace-categories {
flex-grow: 1;
padding: 1.25rem 1.25rem 0px 1.25rem;
}
a {
display: flex;
position: relative;
gap: 0.5rem;
padding: 1.25rem;
&:hover {
text-decoration-line: none;
}
img {
opacity: 0.7;
filter: invert(100%);
}
span {
font-size: 1rem;
line-height: 1.5rem;
color: rgb(250 250 250);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
.divide-bar > * + * {
border-top-width: 1px;
border-bottom-width: 0px;
border-color: rgb(113 113 122);
}
}
}
}
*,
::before,
::after {
box-sizing: border-box;
border-width: 0;
border-style: solid;
border-color: rgb(var(--tw-color-gray-200) / 1);
}

View File

@@ -1,28 +1,25 @@
<button
*ngFor="let cat of categories || ['', '', '', '', '', '']"
class="flex relative gap-2 hover:no-underline hover:cursor-pointer sm:hover:bg-[#222428] sm:hover:opacity-90 sm:w-[120%] rounded-l-lg ease-in-out delay-75 duration-300 mb-5 sm:p-2 sm:mb-3 z-50"
routerLink="/marketplace"
routerLink="../"
(click)="switchCategory(cat)"
[class.category_selected]="cat === category"
>
<div
class="relative flex"
class="category-wrapper"
[class.tui-skeleton]="!categories"
[class.tui-skeleton_rounded]="!categories"
>
<img
alt="Category Icon"
width="24"
height="24"
class="opacity-70 invert"
src="/svg/{{ determineIcon(cat) }}.svg"
/>
<tui-icon tuiAppearance="icon" icon="{{ determineIcon(cat) }}"></tui-icon>
</div>
<span
class="text-base text-zinc-50 text-ellipsis overflow-hidden whitespace-nowrap"
class="category-title"
[class.tui-skeleton]="!categories"
[class.tui-skeleton_rounded]="!categories"
>
{{ (cat | titlecase) || 'loading category...' }}
{{
cat === 'ai'
? (cat | uppercase)
: (cat | titlecase) || 'loading category...'
}}
</span>
</button>

View File

@@ -9,4 +9,49 @@
background-color: #222428;
opacity: 90;
}
}
}
button {
display: flex;
position: relative;
gap: 0.5rem;
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: 75ms;
transition-duration: 300ms;
margin-bottom: 1.25rem;
z-index: 50;
&:hover {
text-decoration-line: none;
cursor: pointer;
}
@media (min-width: 640px) {
width: 120%;
padding: 0.5rem;
margin-bottom: 0.75rem;
&:hover {
background-color: rgb(34 36 40);
opacity: 0.9;
}
}
}
.category {
&-wrapper {
position: relative;
display: flex;
}
&-title {
font-size: 1rem;
line-height: 1.5rem;
color: rgb(250 250 250);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}

View File

@@ -30,27 +30,31 @@ export class CategoriesComponent {
determineIcon(category: string): string {
switch (category.toLowerCase()) {
case 'all':
return 'apps-outline'
return 'tuiIconGridLarge'
case 'bitcoin':
return 'logo-bitcoin'
// @TODO need bitcoin icon
return 'tuiIconBoldLarge'
case 'messaging':
case 'communications':
return 'chatbubbles-outline'
return 'tuiIconMessageCircleLarge'
case 'data':
return 'document-outline'
return 'tuiIconFileTextLarge'
case 'developer tools':
return 'code-slash-outline'
return 'tuiIconTableSplitLarge'
case 'featured':
return 'star-outline'
return 'tuiIconStarLarge'
case 'lightning':
return 'flash-outline'
return 'tuiIconZapLarge'
case 'media':
return 'play-outline'
return 'tuiIconPlayCircleLarge'
case 'networking':
return 'globe-outline'
return 'tuiIconGlobeLarge'
case 'social':
return 'people-outline'
return 'tuiIconUsersLarge'
case 'ai':
return 'tuiIconCpuLarge'
default:
return 'cube-outline'
return 'tuiIconBoxLarge'
}
}
}

View File

@@ -2,9 +2,11 @@ import { CommonModule } from '@angular/common'
import { NgModule } from '@angular/core'
import { CategoriesComponent } from './categories.component'
import { TuiAppearanceModule, TuiIconModule } from '@taiga-ui/experimental'
import { RouterModule } from '@angular/router'
@NgModule({
imports: [CommonModule],
imports: [RouterModule, CommonModule, TuiAppearanceModule, TuiIconModule],
declarations: [CategoriesComponent],
exports: [CategoriesComponent],
})

View File

@@ -1,32 +1,24 @@
<div
class="h-full relative rounded-3xl pt-20 pb-10 px-8 gap-4 shadow-lg hover:scale-90 transition duration-500 ease-in-out min-w-[300px]"
>
<div class="item-container box-shadow-lg">
<!-- color background -->
<div
class="overflow-hidden absolute w-full h-full top-0 left-0 -z-50 rounded-3xl bg-zinc-800"
>
<div class="background">
<img
[src]="'data:image/png;base64,' + pkg.icon | trustUrl"
class="absolute object-cover pointer-events-none w-[150%] h-[150%] max-w-[200%] blur-[100px]"
[src]="pkg | mimeType | trustUrl"
alt="{{ pkg.manifest.title }} Icon"
/>
</div>
<!-- darkening overlay -->
<div
class="overflow-hidden absolute w-full h-full top-0 left-0 -z-50 rounded-3xl bg-zinc-800 opacity-40"
></div>
<div class="overlay"></div>
<!-- icon -->
<img
[src]="'data:image/png;base64,' + pkg.icon | trustUrl"
class="w-[5.5rem] h-[5.5rem] pointer-events-none absolute -top-10 rounded-full object-cover shadow-lg z-10"
[src]="pkg | mimeType | trustUrl"
class="icon box-shadow-lg"
alt="{{ pkg.manifest.title }} Icon"
style="transform: none"
/>
<div class="mt-3 text-zinc-5 mix-blend-plus-lighter">
<span class="block text-2xl font-medium line-clamp-1 mb-1">
<div class="detail">
<span class="detail-title">
{{ pkg.manifest.title }}
</span>
<span class="block text-base h-12 line-clamp-2">
<span class="detail-description">
{{ pkg.manifest.description.short }}
</span>
</div>

View File

@@ -0,0 +1,91 @@
.item-container {
height: 100%;
position: relative;
min-width: 300px;
border-radius: 1.5rem;
padding: 5rem 2rem 2rem 2.5rem;
gap: 1rem;
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 500ms;
&:hover {
transform: scaleX(0.9) scaleY(0.9);
}
}
.background {
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
z-index: -50;
border-radius: 1.5rem;
background-color: rgb(39 39 42);
img {
position: absolute;
object-fit: cover;
pointer-events: none;
width: 150%;
height: 150%;
max-width: 200%;
filter: blur(100px);
}
}
.overlay {
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
border-radius: 1.5rem;
background-color: rgb(39 39 42);
opacity: 0.4;
}
.icon {
width: 5.5rem;
height: 5.5rem;
pointer-events: none;
position: absolute;
top: -2.5rem;
border-radius: 9999px;
object-fit: cover;
z-index: 10;
backdrop-filter: blur(24px);
background-color: rgb(0 0 0 / 0.5);
transform: none;
}
.detail {
margin-top: 0.75rem;
mix-blend-mode: plus-lighter;
&-title {
display: block;
font-size: 1.5rem;
line-height: 2rem;
margin-bottom: 0.25rem;
font-weight: 500;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
&-description {
display: block;
font-size: 1rem;
line-height: 1.5rem;
height: 3rem;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}

View File

@@ -4,6 +4,7 @@ import { MarketplacePkg } from '../../../types'
@Component({
selector: 'marketplace-item',
templateUrl: 'item.component.html',
styleUrls: ['item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ItemComponent {

View File

@@ -3,10 +3,11 @@ import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { SharedPipesModule } from '@start9labs/shared'
import { ItemComponent } from './item.component'
import { MimeTypePipeModule } from '../../../pipes/mime-type.pipe'
@NgModule({
declarations: [ItemComponent],
exports: [ItemComponent],
imports: [CommonModule, RouterModule, SharedPipesModule],
imports: [CommonModule, RouterModule, SharedPipesModule, MimeTypePipeModule],
})
export class ItemModule {}

View File

@@ -1,20 +1,11 @@
<div class="text-zinc-100 bg-zinc-500 px-3 rounded-full">
<div class="relative flex items-center">
<img
alt="Search icon"
width="24"
height="24"
class="invert"
src="svg/search.svg"
/>
<input
type="text"
name="search"
class="mt-1 bg-transparent placeholder-zinc-300 focus:outline-none px-3 py-2"
placeholder="Search..."
autocomplete="off"
[ngModel]="query"
(ngModelChange)="onModelChange($event)"
/>
</div>
<div class="search-box">
<tui-svg src="tuiIconSearchLarge"></tui-svg>
<input
type="text"
name="search"
placeholder="Search..."
autocomplete="off"
[ngModel]="query"
(ngModelChange)="onModelChange($event)"
/>
</div>

View File

@@ -0,0 +1,32 @@
.search-box {
color: rgb(244 244 245);
background-color: rgb(113 113 122);
padding-left: 0.75rem;
padding-right: 0.75rem;
border-radius: 9999px;
position: relative;
display: flex;
align-items: center;
input {
margin-top: 0.25rem;
background-color: transparent;
padding: 0.5rem 0.75rem;
&::placeholder {
color: rgb(212 212 216);
}
&:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
}
*,
::before,
::after {
box-sizing: border-box;
border-width: 0;
border-style: solid;
border-color: rgb(var(--tw-color-gray-200) / 1);
}
}

View File

@@ -2,9 +2,10 @@ import { CommonModule } from '@angular/common'
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { SearchComponent } from './search.component'
import { TuiSvgModule } from '@taiga-ui/core'
@NgModule({
imports: [FormsModule, CommonModule],
imports: [FormsModule, CommonModule, TuiSvgModule],
declarations: [SearchComponent],
exports: [SearchComponent],
})

View File

@@ -1,24 +1,21 @@
<div
class="rounded-xl bg-gradient-to-bl from-zinc-400/75 to-zinc-600 p-px shadow-lg shadow-zinc-400/10 mt-6"
>
<div class="bg-zinc-800 rounded-xl p-7 grid grid-flow-row items-center gap-6">
<div class="block">
<h3 class="text-lg font-bold small-caps">What's new</h3>
<p
*ngIf="pkg['published-at'] as published"
class="text-base font-light mb-1 text-zinc-300"
>
<div class="background-border box-shadow-lg shadow-color-light">
<div class="box-container">
<div class="box-container-title">
<h3 class="small-caps">What's new</h3>
<p *ngIf="pkg['published-at'] as published">
<span class="small-caps">Latest Release</span>
&nbsp;-&nbsp;
<span class="text-sm">{{ published | date: 'medium' }}</span>
<span class="box-container-title-date">
{{ published | date: 'medium' }}
</span>
</p>
</div>
<div class="flex flex-wrap justify-between gap-6">
<div class="text-base">
<div class="box-container-details">
<div class="box-container-details-version">
<p>Version {{ pkg.manifest.version }}</p>
<p
safeLinks
class="flex-wrap mt-1"
class="box-container-details-notes"
[innerHTML]="pkg.manifest['release-notes'] | markdown | dompurify"
></p>
</div>
@@ -27,7 +24,6 @@
type="button"
appearance="secondary"
size="m"
class="mt-3 place-self-end sm:place-self-start md:place-self-start lg:place-self-end"
(click)="showReleaseNotes(template)"
>
Previous releases
@@ -39,11 +35,12 @@
<ng-template #template let-observer>
<ng-container *ngIf="notes$ | async as notes; else loading">
<tui-accordion
class="max-w-lg"
class="max-width-lg"
style="max-width: 32rem"
[closeOthers]="false"
*ngFor="let note of notes | keyvalue: asIsOrder"
>
<tui-accordion-item class="my-1">
<tui-accordion-item style="margin: 0.25rem 0">
{{ note.key | displayEmver }}
<ng-template tuiAccordionItemContent>
<p safeLinks [innerHTML]="note.value | markdown | dompurify"></p>

View File

@@ -0,0 +1,66 @@
.box-container {
background-color: rgb(39 39 42);
border-radius: 0.75rem;
padding: 1.75rem;
display: grid;
grid-auto-flow: row;
align-items: center;
gap: 1.5rem;
&-title {
display: block;
h3 {
font-size: 1.125rem;
line-height: 1.75rem;
font-weight: 700;
}
p {
font-size: 1rem;
line-height: 1.5rem;
font-weight: 300;
margin-bottom: 0.25rem;
color: rgb(212 212 216);
}
&-date {
font-size: 0.875rem;
line-height: 1.25rem;
}
}
&-details {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 1.5rem;
&-version {
font-size: 1rem;
line-height: 1.5rem;
}
&-notes {
flex-wrap: wrap;
margin-top: 0.25rem;
}
button {
margin-top: 0.75rem;
place-self: end;
// @media (min-width: 640px) {
// place-self: start;
// }
@media (min-width: 768px) {
place-self: start;
}
@media (min-width: 1024px) {
place-self: end;
}
}
}
}

View File

@@ -1,18 +1,16 @@
<div
class="rounded-xl bg-gradient-to-bl from-zinc-400/75 to-zinc-600 p-px shadow-lg shadow-zinc-400/10"
>
<div class="lg:col-span-5 xl:col-span-4 bg-zinc-800 rounded-xl p-7">
<h2 class="text-lg font-bold small-caps pb-3">Description</h2>
<p class="text-base mb-3">
<div class="background-border box-shadow-lg shadow-color-light">
<div class="box-container">
<h2 class="additional-detail-title">Description</h2>
<p>
{{ pkg.manifest.description.long }}
</p>
<ng-container *ngIf="pkg.manifest.replaces as replaces">
<div *ngIf="replaces.length">
<h2 class="text-lg font-bold small-caps pb-3">Intended to replace</h2>
<h2 class="replaces">Intended to replace</h2>
<tui-tag
*ngFor="let app; index as i; of: replaces"
size="l"
[class]="i > 0 ? 'ml-1.5 mt-2' : 'mt-2'"
[class]="i > 0 ? 'tag-margin-full' : 'tag-margin-empty'"
[value]="app"
></tui-tag>
</div>

View File

@@ -0,0 +1,31 @@
.box-container {
background-color: rgb(39 39 42);
border-radius: 0.75rem;
padding: 1.75rem;
@media (min-width: 1024px) {
grid-column: span 5 / span 5;
}
@media (min-width: 1280px) {
grid-column: span 4 / span 4;
}
p {
font-size: 1rem;
line-height: 1.5rem;
margin-bottom: 0.75rem;
}
}
.tag-margin-full {
margin-left: 0.375rem;
margin-top: 0.5rem;
}
.tag-margin-empty {
margin-top: 0.5rem;
}
.replaces {
font-weight: 600;
}

View File

@@ -1,12 +1,8 @@
<a [href]="url" target="_blank" rel="noreferrer">
<div class="flex justify-between items-center">
<label [tuiLabel]="label" class="hover:cursor-pointer">
<div class="link-container">
<label [tuiLabel]="label">
<tui-line-clamp [content]="url" [linesLimit]="1"></tui-line-clamp>
</label>
<img
alt="Open Icon"
class="block opacity-70 invert w-4"
src="svg/open-outline.svg"
/>
<tui-svg src="tuiIconExternalLinkLarge"></tui-svg>
</div>
</a>

View File

@@ -1,11 +1,11 @@
import { CommonModule } from '@angular/common'
import { NgModule } from '@angular/core'
import { AdditionalLinkComponent } from './additional-link.component'
import { TuiLabelModule } from '@taiga-ui/core'
import { TuiLabelModule, TuiSvgModule } from '@taiga-ui/core'
import { TuiLineClampModule } from '@taiga-ui/kit'
@NgModule({
imports: [CommonModule, TuiLabelModule, TuiLineClampModule],
imports: [CommonModule, TuiLabelModule, TuiLineClampModule, TuiSvgModule],
declarations: [AdditionalLinkComponent],
exports: [AdditionalLinkComponent],
})

View File

@@ -0,0 +1,13 @@
.link-container {
display: flex;
justify-content: space-between;
align-items: center;
label:hover {
cursor: pointer;
}
tui-svg {
opacity: 0.7;
}
}

View File

@@ -1,127 +1,93 @@
<div
class="rounded-xl bg-gradient-to-bl from-zinc-400/75 to-zinc-600 p-px shadow-lg shadow-zinc-400/10"
>
<div class="bg-zinc-800 rounded-xl p-7">
<h2 class="text-lg font-bold small-caps pb-3">Information</h2>
<div class="grid grid-flow-row divide-y divide-zinc-500">
<div class="background-border shadow-color-light box-shadow-lg">
<div class="box-container">
<h2 class="additional-detail-title">Information</h2>
<div class="detail-container">
<!-- git hash -->
<div
*ngIf="pkg.manifest['git-hash'] as gitHash; else noHash"
button
detail="false"
class="py-3 px-1 flex flex-wrap justify-between items-center"
class="detail-container-item item-padding item-copy"
(click)="copyService.copy(gitHash)"
>
<label tuiLabel="Git Hash">{{ gitHash }}</label>
<img
alt="Copy Icon"
class="block opacity-70 invert w-4 hover:cursor-copy"
src="svg/copy-outline.svg"
/>
<label class="git-hash-label" tuiLabel="Git Hash">{{ gitHash }}</label>
<tui-svg src="tuiIconCopyLarge"></tui-svg>
</div>
<ng-template #noHash>
<div class="py-3 px-1">
<div class="item-padding">
<label tuiLabel="Git Hash">Unknown</label>
</div>
</ng-template>
<!-- license -->
<div
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="detail-container-item item-padding item-pointer"
(click)="presentModalMd('License')"
>
<div class="flex flex-wrap justify-between items-center">
<label tuiLabel="License" class="hover:cursor-pointer">
{{ pkg.manifest.license }}
</label>
<img
alt="Open Icon"
class="block opacity-70 invert w-4"
src="svg/chevron-forward.svg"
/>
</div>
<label tuiLabel="License">
{{ pkg.manifest.license }}
</label>
<tui-svg src="tuiIconChevronRightLarge"></tui-svg>
</div>
<!-- instructions -->
<div
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="detail-container-item item-padding item-pointer"
(click)="presentModalMd('Instructions')"
>
<div class="flex flex-wrap justify-between items-center">
<label tuiLabel="Instructions" class="hover:cursor-pointer">
Click to view instructions
</label>
<img
alt="Open Icon"
class="block opacity-70 invert w-4"
src="svg/chevron-forward.svg"
/>
</div>
<label tuiLabel="Instructions">Click to view instructions</label>
<tui-svg src="tuiIconChevronRightLarge"></tui-svg>
</div>
<!-- versions -->
<div
class="detail-container-item item-padding item-pointer"
(click)="presentAlertVersions(version)"
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
>
<div class="flex flex-wrap justify-between items-center">
<label tuiLabel="Other versions" class="hover:cursor-pointer">
Click to view other versions
</label>
<img
alt="Open Icon"
class="block opacity-70 invert w-4"
src="svg/chevron-forward.svg"
/>
</div>
<ng-template #version let-data="data" let-completeWith="completeWith">
<tui-radio-list
class="radio"
size="l"
[items]="data.items"
[itemContent]="displayEmver | tuiStringifyContent"
[(ngModel)]="data.value"
></tui-radio-list>
<footer class="buttons">
<button
tuiButton
appearance="secondary"
(click)="completeWith(null)"
>
Cancel
</button>
<button
tuiButton
appearance="secondary"
(click)="completeWith(data.value)"
>
Ok
</button>
</footer>
</ng-template>
<label tuiLabel="Other versions">Click to view other versions</label>
<tui-svg src="tuiIconChevronRightLarge"></tui-svg>
</div>
<ng-template #version let-data="data" let-completeWith="completeWith">
<tui-radio-list
size="l"
[items]="data.items"
[itemContent]="displayEmver | tuiStringifyContent"
[(ngModel)]="data.value"
></tui-radio-list>
<footer class="buttons">
<button tuiButton appearance="secondary" (click)="completeWith(null)">
Cancel
</button>
<button
tuiButton
appearance="secondary"
(click)="completeWith(data.value)"
>
Ok
</button>
</footer>
</ng-template>
<!-- links -->
<marketplace-additional-link
[url]="pkg.manifest['marketing-site']"
*ngIf="pkg.manifest['marketing-site']"
label="Marketing Site"
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="item-padding item-pointer"
></marketplace-additional-link>
<marketplace-additional-link
[url]="pkg.manifest['upstream-repo']"
*ngIf="pkg.manifest['upstream-repo']"
label="Source Repository"
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="item-padding item-pointer"
></marketplace-additional-link>
<marketplace-additional-link
[url]="pkg.manifest['wrapper-repo']"
*ngIf="pkg.manifest['wrapper-repo']"
label="Wrapper Repository"
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="item-padding item-pointer"
></marketplace-additional-link>
<marketplace-additional-link
[url]="pkg.manifest['support-site']"
*ngIf="pkg.manifest['support-site']"
label="Support Site"
class="py-3 px-1 hover:bg-zinc-500/10 hover:cursor-pointer"
class="item-padding item-pointer"
></marketplace-additional-link>
</div>
</div>

View File

@@ -0,0 +1,56 @@
.box-container {
background-color: rgb(39 39 42);
border-radius: 0.75rem;
padding: 1.75rem;
}
.detail-container {
display: grid;
grid-auto-flow: row;
& > * + * {
border-top-width: 1px;
border-bottom-width: 0px;
border-color: rgb(113 113 122);
}
&-item {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
}
.item {
&-padding {
padding: 0.75rem 0.25rem;
}
&-pointer:hover {
cursor: pointer;
background-color: rgb(113 113 122 / 0.1);
}
&-copy:hover {
cursor: copy;
background-color: rgb(113 113 122 / 0.1);
}
}
::ng-deep .t-text {
font-weight: 600;
}
*,
::before,
::after {
box-sizing: border-box;
border-width: 0;
border-style: solid;
border-color: rgb(var(--tw-color-gray-200) / 1);
}
.git-hash-label {
font-size: 0.73rem;
}

View File

@@ -6,7 +6,7 @@ import {
TuiStringifyContentPipeModule,
} from '@taiga-ui/kit'
import { FormsModule } from '@angular/forms'
import { TuiButtonModule, TuiLabelModule } from '@taiga-ui/core'
import { TuiButtonModule, TuiLabelModule, TuiSvgModule } from '@taiga-ui/core'
import { AdditionalLinkModule } from './additional-link/additional-link.component.module'
@NgModule({
@@ -18,6 +18,7 @@ import { AdditionalLinkModule } from './additional-link/additional-link.componen
TuiButtonModule,
TuiLabelModule,
AdditionalLinkModule,
TuiSvgModule,
],
declarations: [AdditionalComponent],
exports: [AdditionalComponent],

View File

@@ -1,14 +1,9 @@
<div
class="bg-zinc-700/40 rounded-xl py-3 px-5 gap-2 drop-shadow-lg hover:bg-zinc-700/70"
>
<div class="flex items-center gap-6">
<tui-avatar
class="w-16 pointer-events-none rounded-full object-cover drop-shadow-lg"
[src]="getImage(dep.key)"
></tui-avatar>
<div class="mt-3">
<div class="flex flex-wrap items-center gap-1 mb-1">
<span class="block text-base font-medium text-zinc-50/90 line-clamp-1">
<div class="outer-container">
<div class="inner-container">
<tui-avatar class="dep-img" [src]="getImage(dep.key)"></tui-avatar>
<div class="wrapper-margin">
<div class="inner-container-title">
<span>
{{ getTitle(dep.key) }}
</span>
<p>
@@ -19,10 +14,10 @@
</ng-container>
</p>
</div>
<span class="text-sm text-zinc-50/70 line-clamp-1">
<span class="inner-container-version">
{{ dep.value.version | displayEmver }}
</span>
<span class="text-sm text-zinc-50/70 h-11 line-clamp-2">
<span class="inner-container-description">
{{ dep.value.description }}
</span>
</div>

View File

@@ -0,0 +1,73 @@
.outer-container {
background-color: rgb(63 63 70 / 0.4);
border-radius: 0.75rem;
padding: 0.75rem 1.25rem;
gap: 0.5rem;
filter: drop-shadow(0 10px 8px rgb(0 0 0 / 0.04))
drop-shadow(0 4px 3px rgb(0 0 0 / 0.1));
&:hover {
background-color: rgb(63 63 70 / 0.7);
}
}
.inner-container {
display: flex;
align-items: center;
gap: 1.5rem;
&-title {
margin-bottom: 0.25rem;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.25rem;
span {
display: block;
font-size: 1rem;
line-height: 1.5rem;
font-weight: 500;
color: rgb(250 250 250 / 0.9);
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
&-version {
font-size: 0.875rem;
line-height: 1.25rem;
color: rgb(250 250 250 / 0.7);
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
&-description {
font-size: 0.875rem;
line-height: 1.25rem;
color: rgb(250 250 250 / 0.7);
height: 2.75rem;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
::ng-deep .dep-img {
width: 4rem;
pointer-events: none;
border-radius: 9999px;
object-fit: cover;
filter: drop-shadow(0 10px 8px rgb(0 0 0 / 0.04))
drop-shadow(0 4px 3px rgb(0 0 0 / 0.1));
margin-bottom: 0.75rem;
}
.wrapper-margin {
margin-top: 0.75rem;
}

View File

@@ -7,35 +7,28 @@ import { MimeTypePipeModule } from '../../../pipes/mime-type.pipe'
@Component({
selector: 'marketplace-package-hero',
template: `
<div class="flex justify-center mt-10 md:mt-0 z-0">
<div
class="flex flex-col w-full h-[32vh] xs:h-[26vh] md:min-h-[14rem] relative rounded-3xl pt-16 px-8 shadow-lg"
>
<div class="outer-container">
<div class="inner-container box-shadow-lg">
<!-- icon -->
<img
[src]="pkg | mimeType | trustUrl"
class="w-24 h-24 pointer-events-none rounded-full object-cover shadow-lg absolute -top-9 left-7 z-10"
class="box-shadow-lg"
alt="{{ pkg.manifest.title }} Icon"
/>
<!-- color background -->
<div
class="overflow-hidden absolute w-full h-full top-0 left-0 rounded-3xl bg-zinc-800"
>
<div class="color-background">
<img
[src]="pkg | mimeType | trustUrl"
class="absolute object-cover pointer-events-none w-[200%] h-[200%] max-w-[200%] blur-[100px] saturate-150 rounded-full"
alt="{{ pkg.manifest.title }} background image"
/>
</div>
<!-- background darkening overlay -->
<div
class="overflow-hidden absolute w-full h-full top-0 left-0 rounded-3xl bg-zinc-700 opacity-70"
></div>
<div class="my-4 text-zinc-50 mix-blend-plus-lighter">
<h2 class="text-2xl font-medium line-clamp-1 mb-1">
<div class="dark-overlay"></div>
<div class="inner-container-title">
<h2>
{{ pkg.manifest.title }}
</h2>
<p class="block text-base line-clamp-2">
<p>
{{ pkg.manifest.description.short }}
</p>
</div>
@@ -44,7 +37,111 @@ import { MimeTypePipeModule } from '../../../pipes/mime-type.pipe'
</div>
</div>
`,
styles: [],
styles: [
`
.outer-container {
display: flex;
justify-content: center;
margin-top: 2.5rem;
z-index: 0;
@media (min-width: 768px) {
margin-top: 0px;
}
}
.inner-container {
display: flex;
flex-direction: column;
width: 100%;
height: 32vh;
position: relative;
border-radius: 1.5rem;
padding: 4rem 2rem 0 2rem;
@media (min-width: 376px) {
height: 26vh;
}
@media (min-width: 768px) {
min-height: 14rem;
}
img {
width: 6rem;
height: 6rem;
pointer-events: none;
border-radius: 9999px;
object-fit: cover;
position: absolute;
top: -2.25rem;
left: 1.75rem;
z-index: 1;
}
.inner-container-title {
margin: 1rem 0;
color: rgb(250 250 250);
mix-blend-mode: plus-lighter;
z-index: 1;
h2 {
font-size: 1.5rem;
line-height: 2rem;
font-weight: 500;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
margin-bottom: 0.25rem;
}
p {
display: block;
font-size: 1rem;
line-height: 1.5rem;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
.color-background {
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
z-index: -50;
border-radius: 1.5rem;
background-color: rgb(39 39 42);
img {
position: absolute;
object-fit: cover;
pointer-events: none;
width: 200%;
height: 200%;
max-width: 200%;
filter: blur(100px) saturate(1.5);
}
}
.dark-overlay {
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
border-radius: 1.5rem;
background-color: rgb(63 63 70);
opacity: 0.7;
}
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, SharedPipesModule, MimeTypePipeModule],

View File

@@ -18,11 +18,7 @@ import { PolymorpheusContent } from '@tinkoff/ng-polymorpheus'
@Component({
selector: 'marketplace-package-screenshots',
template: `
<div
*ngIf="pkg.screenshots"
tuiCarouselButtons
class="flex items-center content-center m-0 lg:-ml-14 lg:-mr-14 lg:min-h-80 lg:h-80 2xl:h-full"
>
<div *ngIf="pkg.screenshots" tuiCarouselButtons class="outer-container">
<button
tuiIconButton
appearance="flat"
@@ -35,27 +31,27 @@ import { PolymorpheusContent } from '@tinkoff/ng-polymorpheus'
#carousel
[itemsCount]="isMobile ? 1 : 2"
[(index)]="index"
class="overflow-y-hidden overflow-x-scroll carousel overflow-hidden"
class="carousel"
>
<ng-container *ngFor="let item of pkg.screenshots; let i = index">
<div
*tuiItem
draggable="false"
[class.item_active]="i === index + 1"
class="object-cover overflow-hidden rounded-lg md:rounded-xl border border-zinc-400/30 hover:cursor-pointer shadow-lg shadow-zinc-400/10"
class="screenshot-item box-shadow-lg"
>
<img
#template
alt="Service screenshot"
src="assets/img/temp/{{ item }}"
class="w-full h-full rounded-lg md:rounded-xl"
class="screenshot-item-img"
(click)="presentModalImg(dialogTemplate)"
/>
<ng-template #dialogTemplate let-observer>
<img
alt="Service screenshot"
src="assets/img/temp/{{ item }}"
class="rounded-none"
class="screenshot-item-img-enlarged"
/>
</ng-template>
</div>
@@ -71,7 +67,65 @@ import { PolymorpheusContent } from '@tinkoff/ng-polymorpheus'
></button>
</div>
`,
styles: [],
styles: [
`
.outer-container {
display: flex;
align-items: center;
align-content: center;
margin: 0px;
@media (min-width: 1024px) {
margin-left: -3.5rem;
margin-right: -3.5rem;
min-height: 20rem;
height: 20rem;
}
@media (min-width: 1536px) {
height: 100%;
}
}
.carousel {
overflow-y: hidden;
overflow-x: scroll;
overflow: hidden;
}
.screenshot-item {
--tw-shadow-color: rgb(161 161 170 / 0.1);
--tw-shadow: var(--tw-shadow-colored);
object-fit: cover;
overflow: hidden;
border-radius: 0.5rem;
border-width: 1px;
border-color: rgb(161 161 170 / 0.3);
&:hover {
cursor: pointer;
}
@media (min-width: 768px) {
border-radius: 0.75rem;
}
.screenshot-item-img {
width: 100%;
height: 100%;
border-radius: 0.5rem;
@media (min-width: 768px) {
border-radius: 0.75rem;
}
.screenshot-item-img-enlarged {
border-radius: 0px;
}
}
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, TuiCarouselModule, TuiButtonModule],