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

720
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,6 @@
"pbkdf2": "^3.1.2",
"rxjs": "^7.5.6",
"swiper": "^8.2.4",
"tailwindcss": "^3.3.3",
"ts-matches": "^5.2.1",
"tslib": "^2.3.0",
"uuid": "^8.3.2",

View File

@@ -1,13 +1,12 @@
{
"name": "@start9labs/marketplace",
"version": "0.3.16",
"version": "0.3.19",
"peerDependencies": {
"@angular/common": ">=13.2.0",
"@angular/core": ">=13.2.0",
"@start9labs/shared": ">=0.3.2",
"@taiga-ui/cdk": ">=3.0.0",
"@tinkoff/ng-dompurify": ">=4.0.0",
"tailwindcss": "^3.3.2",
"fuse.js": "^6.4.6"
},
"dependencies": {

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],

View File

@@ -1,11 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{html,ts}'],
theme: {
extend: {},
fontFamily: {
sans: ['Montserrat', 'sans-serif'],
},
},
plugins: [],
}

View File

@@ -1,6 +1,6 @@
{
"name": "@start9labs/shared",
"version": "0.3.6",
"version": "0.3.9",
"peerDependencies": {
"@angular/common": "^17.0.6",
"@angular/core": "^17.0.6",

View File

@@ -41,7 +41,7 @@ import { SetupService } from '../../services/setup.service'
padding: 1rem;
margin: 1.5rem;
text-align: center;
// TODO: Theme
/* TODO: Theme */
background: #e0e0e0;
color: #333;
--tui-clear-inverse: rgba(0, 0, 0, 0.1);
@@ -56,7 +56,7 @@ import { SetupService } from '../../services/setup.service'
text-align: left;
overflow: hidden;
border-radius: 2rem;
// TODO: Theme
/* TODO: Theme */
background: #181818;
}
`,

View File

@@ -4,4 +4,15 @@
:host ::ng-deep img {
border-radius: 0 !important;
}
:host ::ng-deep h1,
:host ::ng-deep h2,
:host ::ng-deep h3,
:host ::ng-deep h4,
:host ::ng-deep h5,
:host ::ng-deep h6,
:host ::ng-deep hr,
:host ::ng-deep p {
margin: revert;
}

View File

@@ -1,7 +1,7 @@
import { Log } from '../types/api'
import { toLocalIsoString } from './to-local-iso-string'
import Convert from 'ansi-to-html'
const Convert = require('ansi-to-html')
const CONVERT = new Convert({
bg: 'transparent',
colors: { 4: 'Cyan' },

View File

@@ -86,10 +86,12 @@ ion-modal {
}
.divider {
background: linear-gradient(90deg,
var(--ion-color-light) 0,
var(--ion-color-dark) 50%,
var(--ion-color-light) 100%);
background: linear-gradient(
90deg,
var(--ion-color-light) 0,
var(--ion-color-dark) 50%,
var(--ion-color-light) 100%
);
height: 1px;
}
@@ -112,11 +114,11 @@ ion-modal {
}
.color-success-shade {
color: var(--ion-color-success-shade)
color: var(--ion-color-success-shade);
}
.color-primary-shade {
color: var(--ion-color-primary-shade)
color: var(--ion-color-primary-shade);
}
@keyframes ellipsis-dot {
@@ -167,3 +169,63 @@ a {
gap: 16px;
margin-top: 24px;
}
/* marketplace */
.background-border {
border-radius: 0.75rem;
background-image: linear-gradient(
to bottom left,
rgb(161 161 170 / 0.75),
#52525b
);
padding: 1px;
margin-top: 1.5rem;
}
.box-shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color),
0 4px 6px -4px var(--tw-shadow-color);
box-shadow:
0 0 #0000,
0 0 #0000,
var(--tw-shadow);
}
.shadow-color-light {
--tw-shadow-color: rgb(161 161 170 / 0.1);
--tw-shadow: var(--tw-shadow-colored);
}
.additional-detail-title {
font-size: 1.125rem;
line-height: 1.75rem;
font-weight: 700;
padding-bottom: 0.75rem;
font-variant: all-small-caps;
}
.buttons {
margin-top: 0.5rem;
:first-child {
margin-right: 0.5rem;
}
}
a {
color: inherit;
text-decoration: inherit;
}
h1,
h2,
h3,
h4,
h5,
h6,
hr,
p {
margin: 0;
}

View File

@@ -86,10 +86,49 @@
--ion-color-step-900: #e7e7e7;
--ion-color-step-950: #f3f3f3;
--alt-red: #FF4961;
--alt-orange: #F89248;
--alt-yellow: #E5D53E;
--alt-green: #3DCF6F;
--alt-blue: #00A8A8;
--alt-purple: #9747FF;
--alt-red: #ff4961;
--alt-orange: #f89248;
--alt-yellow: #e5d53e;
--alt-green: #3dcf6f;
--alt-blue: #00a8a8;
--alt-purple: #9747ff;
--portal-header-height: 56px;
// @TODO rename when make style lib
--tw-color-black: 0 0 0;
--tw-color-white: 255 255 255;
--tw-color-slate-50: 248 250 252;
--tw-color-slate-100: 241 245 249;
--tw-color-slate-200: 226 232 240;
--tw-color-slate-300: 203 213 225;
--tw-color-slate-400: 148 163 184;
--tw-color-slate-500: 100 116 139;
--tw-color-slate-600: 71 85 105;
--tw-color-slate-700: 51 65 85;
--tw-color-slate-800: 30 41 59;
--tw-color-slate-900: 15 23 42;
--tw-color-slate-950: 2 6 23;
--tw-color-gray-50: 249 250 251;
--tw-color-gray-100: 243 244 246;
--tw-color-gray-200: 229 231 235;
--tw-color-gray-300: 209 213 219;
--tw-color-gray-400: 156 163 175;
--tw-color-gray-500: 107 114 128;
--tw-color-gray-600: 75 85 99;
--tw-color-gray-700: 55 65 81;
--tw-color-gray-800: 31 41 55;
--tw-color-gray-900: 17 24 39;
--tw-color-gray-950: 3 7 18;
--tw-color-zinc-50: 250 250 250;
--tw-color-zinc-100: 244 244 245;
--tw-color-zinc-200: 228 228 231;
--tw-color-zinc-300: 212 212 216;
--tw-color-zinc-400: 161 161 170;
--tw-color-zinc-500: 113 113 122;
--tw-color-zinc-600: 82 82 91;
--tw-color-zinc-700: 63 63 70;
--tw-color-zinc-800: 39 39 42;
--tw-color-zinc-900: 24 24 27;
--tw-color-zinc-950: 9 9 11;
}

View File

@@ -31,7 +31,6 @@ import { MarketplaceService } from 'src/app/services/marketplace.service'
import { hasCurrentDeps } from 'src/app/util/has-deps'
import { getAllPackages } from 'src/app/util/get-package-data'
import { dryUpdate } from 'src/app/util/dry-update'
import { SidebarService } from 'src/app/services/sidebar.service'
import { MarketplaceAlertsService } from '../services/alerts.service'
@Component({

View File

@@ -15,21 +15,28 @@ import { MARKETPLACE_REGISTRY } from '../modals/registry.component'
tuiIconButton
type="button"
appearance="icon"
icon="tuiIconRepeat"
icon="tuiIconRepeatLarge"
(click)="changeRegistry()"
>
Change Registry
</button>
<button
slot="mobile"
class="flex gap-2 p-5 text-base"
(click)="changeRegistry()"
>
<tui-icon tuiAppearance="icon" icon="tuiIconRepeat"></tui-icon>
<button slot="mobile" class="mobile-button" (click)="changeRegistry()">
<tui-icon tuiAppearance="icon" icon="tuiIconRepeatLarge"></tui-icon>
Change Registry
</button>
</menu>
`,
styles: [
`
.mobile-button {
display: flex;
gap: 0.5rem;
padding: 1.25rem;
font-size: 1rem;
line-height: 1.5rem;
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [MenuModule, TuiButtonModule, TuiIconModule, TuiAppearanceModule],
})

View File

@@ -7,7 +7,11 @@ import { ConfigService } from 'src/app/services/config.service'
standalone: true,
selector: 'marketplace-notification',
template: `
<tui-notification [status]="status || 'warning'" icon="" class="m-4">
<tui-notification
[status]="status || 'warning'"
icon=""
class="notification-wrapper"
>
@switch (status) {
@case ('success') {
Services from this registry are packaged and maintained by the Start9
@@ -48,6 +52,13 @@ import { ConfigService } from 'src/app/services/config.service'
}
</tui-notification>
`,
styles: [
`
.notification-wrapper {
margin: 1rem;
}
`,
],
imports: [TuiNotificationModule],
})
export class MarketplaceNotificationComponent {

View File

@@ -30,7 +30,7 @@ import { MarketplaceSidebarService } from '../services/sidebar.service'
direction: 'right';
autoWidth: true
"
class="overflow-y-auto max-w-full md:max-w-[30rem]"
class="preview-wrapper"
[pkg]="pkg"
(tuiActiveZoneChange)="toggle($event)"
>
@@ -38,7 +38,7 @@ import { MarketplaceSidebarService } from '../services/sidebar.service'
tuiAutoFocus
slot="close"
size="xs"
class="place-self-end"
class="close-button"
tuiIconButton
type="button"
appearance="icon"
@@ -47,7 +47,7 @@ import { MarketplaceSidebarService } from '../services/sidebar.service'
></button>
<marketplace-controls
slot="controls"
class="flex justify-start gap-2"
class="controls-wrapper"
[pkg]="pkg"
[localPkg]="pkg.manifest.id | toLocal | async"
/>
@@ -70,6 +70,25 @@ import { MarketplaceSidebarService } from '../services/sidebar.service'
opacity: 1;
}
}
.preview-wrapper {
overflow-y: auto;
max-width: 100%;
@media (min-width: 768px) {
max-width: 30rem;
}
}
.close-button {
place-self: end;
}
.controls-wrapper {
display: flex;
justify-content: flex-start;
gap: 0.5rem;
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -17,30 +17,26 @@ import { MarketplaceSidebarsComponent } from './components/sidebars.component'
standalone: true,
template: `
<marketplace-menu />
<div
class="sm:pl-[34vw] md:pl-[28vw] lg:pl-[22vw] 2xl:pl-[280px] min-h-screen flex justify-between overflow-auto scroll-smooth"
>
<div class="pt-24 sm:pt-3 md:pb-10 md:px-8">
<div class="marketplace-content-wrapper">
<div class="marketplace-content-inner">
<marketplace-notification [url]="(details$ | async)?.url || ''" />
<div class="mt-8 px-6 mb-10">
<h1 class="text-4xl sm:text-5xl font-bold text-zinc-50/80">
<div class="title-wrapper">
<h1>
{{ category$ | async | titlecase }}
</h1>
</div>
@if (filtered$ | async; as filtered) {
<section
class="p-6 md:p-8 grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-3 gap-16 list-none"
>
<section class="marketplace-content-list">
@for (pkg of filtered; track $index) {
<marketplace-tile
[pkg]="pkg"
[style.--animation-order]="$index"
class="block h-full"
class="tile-wrapper"
/>
}
</section>
} @else {
<h1 class="text-xl pl-6">
<h1 class="loading-text">
Loading
<span class="loading-dots"></span>
</h1>
@@ -58,6 +54,96 @@ import { MarketplaceSidebarsComponent } from './components/sidebars.component'
background: #18181b url('/assets/img/background.png') no-repeat top
right;
}
::ng-deep menu {
margin: 0;
padding: 0;
}
::ng-deep button {
background-color: transparent;
background-image: none;
}
.marketplace-content {
&-wrapper {
display: flex;
justify-content: space-between;
overflow: auto;
scroll-behavior: smooth;
min-height: 100vh;
@media (min-width: 640px) {
padding-left: 34vw;
}
@media (min-width: 768px) {
padding-left: 28vw;
}
@media (min-width: 1024px) {
padding-left: 22vw;
}
@media (min-width: 1536px) {
padding-left: 280px;
}
}
&-inner {
padding-top: 6rem;
@media (min-width: 640px) {
padding-top: 0.75rem;
}
@media (min-width: 768px) {
padding: 0 2rem 2.5rem 2rem;
}
.title-wrapper {
margin: 2rem 0 2.5rem 0;
padding: 0 1.5rem;
h1 {
font-size: 2.25rem;
line-height: 2.5rem;
font-weight: 700;
color: rgb(250 250 250 / 0.8);
@media (min-width: 640px) {
font-size: 3rem;
line-height: 1;
}
}
}
}
&-list {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: 4rem;
list-style-type: none;
padding: 1.5rem;
@media (min-width: 768px) {
padding: 2rem;
}
@media (min-width: 1280px) {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 1536px) {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.tile-wrapper {
display: block;
height: 100%;
}
}
}
.loading-text {
font-size: 1.25rem;
line-height: 1.75rem;
padding-left: 1.5rem;
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -22,7 +22,7 @@ import { Router } from '@angular/router'
@Component({
selector: 'marketplace-preview',
template: `
<div class="grid gap-8 p-7 justify-center">
<div class="outer-container">
<ng-content select="[slot=close]" />
<marketplace-package-hero [pkg]="pkg">
<ng-content select="[slot=controls]" />
@@ -38,17 +38,13 @@ import { Router } from '@angular/router'
View more details
</a>
}
<div class="grid grid-cols-1 gap-x-8">
<div class="inner-container">
<marketplace-about [pkg]="pkg" />
@if (!(pkg.manifest.dependencies | empty)) {
<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="lg:col-span-5 xl:col-span-4 bg-zinc-800 rounded-xl p-7">
<h2 class="text-lg font-bold small-caps my-2 pb-3">
Dependencies
</h2>
<div class="grid grid-row-auto gap-3">
<div class="background-border shadow-color-light box-shadow-lg">
<div class="dependencies-container">
<h2>Dependencies</h2>
<div class="dependencies-list">
@for (
dep of pkg.manifest.dependencies | keyvalue;
track $index
@@ -64,11 +60,64 @@ import { Router } from '@angular/router'
</div>
}
<release-notes [pkg]="pkg" />
<marketplace-additional class="mt-6" [pkg]="pkg" />
<marketplace-additional class="additional-wrapper" [pkg]="pkg" />
</div>
</div>
`,
styles: [':host { pointer-events: auto }'],
styles: [
`
:host {
pointer-events: auto;
}
.outer-container {
display: grid;
justify-content: center;
gap: 2rem;
padding: 1.75rem;
}
.inner-container {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
column-gap: 2rem;
}
.dependencies {
&-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;
}
h2 {
font-size: 1.125rem;
line-height: 1.75rem;
font-weight: 700;
margin: 0.5rem 0;
padding-bottom: 0.75rem;
font-variant: all-small-caps;
}
}
&-list {
display: grid;
grid-auto-rows: auto;
gap: 0.75rem;
}
}
.additional-wrapper {
margin-top: 1.5rem;
}
`,
],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [

View File

@@ -102,7 +102,7 @@ export module Mock {
icon: 'icon.png',
},
'release-notes':
'Dual funded channels! And lots more amazing new features. Also includes several bugfixes and performance enhancements.',
'* Dual funded channels! And lots more amazing new features. Also includes several bugfixes and performance enhancements.',
license: 'MIT',
'wrapper-repo': 'https://github.com/start9labs/lnd-wrapper',
'upstream-repo': 'https://github.com/lightningnetwork/lnd',

View File

@@ -104,7 +104,8 @@ export class MockApiService extends ApiService {
async getStatic(url: string): Promise<string> {
await pauseFor(2000)
return '' // markdown
return `* Test markdown instructions
* Test markdown instructions with [link](https://start9.com)`
}
async uploadPackage(guid: string, body: Blob): Promise<void> {
@@ -458,6 +459,7 @@ export class MockApiService extends ApiService {
'messaging',
'social',
'alt coin',
'ai',
],
}
return info
@@ -466,7 +468,8 @@ export class MockApiService extends ApiService {
} else if (path.startsWith('/package/v0/release-notes')) {
return Mock.ReleaseNotes
} else if (path.includes('instructions') || path.includes('license')) {
return '' // markdown
return `* Test markdown instructions
* Test markdown instructions with [link](https://start9.com)`
}
}

View File

@@ -1,6 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import '@taiga-ui/core/styles/taiga-ui-local';
@font-face {

View File

@@ -1,25 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{html,ts}', '../marketplace/src/**/*.{html,ts}'],
theme: {
extend: {
screens: {
xs: '376px',
'3xl': '1792px',
'4xl': '2048px',
},
colors: {
folly: '#FF4961',
lime: '#BCFF49',
cyan: '#49FFE7',
veronica: '#9747ff',
tangerine: '#ff8c49',
royal: '#4961ff',
background: '#222428',
},
},
fontFamily: {
sans: ['Montserrat', 'sans-serif'],
},
},
}