Skip to content

Commit 8a6b7a3

Browse files
feat(registry-discover): registry discover page (#199)
* feat(registry-discover): registry discover page * fix(branded-registry): minor fixes
1 parent 905615d commit 8a6b7a3

36 files changed

+1090
-100
lines changed

src/app/core/components/nav-menu/nav-menu.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class NavMenuComponent {
7171

7272
const isCollectionsWithId = urlSegments[0] === 'collections' && urlSegments[1] && urlSegments[1] !== '';
7373
const isRegistryRoute = urlSegments[0] === 'registries' && !!urlSegments[2];
74-
const isRegistryRouteDetails = urlSegments[0] === 'registries' && urlSegments[2];
74+
const isRegistryRouteDetails = urlSegments[0] === 'registries' && urlSegments[2] === 'overview';
7575

7676
return {
7777
resourceId,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<section class="registries-hero-container py-5 px-3 flex flex-column gap-4 md:py-6 md:px-4">
2+
<div class="flex flex-column align-items-start gap-4 md:flex-row">
3+
<div class="flex align-items-center gap-2">
4+
@if (isProviderLoading()) {
5+
<p-skeleton width="3rem" height="1.5rem" />
6+
<p-skeleton width="12rem" height="1.5rem" />
7+
} @else {
8+
<img
9+
class="preprint-provider-hero-logo"
10+
alt="Provider Logo"
11+
height="40"
12+
[src]="provider()!.brand.heroLogoImageUrl"
13+
/>
14+
}
15+
</div>
16+
</div>
17+
18+
<div class="provider-description">
19+
@if (isProviderLoading()) {
20+
<div class="flex flex-column gap-2">
21+
<p-skeleton width="40%" height="1.5rem"></p-skeleton>
22+
<p-skeleton width="70%" height="1.5rem"></p-skeleton>
23+
24+
<p-skeleton width="10%" height="1rem"></p-skeleton>
25+
</div>
26+
} @else {
27+
<div [innerHTML]="provider()!.descriptionHtml | decodeHtml"></div>
28+
}
29+
</div>
30+
31+
@if (isProviderLoading()) {
32+
<p-skeleton class="w-full" height="3rem" />
33+
} @else {
34+
<div class="search-input-container">
35+
<osf-search-input
36+
class="w-full"
37+
[showHelpIcon]="true"
38+
[placeholder]="'preprints.searchPlaceholder' | translate: { preprintWord: 'Registrations' } | titlecase"
39+
[control]="searchControl()"
40+
(triggerSearch)="onTriggerSearch($event)"
41+
(helpClicked)="openHelpDialog()"
42+
/>
43+
</div>
44+
}
45+
</section>

src/app/features/registries/components/registry-provider-hero/registry-provider-hero.component.scss

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { RegistryProviderHeroComponent } from './registry-provider-hero.component';
4+
5+
describe('RegistryProviderHeroComponent', () => {
6+
let component: RegistryProviderHeroComponent;
7+
let fixture: ComponentFixture<RegistryProviderHeroComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [RegistryProviderHeroComponent],
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(RegistryProviderHeroComponent);
15+
component = fixture.componentInstance;
16+
fixture.detectChanges();
17+
});
18+
19+
it('should create', () => {
20+
expect(component).toBeTruthy();
21+
});
22+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
2+
3+
import { DialogService } from 'primeng/dynamicdialog';
4+
import { Skeleton } from 'primeng/skeleton';
5+
6+
import { TitleCasePipe } from '@angular/common';
7+
import { ChangeDetectionStrategy, Component, effect, inject, input, output } from '@angular/core';
8+
import { FormControl } from '@angular/forms';
9+
10+
import { PreprintsHelpDialogComponent } from '@osf/features/preprints/components';
11+
import { RegistryProviderDetails } from '@osf/features/registries/models/registry-provider.model';
12+
import { SearchInputComponent } from '@shared/components';
13+
import { DecodeHtmlPipe } from '@shared/pipes';
14+
import { BrandService } from '@shared/services';
15+
import { HeaderStyleHelper } from '@shared/utils';
16+
17+
@Component({
18+
selector: 'osf-registry-provider-hero',
19+
imports: [DecodeHtmlPipe, SearchInputComponent, Skeleton, TitleCasePipe, TranslatePipe],
20+
templateUrl: './registry-provider-hero.component.html',
21+
styleUrl: './registry-provider-hero.component.scss',
22+
changeDetection: ChangeDetectionStrategy.OnPush,
23+
})
24+
export class RegistryProviderHeroComponent {
25+
protected translateService = inject(TranslateService);
26+
protected dialogService = inject(DialogService);
27+
28+
searchControl = input<FormControl>(new FormControl());
29+
provider = input.required<RegistryProviderDetails | null>();
30+
isProviderLoading = input.required<boolean>();
31+
triggerSearch = output<string>();
32+
33+
onTriggerSearch(value: string) {
34+
this.triggerSearch.emit(value);
35+
}
36+
37+
constructor() {
38+
effect(() => {
39+
const provider = this.provider();
40+
41+
if (provider) {
42+
BrandService.applyBranding(provider.brand);
43+
HeaderStyleHelper.applyHeaderStyles(
44+
provider.brand.primaryColor,
45+
undefined,
46+
provider.brand.heroBackgroundImageUrl
47+
);
48+
}
49+
});
50+
}
51+
52+
openHelpDialog() {
53+
this.dialogService.open(PreprintsHelpDialogComponent, {
54+
focusOnShow: false,
55+
header: this.translateService.instant('preprints.helpDialog.header'),
56+
closeOnEscape: true,
57+
modal: true,
58+
closable: true,
59+
});
60+
}
61+
}

src/app/features/registries/mappers/providers.mapper.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { RegistryProviderDetails } from '@osf/features/registries/models/registry-provider.model';
2+
import { RegistryProviderDetailsJsonApi } from '@osf/features/registries/models/registry-provider-json-api.model';
3+
14
import { ProviderSchema, ProvidersResponseJsonApi } from '../models';
25

36
export class ProvidersMapper {
@@ -7,4 +10,23 @@ export class ProvidersMapper {
710
name: item.attributes.name,
811
}));
912
}
13+
14+
static fromRegistryProvider(response: RegistryProviderDetailsJsonApi): RegistryProviderDetails {
15+
const brandRaw = response.embeds!.brand.data;
16+
return {
17+
id: response.id,
18+
name: response.attributes.name,
19+
descriptionHtml: response.attributes.description,
20+
brand: {
21+
id: brandRaw.id,
22+
name: brandRaw.attributes.name,
23+
heroLogoImageUrl: brandRaw.attributes.hero_logo_image,
24+
heroBackgroundImageUrl: brandRaw.attributes.hero_background_image,
25+
topNavLogoImageUrl: brandRaw.attributes.topnav_logo_image,
26+
primaryColor: brandRaw.attributes.primary_color,
27+
secondaryColor: brandRaw.attributes.secondary_color,
28+
},
29+
iri: response.links.iri,
30+
};
31+
}
1032
}

src/app/features/registries/models/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ export * from './project';
33
export * from './projects-json-api.model';
44
export * from './provider-schema.model';
55
export * from './providers-json-api.model';
6+
export * from './registry-provider.model';
7+
export * from './registry-provider-json-api.model';
68
export * from './schema-blocks-json-api.model';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { BrandDataJsonApi } from '@shared/models';
2+
3+
export interface RegistryProviderDetailsJsonApi {
4+
id: string;
5+
type: 'registration-providers';
6+
attributes: {
7+
name: string;
8+
description: string;
9+
};
10+
embeds?: {
11+
brand: {
12+
data: BrandDataJsonApi;
13+
};
14+
};
15+
links: {
16+
iri: string;
17+
};
18+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Brand } from '@shared/models';
2+
3+
export interface RegistryProviderDetails {
4+
id: string;
5+
name: string;
6+
descriptionHtml: string;
7+
brand: Brand;
8+
iri: string;
9+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<osf-registry-provider-hero
2+
[searchControl]="searchControl"
3+
[provider]="provider()"
4+
[isProviderLoading]="isProviderLoading()"
5+
></osf-registry-provider-hero>
6+
7+
<div class="flex flex-column flex-1 w-full">
8+
<div class="py-4 px-3 md:px-5 xl:px-4 bg-white">
9+
<osf-search-results-container
10+
[resources]="resources()"
11+
[searchCount]="resourcesCount()"
12+
[selectedSort]="selectedSort()"
13+
[selectedTab]="resourceType()"
14+
[selectedValues]="selectedValues()"
15+
[first]="first()"
16+
[prev]="previous()"
17+
[next]="next()"
18+
[isFiltersOpen]="isFiltersOpen()"
19+
[isSortingOpen]="isSortingOpen()"
20+
[showTabs]="false"
21+
(sortChanged)="onSortChanged($event)"
22+
(pageChanged)="onPageChanged($event)"
23+
(filtersToggled)="onFiltersToggled()"
24+
(sortingToggled)="onSortingToggled()"
25+
>
26+
<div slot="filter-chips">
27+
<osf-filter-chips
28+
[selectedValues]="selectedValues()"
29+
[filterLabels]="filterLabels()"
30+
[filterOptions]="filterOptions()"
31+
(filterRemoved)="onFilterChipRemoved($event)"
32+
(allFiltersCleared)="onAllFiltersCleared()"
33+
/>
34+
</div>
35+
36+
<div slot="filters">
37+
<osf-reusable-filters
38+
[filters]="filters()"
39+
[selectedValues]="selectedValues()"
40+
[isLoading]="isResourcesLoading()"
41+
[showEmptyState]="true"
42+
(loadFilterOptions)="onLoadFilterOptions($event)"
43+
(filterValueChanged)="onFilterChanged($event)"
44+
/>
45+
</div>
46+
47+
<div slot="mobile-filters">
48+
<osf-reusable-filters
49+
[filters]="filters()"
50+
[selectedValues]="selectedValues()"
51+
[isLoading]="isResourcesLoading()"
52+
[showEmptyState]="true"
53+
(loadFilterOptions)="onLoadFilterOptions($event)"
54+
(filterValueChanged)="onFilterChanged($event)"
55+
/>
56+
</div>
57+
</osf-search-results-container>
58+
59+
<osf-search-help-tutorial [(currentStep)]="currentStep"></osf-search-help-tutorial>
60+
</div>
61+
</div>

0 commit comments

Comments
 (0)