From 684b3e24de2d249d431660c3de08ee344197d29d Mon Sep 17 00:00:00 2001 From: Roman Nastyuk Date: Mon, 2 Jun 2025 18:28:19 +0300 Subject: [PATCH 1/3] feat(design-collections-page): added layout for the collections landing page --- src/app/app.routes.ts | 4 + src/app/core/constants/nav-items.constant.ts | 6 + src/app/core/interceptors/auth.interceptor.ts | 5 +- .../collections/collections.component.html | 27 +++ .../collections/collections.component.scss | 48 ++++ .../collections/collections.component.spec.ts | 22 ++ .../collections/collections.component.ts | 22 ++ .../collections/collections.routes.ts | 10 + .../collections-filter-chips.component.html | 21 ++ .../collections-filter-chips.component.scss | 0 ...collections-filter-chips.component.spec.ts | 22 ++ .../collections-filter-chips.component.ts | 31 +++ .../collections-filters.component.html | 43 ++++ .../collections-filters.component.scss | 16 ++ .../collections-filters.component.spec.ts | 22 ++ .../collections-filters.component.ts | 81 +++++++ .../collections-main-content.component.html | 74 ++++++ .../collections-main-content.component.scss | 16 ++ ...collections-main-content.component.spec.ts | 22 ++ .../collections-main-content.component.ts | 95 ++++++++ ...lections-search-result-card.component.html | 27 +++ ...lections-search-result-card.component.scss | 30 +++ ...tions-search-result-card.component.spec.ts | 22 ++ ...ollections-search-result-card.component.ts | 28 +++ .../collections-search-results.component.html | 13 + .../collections-search-results.component.scss | 3 + ...llections-search-results.component.spec.ts | 22 ++ .../collections-search-results.component.ts | 86 +++++++ .../collection-search-result-card.models.ts | 25 ++ src/app/features/collections/models/index.ts | 1 + .../collections/store/collections.actions.ts | 55 +++++ .../collections/store/collections.model.ts | 16 ++ .../store/collections.selectors.ts | 67 +++++- .../collections/store/collections.state.ts | 149 ++++++++++++ src/app/features/collections/utils/index.ts | 1 + .../collections/utils/sort-options.const.ts | 7 + .../utils/submission-attributes.const.ts | 13 + src/assets/i18n/en.json | 78 ++++++ src/assets/icons/dist/icons.css | 224 +++++++++++------- src/assets/icons/dist/icons.eot | Bin 13392 -> 12984 bytes src/assets/icons/dist/icons.html | 21 +- src/assets/icons/dist/icons.json | 140 ++++++----- src/assets/icons/dist/icons.ts | 132 +++++------ src/assets/icons/dist/icons.woff | Bin 6944 -> 6768 bytes src/assets/icons/dist/icons.woff2 | Bin 5820 -> 5700 bytes src/assets/icons/source/arrow-down.svg | 6 +- src/assets/icons/source/warning-sign.svg | 6 +- src/assets/styles/overrides/button.scss | 12 + src/assets/styles/overrides/multiselect.scss | 34 +++ src/assets/styles/overrides/paginator.scss | 6 + src/assets/styles/styles.scss | 1 + 51 files changed, 1565 insertions(+), 247 deletions(-) create mode 100644 src/app/features/collections/collections.component.html create mode 100644 src/app/features/collections/collections.component.scss create mode 100644 src/app/features/collections/collections.component.spec.ts create mode 100644 src/app/features/collections/collections.component.ts create mode 100644 src/app/features/collections/collections.routes.ts create mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html create mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss create mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts create mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts create mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.html create mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.scss create mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts create mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.ts create mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.html create mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.scss create mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts create mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.ts create mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html create mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss create mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts create mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts create mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.html create mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.scss create mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts create mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.ts create mode 100644 src/app/features/collections/models/collection-search-result-card.models.ts create mode 100644 src/app/features/collections/utils/index.ts create mode 100644 src/app/features/collections/utils/sort-options.const.ts create mode 100644 src/app/features/collections/utils/submission-attributes.const.ts create mode 100644 src/assets/styles/overrides/multiselect.scss diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 8972a0c0c..269df519e 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -64,6 +64,10 @@ export const routes: Routes = [ loadComponent: () => import('./features/static/privacy-policy/privacy-policy.component').then((mod) => mod.PrivacyPolicyComponent), }, + { + path: 'collections', + loadChildren: () => import('./features/collections/collections.routes').then((mod) => mod.collectionsRoutes), + }, { path: 'meetings', loadComponent: () => import('./features/meetings/meetings.component').then((mod) => mod.MeetingsComponent), diff --git a/src/app/core/constants/nav-items.constant.ts b/src/app/core/constants/nav-items.constant.ts index 9fabf8d12..c6dda0acf 100644 --- a/src/app/core/constants/nav-items.constant.ts +++ b/src/app/core/constants/nav-items.constant.ts @@ -40,6 +40,12 @@ export const NAV_ITEMS: NavItem[] = [ icon: 'profile', useExactMatch: true, }, + { + path: '/collections', + label: 'navigation.collections', + icon: 'collections', + useExactMatch: true, + }, { path: '/meetings', label: 'navigation.meetings', diff --git a/src/app/core/interceptors/auth.interceptor.ts b/src/app/core/interceptors/auth.interceptor.ts index 46cc9dd13..9b2ac4219 100644 --- a/src/app/core/interceptors/auth.interceptor.ts +++ b/src/app/core/interceptors/auth.interceptor.ts @@ -7,8 +7,9 @@ export const authInterceptor: HttpInterceptorFn = ( next: HttpHandlerFn ): Observable> => { const authToken = 'UlO9O9GNKgVzJD7pUeY53jiQTKJ4U2znXVWNvh0KZQruoENuILx0IIYf9LoDz7Duq72EIm'; - // '2rjFZwmdDG4rtKj7hGkEMO6XyHBM2lN7XBbsA1e8OqcFhOWu6Z7fQZiheu9RXtzSeVrgOt'; - // 'OBJoUomBgbUuDgQo5JoaSKNya6XaYcd0ojAX1XOLmWi6J2arQPzByxyEi81fHE60drQUWv'; + // OBJoUomBgbUuDgQo5JoaSKNya6XaYcd0ojAX1XOLmWi6J2arQPzByxyEi81fHE60drQUWv + // UlO9O9GNKgVzJD7pUeY53jiQTKJ4U2znXVWNvh0KZQruoENuILx0IIYf9LoDz7Duq72EIm kyrylo + // 2rjFZwmdDG4rtKj7hGkEMO6XyHBM2lN7XBbsA1e8OqcFhOWu6Z7fQZiheu9RXtzSeVrgOt roman nastyuk if (authToken) { const authReq = req.clone({ diff --git a/src/app/features/collections/collections.component.html b/src/app/features/collections/collections.component.html new file mode 100644 index 000000000..66b8eb9fd --- /dev/null +++ b/src/app/features/collections/collections.component.html @@ -0,0 +1,27 @@ +
+
+
+ +

Collection Title

+
+ + +
+ +
+ better-research + +
+ +
+ +
+
diff --git a/src/app/features/collections/collections.component.scss b/src/app/features/collections/collections.component.scss new file mode 100644 index 000000000..45e015896 --- /dev/null +++ b/src/app/features/collections/collections.component.scss @@ -0,0 +1,48 @@ +@use "assets/styles/variables" as var; +@use "assets/styles/mixins" as mix; + +:host { + border: 2px solid var.$white; + display: flex; + flex-direction: column; + flex: 1; + margin-top: mix.rem(64px); + background: #013b5c; + + .collections-sub-header { + margin: mix.rem(48px) mix.rem(28px); + + .collections-icon { + font-size: mix.rem(42px); + } + + @media (max-width: 575px) { + margin-bottom: mix.rem(20px); + } + } + + .search-input-container { + margin: 0 mix.rem(28px) mix.rem(48px) mix.rem(28px); + position: relative; + + img { + position: absolute; + right: mix.rem(4px); + top: mix.rem(4px); + z-index: 1; + } + } + + .content-container { + background: var.$white; + padding: mix.rem(28px); + } + + @media (min-width: 576px) and (max-width: 1199px) { + margin-top: mix.rem(36px); + } + + @media (max-width: 575px) { + margin-top: 0; + } +} diff --git a/src/app/features/collections/collections.component.spec.ts b/src/app/features/collections/collections.component.spec.ts new file mode 100644 index 000000000..ba26a5f4a --- /dev/null +++ b/src/app/features/collections/collections.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsComponent } from './collections.component'; + +describe('CollectionsComponent', () => { + let component: CollectionsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/collections.component.ts b/src/app/features/collections/collections.component.ts new file mode 100644 index 000000000..9fa7d2062 --- /dev/null +++ b/src/app/features/collections/collections.component.ts @@ -0,0 +1,22 @@ +import { TranslatePipe } from '@ngx-translate/core'; + +import { Button } from 'primeng/button'; + +import { NgOptimizedImage } from '@angular/common'; +import { ChangeDetectionStrategy, Component, signal } from '@angular/core'; +import { FormControl } from '@angular/forms'; + +import { CollectionsMainContentComponent } from '@osf/features/collections/components/collections-main-content/collections-main-content.component'; +import { SearchInputComponent } from '@shared/components'; + +@Component({ + selector: 'osf-collections', + imports: [NgOptimizedImage, SearchInputComponent, TranslatePipe, Button, CollectionsMainContentComponent], + templateUrl: './collections.component.html', + styleUrl: './collections.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsComponent { + protected searchValue = signal(''); + protected searchControl = new FormControl(''); +} diff --git a/src/app/features/collections/collections.routes.ts b/src/app/features/collections/collections.routes.ts new file mode 100644 index 000000000..2c7681352 --- /dev/null +++ b/src/app/features/collections/collections.routes.ts @@ -0,0 +1,10 @@ +import { Routes } from '@angular/router'; + +import { CollectionsComponent } from '@osf/features/collections/collections.component'; + +export const collectionsRoutes: Routes = [ + { + path: '', + component: CollectionsComponent, + }, +]; diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html new file mode 100644 index 000000000..a6007214a --- /dev/null +++ b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html @@ -0,0 +1,21 @@ +
+ @if (activeFilters().programArea.length) { + @for (filter of activeFilters().programArea; track filter) { + + + + + + } + } + + @if (activeFilters().collectedType.length) { + @for (filter of activeFilters().collectedType; track filter) { + + + + + + } + } +
diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts new file mode 100644 index 000000000..cfc3b6a7a --- /dev/null +++ b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsFilterChipsComponent } from './collections-filter-chips.component'; + +describe('CollectionsFilterChipsComponent', () => { + let component: CollectionsFilterChipsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsFilterChipsComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsFilterChipsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts new file mode 100644 index 000000000..0355dc9fe --- /dev/null +++ b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts @@ -0,0 +1,31 @@ +import { select, Store } from '@ngxs/store'; + +import { PrimeTemplate } from 'primeng/api'; +import { Chip } from 'primeng/chip'; + +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +import { CollectionsSelectors, SetCollectedTypeFilters, SetProgramAreaFilters } from '@osf/features/collections/store'; + +@Component({ + selector: 'osf-collections-filter-chips', + imports: [Chip, PrimeTemplate], + templateUrl: './collections-filter-chips.component.html', + styleUrl: './collections-filter-chips.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsFilterChipsComponent { + protected activeFilters = select(CollectionsSelectors.getAllFilters); + + constructor(private store: Store) {} + + protected onRemoveProgramAreaFilter(removedFilter: string): void { + const currentFilters = this.activeFilters().programArea.filter((filter) => filter !== removedFilter); + this.store.dispatch(new SetProgramAreaFilters(currentFilters)); + } + + protected onRemoveCollectedTypeFilter(removedFilter: string): void { + const currentFilters = this.activeFilters().collectedType.filter((filter) => filter !== removedFilter); + this.store.dispatch(new SetCollectedTypeFilters(currentFilters)); + } +} diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.html b/src/app/features/collections/components/collections-filters/collections-filters.component.html new file mode 100644 index 000000000..f504d2704 --- /dev/null +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.html @@ -0,0 +1,43 @@ +
+ + + {{ 'collections.filters.programArea.label' | translate }} + + + + + + + {{ 'collections.filters.collectedType.label' | translate }} + + + + + +
diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.scss b/src/app/features/collections/components/collections-filters/collections-filters.component.scss new file mode 100644 index 000000000..814224024 --- /dev/null +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.scss @@ -0,0 +1,16 @@ +@use "assets/styles/variables" as var; +@use "assets/styles/mixins" as mix; + +:host { + width: 35%; + + .filters { + border: 1px solid var.$grey-2; + border-radius: mix.rem(12px); + padding: 0 mix.rem(20px); + display: flex; + flex-direction: column; + row-gap: 0.8rem; + height: fit-content; + } +} diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts b/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts new file mode 100644 index 000000000..79caa341d --- /dev/null +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsFiltersComponent } from './collections-filters.component'; + +describe('CollectionsFiltersComponent', () => { + let component: CollectionsFiltersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsFiltersComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsFiltersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.ts b/src/app/features/collections/components/collections-filters/collections-filters.component.ts new file mode 100644 index 000000000..a7edd142e --- /dev/null +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.ts @@ -0,0 +1,81 @@ +import { createDispatchMap, select } from '@ngxs/store'; + +import { TranslatePipe } from '@ngx-translate/core'; + +import { Accordion, AccordionContent, AccordionHeader, AccordionPanel } from 'primeng/accordion'; +import { MultiSelect, MultiSelectChangeEvent } from 'primeng/multiselect'; + +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { CollectionsSelectors } from '@osf/features/collections/store'; +import { SetCollectedTypeFilters, SetProgramAreaFilters } from '@osf/features/collections/store/collections.actions'; + +@Component({ + selector: 'osf-collections-filters', + imports: [FormsModule, MultiSelect, Accordion, AccordionContent, AccordionHeader, AccordionPanel, TranslatePipe], + templateUrl: './collections-filters.component.html', + styleUrl: './collections-filters.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsFiltersComponent { + protected selectedProgramAreaFilters = select(CollectionsSelectors.getProgramAreaFilters); + protected selectedCollectedTypeFilters = select(CollectionsSelectors.getCollectedTypeFilters); + protected actions = createDispatchMap({ + setProgramAreaFilters: SetProgramAreaFilters, + setCollectedTypeFilters: SetCollectedTypeFilters, + }); + + // Mocked filter options data + protected programAreaFilterOptions = [ + { label: 'Public Policy', value: 'Public Policy' }, + { label: 'Child Welfare', value: 'Child Welfare' }, + { label: 'Criminal Justice', value: 'Criminal Justice' }, + { label: 'Medicine', value: 'Medicine' }, + { label: 'Public Health', value: 'Public Health' }, + { label: 'Social Work', value: 'Social Work' }, + { label: 'Nursing', value: 'Nursing' }, + { label: 'Education', value: 'Education' }, + { label: 'Law & Jurisprudence', value: 'Law & Jurisprudence' }, + { label: 'N/A', value: 'N/A' }, + ]; + + protected collectedTypeFilterOptions = [ + { label: 'Experiments', value: 'Experiments' }, + { label: 'Interviews', value: 'Interviews' }, + { label: 'Grounded Theory', value: 'Grounded Theory' }, + { label: 'Action Research', value: 'Action Research' }, + { label: 'Case Studies', value: 'Case Studies' }, + { label: 'Direct Observation', value: 'Direct Observation' }, + { label: 'Document Analysis', value: 'Document Analysis' }, + { label: 'Interpretive Research', value: 'Interpretive Research' }, + { label: 'Participatory Action Research', value: 'Participatory Action Research' }, + { label: 'Event-Sampling', value: 'Event-Sampling' }, + { label: 'Surveys', value: 'Surveys' }, + { label: 'Quasi-Experiments', value: 'Quasi-Experiments' }, + { label: 'Ethnography', value: 'Ethnography' }, + { label: 'Social Network Analysis', value: 'Social Network Analysis' }, + { label: 'Critical Research Methods', value: 'Critical Research Methods' }, + { label: 'Design Research', value: 'Design Research' }, + { label: 'Discourse Analysis', value: 'Discourse Analysis' }, + { label: 'Research Synthesis', value: 'Research Synthesis' }, + ]; + + setProgramAreaFilters($event: MultiSelectChangeEvent): void { + const filters = $event.value; + this.actions.setProgramAreaFilters(filters); + } + + setCollectedTypeFilters($event: MultiSelectChangeEvent): void { + const filters = $event.value; + this.actions.setCollectedTypeFilters(filters); + } + + clearProgramAreaFilters(): void { + this.actions.setProgramAreaFilters([]); + } + + clearCollectedTypeFilters(): void { + this.actions.setCollectedTypeFilters([]); + } +} diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.html b/src/app/features/collections/components/collections-main-content/collections-main-content.component.html new file mode 100644 index 000000000..25c026fa1 --- /dev/null +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.html @@ -0,0 +1,74 @@ +
+
+ @if (searchCount() > 10000) { +

{{ 'collections.searchResults.10000results' | translate }}

+ } @else if (searchCount() > 0) { +

{{ searchCount() }} {{ 'collections.searchResults.results' | translate }}

+ } @else { +

{{ 'collections.searchResults.noResults' | translate }}

+ } +
+ +
+ @if (isWeb()) { +

{{ 'collections.filters.sort.label' | translate }}

+ + } @else { + filter by + + sort by + } +
+
+ +@if (isFiltersOpen()) { +
+ +
+} @else if (isSortingOpen()) { +
+ @for (option of sortOptions; track option.value) { +
+ {{ option.label }} +
+ } +
+} @else { + @if (isAnyFilterSelected()) { + + } +} + +
+ @if (isWeb()) { + + } + + +
diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss b/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss new file mode 100644 index 000000000..4a1a10512 --- /dev/null +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss @@ -0,0 +1,16 @@ +@use "assets/styles/variables" as var; +@use "assets/styles/mixins" as mix; + +.sort-card { + @include mix.flex-center; + width: 100%; + height: mix.rem(48px); + border: 1px solid var.$grey-2; + border-radius: mix.rem(12px); + padding: 0 mix.rem(28px); + cursor: pointer; +} + +.card-selected { + background: var.$bg-blue-2; +} diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts new file mode 100644 index 000000000..975cc7318 --- /dev/null +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsMainContentComponent } from './collections-main-content.component'; + +describe('CollectionsSearchComponent', () => { + let component: CollectionsMainContentComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsMainContentComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsMainContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts new file mode 100644 index 000000000..1ce992531 --- /dev/null +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts @@ -0,0 +1,95 @@ +import { select } from '@ngxs/store'; + +import { TranslatePipe } from '@ngx-translate/core'; + +import { Select } from 'primeng/select'; + +import { NgOptimizedImage } from '@angular/common'; +import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { FormsModule } from '@angular/forms'; + +import { CollectionsFilterChipsComponent } from '@osf/features/collections/components/collections-filter-chips/collections-filter-chips.component'; +import { CollectionsFiltersComponent } from '@osf/features/collections/components/collections-filters/collections-filters.component'; +import { CollectionsSearchResultsComponent } from '@osf/features/collections/components/collections-search-results/collections-search-results.component'; +import { CollectionsSelectors } from '@osf/features/collections/store'; +import { SORT_OPTIONS } from '@osf/features/collections/utils/sort-options.const'; +import { IS_WEB } from '@shared/utils'; + +@Component({ + selector: 'osf-collections-main-content', + imports: [ + NgOptimizedImage, + Select, + FormsModule, + CollectionsFiltersComponent, + CollectionsSearchResultsComponent, + CollectionsFilterChipsComponent, + TranslatePipe, + ], + templateUrl: './collections-main-content.component.html', + styleUrl: './collections-main-content.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsMainContentComponent { + protected readonly sortOptions = SORT_OPTIONS; + protected selectedSort = signal('-relevance'); + protected searchCount = signal(3); + + protected isWeb = toSignal(inject(IS_WEB)); + + protected isFiltersOpen = signal(false); + protected isSortingOpen = signal(false); + + protected filters = select(CollectionsSelectors.getAllFilters); + protected filtersOptions = select(CollectionsSelectors.getAllFiltersOptions); + + protected isAnyFilterSelected = computed(() => { + const currentFilters = this.filters(); + return ( + currentFilters.programArea.length || + currentFilters.status.length || + currentFilters.collectedType.length || + currentFilters.dataType.length || + currentFilters.disease.length || + currentFilters.gradeLevels.length || + currentFilters.issue.length || + currentFilters.reviewsState.length || + currentFilters.schoolType.length || + currentFilters.studyDesign.length || + currentFilters.volume.length + ); + }); + + protected isAnyFilterOptions = computed(() => { + const currentOptions = this.filtersOptions(); + return ( + currentOptions.programArea.length || + currentOptions.status.length || + currentOptions.collectedType.length || + currentOptions.dataType.length || + currentOptions.disease.length || + currentOptions.gradeLevels.length || + currentOptions.issue.length || + currentOptions.reviewsState.length || + currentOptions.schoolType.length || + currentOptions.studyDesign.length || + currentOptions.volume.length + ); + }); + + protected openFilters(): void { + this.isFiltersOpen.set(!this.isFiltersOpen()); + this.isSortingOpen.set(false); + } + + protected openSorting(): void { + this.isSortingOpen.set(!this.isSortingOpen()); + this.isFiltersOpen.set(false); + } + + protected selectSort(value: string): void { + this.selectedSort.set(value); + this.openSorting(); + } +} diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html new file mode 100644 index 000000000..4af5f67c1 --- /dev/null +++ b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html @@ -0,0 +1,27 @@ +@let item = cardItem(); + +
+

{{ item?.title }}

+

+ by + @for (contributor of item?.contributors; track contributor.id) { + {{ contributor.name }}{{ $last ? '' : ', ' }} + } +

+

{{ item?.description }}

+

+ {{ 'collections.common.dateCreated' | translate }} + {{ item?.dateCreated | date: 'longDate' }} + | + {{ 'collections.common.dateModified' | translate }} + {{ item?.dateModified | date: 'longDate' }} +

+
+ @for (attribute of presentSubmissionAttributes(); track attribute.key) { + @if (!$first) { + | + } + {{ attribute.label }}: {{ attribute.value }} + } +
+
diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss new file mode 100644 index 000000000..858297a8a --- /dev/null +++ b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss @@ -0,0 +1,30 @@ +@use "assets/styles/variables" as var; +@use "assets/styles/mixins" as mix; + +:host { + width: 100%; + flex: 1; + + .card { + border: 1px solid var.$grey-2; + border-radius: mix.rem(8px); + + .card-title { + font-size: mix.rem(18px); + } + + .card-description { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + line-clamp: 2; + line-height: mix.rem(28px); + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } + + .separator { + margin: 0 mix.rem(6px); + } + } +} diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts new file mode 100644 index 000000000..56ff9143c --- /dev/null +++ b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsSearchResultCardComponent } from './collections-search-result-card.component'; + +describe('CollectionsResultCardComponent', () => { + let component: CollectionsSearchResultCardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsSearchResultCardComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsSearchResultCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts new file mode 100644 index 000000000..7209eaad2 --- /dev/null +++ b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts @@ -0,0 +1,28 @@ +import { TranslatePipe } from '@ngx-translate/core'; + +import { DatePipe } from '@angular/common'; +import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; + +import { CollectionSearchResultCard } from '@osf/features/collections/models/collection-search-result-card.models'; +import { SUBMISSION_ATTRIBUTES } from '@osf/features/collections/utils/submission-attributes.const'; + +@Component({ + selector: 'osf-collections-search-result-card', + imports: [DatePipe, TranslatePipe], + templateUrl: './collections-search-result-card.component.html', + styleUrl: './collections-search-result-card.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsSearchResultCardComponent { + cardItem = input.required(); + + protected presentSubmissionAttributes = computed(() => { + const item = this.cardItem(); + if (!item) return []; + + return SUBMISSION_ATTRIBUTES.map((attribute) => ({ + ...attribute, + value: item[attribute.key as keyof CollectionSearchResultCard] as string, + })).filter((attribute) => attribute.value); + }); +} diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.html b/src/app/features/collections/components/collections-search-results/collections-search-results.component.html new file mode 100644 index 000000000..70326a14d --- /dev/null +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.html @@ -0,0 +1,13 @@ + + +
+ @if (items.length) { + @for (item of items; track item.id) { + + } + + + } +
+
+
diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss b/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss new file mode 100644 index 000000000..b9bc65ea4 --- /dev/null +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss @@ -0,0 +1,3 @@ +:host { + width: 100%; +} diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts new file mode 100644 index 000000000..760e1fc86 --- /dev/null +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsSearchResultsComponent } from './collections-search-results.component'; + +describe('CollectionsResultsComponent', () => { + let component: CollectionsSearchResultsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsSearchResultsComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsSearchResultsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts new file mode 100644 index 000000000..71eb6b152 --- /dev/null +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts @@ -0,0 +1,86 @@ +import { DataView } from 'primeng/dataview'; +import { Paginator } from 'primeng/paginator'; + +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +import { CollectionsSearchResultCardComponent } from '@osf/features/collections/components/collections-search-result-card/collections-search-result-card.component'; +import { CollectionSearchResultCard } from '@osf/features/collections/models/collection-search-result-card.models'; + +@Component({ + selector: 'osf-collections-search-results', + imports: [DataView, CollectionsSearchResultCardComponent, Paginator], + templateUrl: './collections-search-results.component.html', + styleUrl: './collections-search-results.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsSearchResultsComponent { + // Mocked search results data + protected searchResults: CollectionSearchResultCard[] = [ + { + id: '1', + title: 'Pseudo-Random Sonications For Brain HIFU', + description: + 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [ + { id: '1', name: 'Lin Wang' }, + { id: '2', name: 'Roman Nastyuk' }, + ], + programArea: 'Technica', + status: 'Completed', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, + { + id: '2', + title: 'Simulation Of Transcranial FUS Propagation', + description: + "While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, there are currently no precise tools for patient's selection and treatment planning. in this project, focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders", + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [{ id: '1', name: 'Lin Wang' }], + programArea: 'Technica', + status: 'Active', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, + { + id: '3', + title: 'Sonications For Brain HIFU', + description: + 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [{ id: '2', name: 'Roman Nastyuk' }], + programArea: 'Technica', + status: 'Completed', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, + ]; +} diff --git a/src/app/features/collections/models/collection-search-result-card.models.ts b/src/app/features/collections/models/collection-search-result-card.models.ts new file mode 100644 index 000000000..bf192de44 --- /dev/null +++ b/src/app/features/collections/models/collection-search-result-card.models.ts @@ -0,0 +1,25 @@ +export interface CollectionSearchResultCard { + id: string; + title: string; + description?: string; + dateCreated: Date; + dateModified: Date; + category: string; + contributors: Contributor[]; + programArea: string; + collectedType: string; + dataType: string; + disease: string; + gradeLevels: string; + issue: string; + reviewsState: string; + schoolType: string; + status: string; + studyDesign: string; + volume: string; +} + +interface Contributor { + id: string; + name: string; +} diff --git a/src/app/features/collections/models/index.ts b/src/app/features/collections/models/index.ts index 81e640d13..5fc921fd5 100644 --- a/src/app/features/collections/models/index.ts +++ b/src/app/features/collections/models/index.ts @@ -1 +1,2 @@ +export * from './collection-search-result-card.models'; export * from './collections.models'; diff --git a/src/app/features/collections/store/collections.actions.ts b/src/app/features/collections/store/collections.actions.ts index 6288b04a0..036d0a3ed 100644 --- a/src/app/features/collections/store/collections.actions.ts +++ b/src/app/features/collections/store/collections.actions.ts @@ -23,3 +23,58 @@ export class RemoveProjectFromBookmarks { export class ClearCollections { static readonly type = '[Collections] Clear Collections'; } + +export class SetProgramAreaFilters { + static readonly type = '[Collections] Set Program Area Filters'; + constructor(public programAreaFilters: string[]) {} +} + +export class SetCollectedTypeFilters { + static readonly type = '[Collections] Set Collected Type Filters'; + constructor(public collectedTypeFilters: string[]) {} +} + +export class SetStatusFilters { + static readonly type = '[Collections] Set Status Filters'; + constructor(public statusFilters: string[]) {} +} + +export class SetDataTypeFilters { + static readonly type = '[Collections] Set Data Type Filters'; + constructor(public dataTypeFilters: string[]) {} +} + +export class SetDiseaseFilters { + static readonly type = '[Collections] Set Disease Filters'; + constructor(public diseaseFilters: string[]) {} +} + +export class SetGradeLevelsFilters { + static readonly type = '[Collections] Set Grade Levels Filters'; + constructor(public gradeLevelsFilters: string[]) {} +} + +export class SetIssueFilters { + static readonly type = '[Collections] Set Issue Filters'; + constructor(public issueFilters: string[]) {} +} + +export class SetReviewsStateFilters { + static readonly type = '[Collections] Set Reviews State Filters'; + constructor(public reviewsStateFilters: string[]) {} +} + +export class SetSchoolTypeFilters { + static readonly type = '[Collections] Set School Type Filters'; + constructor(public schoolTypeFilters: string[]) {} +} + +export class SetStudyDesignFilters { + static readonly type = '[Collections] Set Study Design Filters'; + constructor(public studyDesignFilters: string[]) {} +} + +export class SetVolumeFilters { + static readonly type = '[Collections] Set Volume Filters'; + constructor(public volumeFilters: string[]) {} +} diff --git a/src/app/features/collections/store/collections.model.ts b/src/app/features/collections/store/collections.model.ts index bb7aff785..b3d8ddde2 100644 --- a/src/app/features/collections/store/collections.model.ts +++ b/src/app/features/collections/store/collections.model.ts @@ -1,5 +1,21 @@ import { AsyncStateModel } from '@osf/shared/models/store'; +export interface CollectionsFilters { + programArea: string[]; + status: string[]; + collectedType: string[]; + dataType: string[]; + disease: string[]; + gradeLevels: string[]; + issue: string[]; + reviewsState: string[]; + schoolType: string[]; + studyDesign: string[]; + volume: string[]; +} + export interface CollectionsStateModel { bookmarksId: AsyncStateModel; + filters: CollectionsFilters; + filtersOptions: CollectionsFilters; } diff --git a/src/app/features/collections/store/collections.selectors.ts b/src/app/features/collections/store/collections.selectors.ts index fe7302d8e..fb09b395d 100644 --- a/src/app/features/collections/store/collections.selectors.ts +++ b/src/app/features/collections/store/collections.selectors.ts @@ -1,6 +1,6 @@ import { Selector } from '@ngxs/store'; -import { CollectionsStateModel } from './collections.model'; +import { CollectionsFilters, CollectionsStateModel } from './collections.model'; import { CollectionsState } from './collections.state'; export class CollectionsSelectors { @@ -18,4 +18,69 @@ export class CollectionsSelectors { static getBookmarksCollectionIdSubmitting(state: CollectionsStateModel) { return state.bookmarksId.isSubmitting; } + + @Selector([CollectionsState]) + static getAllFilters(state: CollectionsStateModel): CollectionsFilters { + return state.filters; + } + + @Selector([CollectionsState]) + static getStatusFilters(state: CollectionsStateModel): string[] { + return state.filters.status; + } + + @Selector([CollectionsState]) + static getProgramAreaFilters(state: CollectionsStateModel): string[] { + return state.filters.programArea; + } + + @Selector([CollectionsState]) + static getCollectedTypeFilters(state: CollectionsStateModel): string[] { + return state.filters.collectedType; + } + + @Selector([CollectionsState]) + static getDataTypeFilters(state: CollectionsStateModel): string[] { + return state.filters.dataType; + } + + @Selector([CollectionsState]) + static getDiseaseFilters(state: CollectionsStateModel): string[] { + return state.filters.disease; + } + + @Selector([CollectionsState]) + static getGradeLevelsFilters(state: CollectionsStateModel): string[] { + return state.filters.gradeLevels; + } + + @Selector([CollectionsState]) + static getIssueFilters(state: CollectionsStateModel): string[] { + return state.filters.issue; + } + + @Selector([CollectionsState]) + static getReviewsStateFilters(state: CollectionsStateModel): string[] { + return state.filters.reviewsState; + } + + @Selector([CollectionsState]) + static getSchoolTypeFilters(state: CollectionsStateModel): string[] { + return state.filters.schoolType; + } + + @Selector([CollectionsState]) + static getStudyDesignFilters(state: CollectionsStateModel): string[] { + return state.filters.studyDesign; + } + + @Selector([CollectionsState]) + static getVolumeFilters(state: CollectionsStateModel): string[] { + return state.filters.volume; + } + + @Selector([CollectionsState]) + static getAllFiltersOptions(state: CollectionsStateModel): CollectionsFilters { + return state.filtersOptions; + } } diff --git a/src/app/features/collections/store/collections.state.ts b/src/app/features/collections/store/collections.state.ts index 609f2925b..4319409db 100644 --- a/src/app/features/collections/store/collections.state.ts +++ b/src/app/features/collections/store/collections.state.ts @@ -11,9 +11,34 @@ import { ClearCollections, GetBookmarksCollectionId, RemoveProjectFromBookmarks, + SetCollectedTypeFilters, + SetDataTypeFilters, + SetDiseaseFilters, + SetGradeLevelsFilters, + SetIssueFilters, + SetProgramAreaFilters, + SetReviewsStateFilters, + SetSchoolTypeFilters, + SetStatusFilters, + SetStudyDesignFilters, + SetVolumeFilters, } from './collections.actions'; import { CollectionsStateModel } from './collections.model'; +const FILTERS_DEFAULTS = { + programArea: [], + status: [], + collectedType: [], + dataType: [], + disease: [], + gradeLevels: [], + issue: [], + reviewsState: [], + schoolType: [], + studyDesign: [], + volume: [], +}; + const COLLECTIONS_DEFAULTS: CollectionsStateModel = { bookmarksId: { data: '', @@ -21,6 +46,8 @@ const COLLECTIONS_DEFAULTS: CollectionsStateModel = { isSubmitting: false, error: null, }, + filters: FILTERS_DEFAULTS, + filtersOptions: FILTERS_DEFAULTS, }; @State({ @@ -106,6 +133,128 @@ export class CollectionsState { ctx.patchState(COLLECTIONS_DEFAULTS); } + // Filter Actions + @Action(SetProgramAreaFilters) + setProgramAreaFilters(ctx: StateContext, action: SetProgramAreaFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + programArea: action.programAreaFilters, + }, + }); + } + + @Action(SetCollectedTypeFilters) + setCollectedTypesFilters(ctx: StateContext, action: SetCollectedTypeFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + collectedType: action.collectedTypeFilters, + }, + }); + } + + @Action(SetStatusFilters) + setStatusFilters(ctx: StateContext, action: SetStatusFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + status: action.statusFilters, + }, + }); + } + + @Action(SetDataTypeFilters) + setDataTypeFilters(ctx: StateContext, action: SetDataTypeFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + dataType: action.dataTypeFilters, + }, + }); + } + + @Action(SetDiseaseFilters) + setDiseaseFilters(ctx: StateContext, action: SetDiseaseFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + disease: action.diseaseFilters, + }, + }); + } + + @Action(SetGradeLevelsFilters) + setGradeLevelsFilters(ctx: StateContext, action: SetGradeLevelsFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + gradeLevels: action.gradeLevelsFilters, + }, + }); + } + + @Action(SetIssueFilters) + setIssueFilters(ctx: StateContext, action: SetIssueFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + issue: action.issueFilters, + }, + }); + } + + @Action(SetReviewsStateFilters) + setReviewsStateFilters(ctx: StateContext, action: SetReviewsStateFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + reviewsState: action.reviewsStateFilters, + }, + }); + } + + @Action(SetSchoolTypeFilters) + setSchoolTypeFilters(ctx: StateContext, action: SetSchoolTypeFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + schoolType: action.schoolTypeFilters, + }, + }); + } + + @Action(SetStudyDesignFilters) + setStudyDesignFilters(ctx: StateContext, action: SetStudyDesignFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + studyDesign: action.studyDesignFilters, + }, + }); + } + + @Action(SetVolumeFilters) + setVolumeFilters(ctx: StateContext, action: SetVolumeFilters) { + const state = ctx.getState(); + ctx.patchState({ + filters: { + ...state.filters, + volume: action.volumeFilters, + }, + }); + } + private handleError(ctx: StateContext, section: keyof CollectionsStateModel, error: Error) { ctx.patchState({ [section]: { diff --git a/src/app/features/collections/utils/index.ts b/src/app/features/collections/utils/index.ts new file mode 100644 index 000000000..5161b6f95 --- /dev/null +++ b/src/app/features/collections/utils/index.ts @@ -0,0 +1 @@ +export * from './sort-options.const'; diff --git a/src/app/features/collections/utils/sort-options.const.ts b/src/app/features/collections/utils/sort-options.const.ts new file mode 100644 index 000000000..2b6377efc --- /dev/null +++ b/src/app/features/collections/utils/sort-options.const.ts @@ -0,0 +1,7 @@ +export const SORT_OPTIONS = [ + { label: 'Relevance', value: '-relevance' }, + { label: 'Date created (newest)', value: '-dateCreated' }, + { label: 'Date created (oldest)', value: 'dateCreated' }, + { label: 'Date modified (newest)', value: '-dateModified' }, + { label: 'Date modified (oldest)', value: 'dateModified' }, +]; diff --git a/src/app/features/collections/utils/submission-attributes.const.ts b/src/app/features/collections/utils/submission-attributes.const.ts new file mode 100644 index 000000000..a3aae7830 --- /dev/null +++ b/src/app/features/collections/utils/submission-attributes.const.ts @@ -0,0 +1,13 @@ +export const SUBMISSION_ATTRIBUTES = [ + { key: 'programArea', label: 'Program Area' }, + { key: 'collectedType', label: 'Type' }, + { key: 'dataType', label: 'Data Type' }, + { key: 'disease', label: 'Disease' }, + { key: 'gradeLevels', label: 'Grade Levels' }, + { key: 'issue', label: 'Issue' }, + { key: 'reviewsState', label: 'Reviews State' }, + { key: 'schoolType', label: 'School Type' }, + { key: 'status', label: 'Status' }, + { key: 'studyDesign', label: 'Study Design' }, + { key: 'volume', label: 'Volume' }, +]; diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index cf36b64ef..8a4640067 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -25,6 +25,7 @@ "meetings": "Meetings", "myProjects": "My Projects", "preprints": "Preprints", + "collections": "Collections", "donate": "Donate", "profileSettings": "Profile Settings", "accountSettings": "Account Settings", @@ -554,6 +555,83 @@ } } }, + "collections": { + "buttons": { + "addToCollection": "Add to Collection" + }, + "searchInput": { + "placeholder": "Enter search term(s) here" + }, + "filters": { + "programArea": { + "label": "Program Area", + "placeholder": "Select program areas", + "description": "Please select the program area from the dropdown below or start typing to find it" + }, + "status": { + "label": "Status", + "placeholder": "Select status", + "description": "Please select the status from the dropdown below or start typing to find it" + }, + "collectedType": { + "label": "Collected Type", + "placeholder": "Select collected types", + "description": "Please select the collected type from the dropdown below or start typing to find it" + }, + "dataType": { + "label": "Data Type", + "placeholder": "Select data types", + "description": "Please select the data type from the dropdown below or start typing to find it" + }, + "disease": { + "label": "Disease", + "placeholder": "Select diseases", + "description": "Please select the disease from the dropdown below or start typing to find it" + }, + "gradeLevels": { + "label": "Grade Levels", + "placeholder": "Select grade levels", + "description": "Please select the grade level from the dropdown below or start typing to find it" + }, + "issue": { + "label": "Issue", + "placeholder": "Select issues", + "description": "Please select the issue from the dropdown below or start typing to find it" + }, + "reviewsState": { + "label": "Reviews State", + "placeholder": "Select reviews states", + "description": "Please select the reviews state from the dropdown below or start typing to find it" + }, + "schoolType": { + "label": "School Type", + "placeholder": "Select school types", + "description": "Please select the school type from the dropdown below or start typing to find it" + }, + "studyDesign": { + "label": "Study Design", + "placeholder": "Select study designs", + "description": "Please select the study design from the dropdown below or start typing to find it" + }, + "volume": { + "label": "Volume", + "placeholder": "Select volumes", + "description": "Please select the volume from the dropdown below or start typing to find it" + }, + "sort": { + "label": "Sort by:" + } + }, + "searchResults": { + "noResults": "0 results", + "10000Results": "10,000+ results", + "results": "results" + }, + "common": { + "dateCreated": "Date Created:", + "dateModified": "Date Modified:" + } + }, "settings": { "developerApps": { "header": { diff --git a/src/assets/icons/dist/icons.css b/src/assets/icons/dist/icons.css index a48d6e24a..5ed8a2400 100644 --- a/src/assets/icons/dist/icons.css +++ b/src/assets/icons/dist/icons.css @@ -1,13 +1,11 @@ @font-face { - font-family: 'icons'; - src: - url('./icons.eot?2e4364c6b3c036b04fd69f71148f23a1#iefix') format('embedded-opentype'), - url('./icons.woff2?2e4364c6b3c036b04fd69f71148f23a1') format('woff2'), - url('./icons.woff?2e4364c6b3c036b04fd69f71148f23a1') format('woff'); + font-family: "icons"; + src: url("./icons.eot?5089ecbbc9bed1b09d80f14b2dfb8179#iefix") format("embedded-opentype"), + url("./icons.woff2?5089ecbbc9bed1b09d80f14b2dfb8179") format("woff2"), + url("./icons.woff?5089ecbbc9bed1b09d80f14b2dfb8179") format("woff"); } -i[class^='osf-icon-']:before, -i[class*=' osf-icon-']:before { +i[class^="osf-icon-"]:before, i[class*=" osf-icon-"]:before { font-family: icons !important; font-style: normal; font-weight: normal !important; @@ -19,215 +17,277 @@ i[class*=' osf-icon-']:before { } .osf-icon-withdrawn:before { - content: '\f101'; + content: "\f101"; } + .osf-icon-warning:before { - content: '\f102'; + content: "\f102"; } + .osf-icon-warning-sign:before { - content: '\f103'; + content: "\f103"; } + .osf-icon-upload:before { - content: '\f104'; + content: "\f104"; } + .osf-icon-trash:before { - content: '\f105'; + content: "\f105"; } + .osf-icon-support:before { - content: '\f106'; + content: "\f106"; } + .osf-icon-supplements:before { - content: '\f107'; -} -.osf-icon-sort:before { - content: '\f108'; + content: "\f107"; } + .osf-icon-sort-desc:before { - content: '\f109'; + content: "\f108"; } + .osf-icon-sort-asc:before { - content: '\f10a'; + content: "\f109"; } + .osf-icon-sort-asc-grey:before { - content: '\f10b'; + content: "\f10a"; } + .osf-icon-share:before { - content: '\f10c'; + content: "\f10b"; } + .osf-icon-settings:before { - content: '\f10d'; + content: "\f10c"; } + .osf-icon-search:before { - content: '\f10e'; + content: "\f10d"; } + .osf-icon-search-2:before { - content: '\f10f'; + content: "\f10e"; } + .osf-icon-rejected:before { - content: '\f110'; + content: "\f10f"; } + .osf-icon-registries:before { - content: '\f111'; + content: "\f110"; } + .osf-icon-quotes:before { - content: '\f112'; + content: "\f111"; } + .osf-icon-profile:before { - content: '\f113'; + content: "\f112"; } + .osf-icon-preprints:before { - content: '\f114'; + content: "\f113"; } + .osf-icon-plus:before { - content: '\f115'; + content: "\f114"; } + .osf-icon-pending:before { - content: '\f116'; + content: "\f115"; } + .osf-icon-pdf:before { - content: '\f117'; + content: "\f116"; } + .osf-icon-papers:before { - content: '\f118'; + content: "\f117"; } + .osf-icon-padlock:before { - content: '\f119'; + content: "\f118"; } + .osf-icon-padlock-unlock:before { - content: '\f11a'; + content: "\f119"; } + .osf-icon-my-projects:before { - content: '\f11b'; + content: "\f11a"; } + .osf-icon-minus:before { - content: '\f11c'; + content: "\f11b"; } + .osf-icon-menu:before { - content: '\f11d'; + content: "\f11c"; } + .osf-icon-meetings:before { - content: '\f11e'; + content: "\f11d"; } + .osf-icon-materials:before { - content: '\f11f'; + content: "\f11e"; } + .osf-icon-list:before { - content: '\f120'; + content: "\f11f"; } + .osf-icon-link:before { - content: '\f121'; + content: "\f120"; } + .osf-icon-last:before { - content: '\f122'; + content: "\f121"; } + .osf-icon-institutions:before { - content: '\f123'; + content: "\f122"; } + .osf-icon-institution:before { - content: '\f124'; + content: "\f123"; } + .osf-icon-information:before { - content: '\f125'; + content: "\f124"; } + .osf-icon-image:before { - content: '\f126'; + content: "\f125"; } + .osf-icon-home:before { - content: '\f127'; + content: "\f126"; } + .osf-icon-home-2:before { - content: '\f128'; + content: "\f127"; } + .osf-icon-help:before { - content: '\f129'; + content: "\f128"; } + .osf-icon-folder:before { - content: '\f12a'; + content: "\f129"; } + .osf-icon-first:before { - content: '\f12b'; + content: "\f12a"; } + .osf-icon-filter:before { - content: '\f12c'; + content: "\f12b"; } + .osf-icon-eye-view:before { - content: '\f12d'; + content: "\f12c"; } + .osf-icon-eye-hidden:before { - content: '\f12e'; + content: "\f12d"; } + .osf-icon-email:before { - content: '\f12f'; + content: "\f12e"; } + .osf-icon-duplicate:before { - content: '\f130'; + content: "\f12f"; } + .osf-icon-download:before { - content: '\f131'; + content: "\f130"; } + .osf-icon-double-arrow-left:before { - content: '\f132'; + content: "\f131"; } + .osf-icon-dots:before { - content: '\f133'; + content: "\f132"; } + .osf-icon-donate:before { - content: '\f134'; + content: "\f133"; } + .osf-icon-doc:before { - content: '\f135'; + content: "\f134"; } + .osf-icon-diagram:before { - content: '\f136'; + content: "\f135"; } + .osf-icon-data:before { - content: '\f137'; + content: "\f136"; } + .osf-icon-customize:before { - content: '\f138'; -} -.osf-icon-cos-shield:before { - content: '\f139'; + content: "\f137"; } + .osf-icon-copy:before { - content: '\f13a'; + content: "\f138"; } + .osf-icon-contact:before { - content: '\f13b'; + content: "\f139"; } + .osf-icon-collections:before { - content: '\f13c'; + content: "\f13a"; } + .osf-icon-code:before { - content: '\f13d'; + content: "\f13b"; } + .osf-icon-close:before { - content: '\f13e'; + content: "\f13c"; } + .osf-icon-chevron-right:before { - content: '\f13f'; + content: "\f13d"; } + .osf-icon-chevron-left:before { - content: '\f140'; + content: "\f13e"; } + .osf-icon-calendar-silhouette:before { - content: '\f141'; + content: "\f13f"; } + .osf-icon-bookmark:before { - content: '\f142'; + content: "\f140"; } + .osf-icon-bookmark-fill:before { - content: '\f143'; + content: "\f141"; } + .osf-icon-arrow:before { - content: '\f144'; + content: "\f142"; } + .osf-icon-arrow-left:before { - content: '\f145'; + content: "\f143"; } + .osf-icon-arrow-down:before { - content: '\f146'; + content: "\f144"; } + .osf-icon-accepted:before { - content: '\f147'; + content: "\f145"; } diff --git a/src/assets/icons/dist/icons.eot b/src/assets/icons/dist/icons.eot index 3fd895de369e68a569fd564fa5b17e625e5741a0..8db0dbdd8fe5f41162af76ac1041b26b48e7922d 100644 GIT binary patch delta 631 zcmXAmUr5tY6vxlKzrXu!zs=v+M(Gm&Eaz(e*{^L`keF)_Bq0^#LqWrBjo5O~A{)U7 zA|)hd7epvBBzhp$o+M(C=+Nt# zD(wDX3JbFF|aKz&};`6#(ro6H?)HX4!}Y1 zLI-q07j%OieC#yejCLZs&2O?daWB13jVQt^qD~ zL3*g}OanF0m6yvolzSlw&tQ|d$UW+!12jVyxHDXy`@~!MDSl0867oVxw2Hd;QLIYc zQdGJn73D^GO5QeP4YP(nN>(W=RpX#BV|-*>GWDB^rghb(M%8Kcy?NIB!*a!P-}1)t zyDnI_qVZab)~98($J#sXn#c(?1a@rR^B;2PJ<{ zckDc-oPM{%;r92`l2ednMV3`Ip)?b@FsE=_p<-UHFMRh*OZYii-yKHvGP~Ji^H@TnA!?JRiQ2SHW11>zskOBTVg(iJ12i_(h^b9&zz0f1 zN)hp38SqdG-aND**z_POD#b&U3dP4oFGW167!fT}yZ+l%5uM%d|G)n+-wZRmce-b? zY)2AcV$Bds(Xqk4XG6`!VhaGd0sx1)deZrCd!C*L5at0atw(cbj@%d>{Q)3P160jt zyVIG@dpEvg?<^vf#e}evWRc%TgtI+`)7zKpWz>6*aOHZt(gz>zzJ>Ffv3|KHeL7F} z!Wh<;U|ew`-P7%PaX2i3;!7+Y`)RR_z zm)s`pJSQ{>y3Q*^Kc5sv_&#y#s@cV6fY%@{vKV>=XU_r!+y`1}zJ&&*7TAnBjQ7!bet}9(JF0=0F)WUDe$H}= zD5Wo!&17j97l@cZX(&fcKo#F1U03TdYA}J)bJAq7yahu9;7ydgb!~^1I8mBorZb?}#SRS!B>ty5Xxs;WLr5TyZ0eP4Fz?!m-D1N0yxoY#< z4%>!ppX?s{27BKAR^6ozs1pwASnJ3*TbvhNLB&<;+ThB$MqKaQ1MYG6jQgV&(zaLO{6xGWJEGZG7@6f0?DY?8%?e?UBDvC ziY)thMhOzBG^mJTQPOq&IjO-baN=1v!(KQH$DshwxF+F6Nmfll5fn}NlBxBii6p!} zEEs7A7NV7*h|&0W{HO2#R @@ -110,14 +113,6 @@

icons

supplements -
- - - -
- sort -
-
@@ -502,14 +497,6 @@

icons

customize
-
- - - -
- cos-shield -
-
diff --git a/src/assets/icons/dist/icons.json b/src/assets/icons/dist/icons.json index acb91a04d..95dd51d82 100644 --- a/src/assets/icons/dist/icons.json +++ b/src/assets/icons/dist/icons.json @@ -1,73 +1,71 @@ { - "withdrawn": 61697, - "warning": 61698, - "warning-sign": 61699, - "upload": 61700, - "trash": 61701, - "support": 61702, - "supplements": 61703, - "sort": 61704, - "sort-desc": 61705, - "sort-asc": 61706, - "sort-asc-grey": 61707, - "share": 61708, - "settings": 61709, - "search": 61710, - "search-2": 61711, - "rejected": 61712, - "registries": 61713, - "quotes": 61714, - "profile": 61715, - "preprints": 61716, - "plus": 61717, - "pending": 61718, - "pdf": 61719, - "papers": 61720, - "padlock": 61721, - "padlock-unlock": 61722, - "my-projects": 61723, - "minus": 61724, - "menu": 61725, - "meetings": 61726, - "materials": 61727, - "list": 61728, - "link": 61729, - "last": 61730, - "institutions": 61731, - "institution": 61732, - "information": 61733, - "image": 61734, - "home": 61735, - "home-2": 61736, - "help": 61737, - "folder": 61738, - "first": 61739, - "filter": 61740, - "eye-view": 61741, - "eye-hidden": 61742, - "email": 61743, - "duplicate": 61744, - "download": 61745, - "double-arrow-left": 61746, - "dots": 61747, - "donate": 61748, - "doc": 61749, - "diagram": 61750, - "data": 61751, - "customize": 61752, - "cos-shield": 61753, - "copy": 61754, - "contact": 61755, - "collections": 61756, - "code": 61757, - "close": 61758, - "chevron-right": 61759, - "chevron-left": 61760, - "calendar-silhouette": 61761, - "bookmark": 61762, - "bookmark-fill": 61763, - "arrow": 61764, - "arrow-left": 61765, - "arrow-down": 61766, - "accepted": 61767 + "withdrawn": 61697, + "warning": 61698, + "warning-sign": 61699, + "upload": 61700, + "trash": 61701, + "support": 61702, + "supplements": 61703, + "sort-desc": 61704, + "sort-asc": 61705, + "sort-asc-grey": 61706, + "share": 61707, + "settings": 61708, + "search": 61709, + "search-2": 61710, + "rejected": 61711, + "registries": 61712, + "quotes": 61713, + "profile": 61714, + "preprints": 61715, + "plus": 61716, + "pending": 61717, + "pdf": 61718, + "papers": 61719, + "padlock": 61720, + "padlock-unlock": 61721, + "my-projects": 61722, + "minus": 61723, + "menu": 61724, + "meetings": 61725, + "materials": 61726, + "list": 61727, + "link": 61728, + "last": 61729, + "institutions": 61730, + "institution": 61731, + "information": 61732, + "image": 61733, + "home": 61734, + "home-2": 61735, + "help": 61736, + "folder": 61737, + "first": 61738, + "filter": 61739, + "eye-view": 61740, + "eye-hidden": 61741, + "email": 61742, + "duplicate": 61743, + "download": 61744, + "double-arrow-left": 61745, + "dots": 61746, + "donate": 61747, + "doc": 61748, + "diagram": 61749, + "data": 61750, + "customize": 61751, + "copy": 61752, + "contact": 61753, + "collections": 61754, + "code": 61755, + "close": 61756, + "chevron-right": 61757, + "chevron-left": 61758, + "calendar-silhouette": 61759, + "bookmark": 61760, + "bookmark-fill": 61761, + "arrow": 61762, + "arrow-left": 61763, + "arrow-down": 61764, + "accepted": 61765 } diff --git a/src/assets/icons/dist/icons.ts b/src/assets/icons/dist/icons.ts index ada611307..7ac49e6f0 100644 --- a/src/assets/icons/dist/icons.ts +++ b/src/assets/icons/dist/icons.ts @@ -6,7 +6,6 @@ export type IconsId = | 'trash' | 'support' | 'supplements' - | 'sort' | 'sort-desc' | 'sort-asc' | 'sort-asc-grey' @@ -55,7 +54,6 @@ export type IconsId = | 'diagram' | 'data' | 'customize' - | 'cos-shield' | 'copy' | 'contact' | 'collections' @@ -79,7 +77,6 @@ export type IconsKey = | 'Trash' | 'Support' | 'Supplements' - | 'Sort' | 'SortDesc' | 'SortAsc' | 'SortAscGrey' @@ -128,7 +125,6 @@ export type IconsKey = | 'Diagram' | 'Data' | 'Customize' - | 'CosShield' | 'Copy' | 'Contact' | 'Collections' @@ -152,7 +148,6 @@ export enum Icons { Trash = 'trash', Support = 'support', Supplements = 'supplements', - Sort = 'sort', SortDesc = 'sort-desc', SortAsc = 'sort-asc', SortAscGrey = 'sort-asc-grey', @@ -201,7 +196,6 @@ export enum Icons { Diagram = 'diagram', Data = 'data', Customize = 'customize', - CosShield = 'cos-shield', Copy = 'copy', Contact = 'contact', Collections = 'collections', @@ -226,68 +220,66 @@ export const ICONS_CODEPOINTS: Record = { [Icons.Trash]: '61701', [Icons.Support]: '61702', [Icons.Supplements]: '61703', - [Icons.Sort]: '61704', - [Icons.SortDesc]: '61705', - [Icons.SortAsc]: '61706', - [Icons.SortAscGrey]: '61707', - [Icons.Share]: '61708', - [Icons.Settings]: '61709', - [Icons.Search]: '61710', - [Icons.Search2]: '61711', - [Icons.Rejected]: '61712', - [Icons.Registries]: '61713', - [Icons.Quotes]: '61714', - [Icons.Profile]: '61715', - [Icons.Preprints]: '61716', - [Icons.Plus]: '61717', - [Icons.Pending]: '61718', - [Icons.Pdf]: '61719', - [Icons.Papers]: '61720', - [Icons.Padlock]: '61721', - [Icons.PadlockUnlock]: '61722', - [Icons.MyProjects]: '61723', - [Icons.Minus]: '61724', - [Icons.Menu]: '61725', - [Icons.Meetings]: '61726', - [Icons.Materials]: '61727', - [Icons.List]: '61728', - [Icons.Link]: '61729', - [Icons.Last]: '61730', - [Icons.Institutions]: '61731', - [Icons.Institution]: '61732', - [Icons.Information]: '61733', - [Icons.Image]: '61734', - [Icons.Home]: '61735', - [Icons.Home2]: '61736', - [Icons.Help]: '61737', - [Icons.Folder]: '61738', - [Icons.First]: '61739', - [Icons.Filter]: '61740', - [Icons.EyeView]: '61741', - [Icons.EyeHidden]: '61742', - [Icons.Email]: '61743', - [Icons.Duplicate]: '61744', - [Icons.Download]: '61745', - [Icons.DoubleArrowLeft]: '61746', - [Icons.Dots]: '61747', - [Icons.Donate]: '61748', - [Icons.Doc]: '61749', - [Icons.Diagram]: '61750', - [Icons.Data]: '61751', - [Icons.Customize]: '61752', - [Icons.CosShield]: '61753', - [Icons.Copy]: '61754', - [Icons.Contact]: '61755', - [Icons.Collections]: '61756', - [Icons.Code]: '61757', - [Icons.Close]: '61758', - [Icons.ChevronRight]: '61759', - [Icons.ChevronLeft]: '61760', - [Icons.CalendarSilhouette]: '61761', - [Icons.Bookmark]: '61762', - [Icons.BookmarkFill]: '61763', - [Icons.Arrow]: '61764', - [Icons.ArrowLeft]: '61765', - [Icons.ArrowDown]: '61766', - [Icons.Accepted]: '61767', + [Icons.SortDesc]: '61704', + [Icons.SortAsc]: '61705', + [Icons.SortAscGrey]: '61706', + [Icons.Share]: '61707', + [Icons.Settings]: '61708', + [Icons.Search]: '61709', + [Icons.Search2]: '61710', + [Icons.Rejected]: '61711', + [Icons.Registries]: '61712', + [Icons.Quotes]: '61713', + [Icons.Profile]: '61714', + [Icons.Preprints]: '61715', + [Icons.Plus]: '61716', + [Icons.Pending]: '61717', + [Icons.Pdf]: '61718', + [Icons.Papers]: '61719', + [Icons.Padlock]: '61720', + [Icons.PadlockUnlock]: '61721', + [Icons.MyProjects]: '61722', + [Icons.Minus]: '61723', + [Icons.Menu]: '61724', + [Icons.Meetings]: '61725', + [Icons.Materials]: '61726', + [Icons.List]: '61727', + [Icons.Link]: '61728', + [Icons.Last]: '61729', + [Icons.Institutions]: '61730', + [Icons.Institution]: '61731', + [Icons.Information]: '61732', + [Icons.Image]: '61733', + [Icons.Home]: '61734', + [Icons.Home2]: '61735', + [Icons.Help]: '61736', + [Icons.Folder]: '61737', + [Icons.First]: '61738', + [Icons.Filter]: '61739', + [Icons.EyeView]: '61740', + [Icons.EyeHidden]: '61741', + [Icons.Email]: '61742', + [Icons.Duplicate]: '61743', + [Icons.Download]: '61744', + [Icons.DoubleArrowLeft]: '61745', + [Icons.Dots]: '61746', + [Icons.Donate]: '61747', + [Icons.Doc]: '61748', + [Icons.Diagram]: '61749', + [Icons.Data]: '61750', + [Icons.Customize]: '61751', + [Icons.Copy]: '61752', + [Icons.Contact]: '61753', + [Icons.Collections]: '61754', + [Icons.Code]: '61755', + [Icons.Close]: '61756', + [Icons.ChevronRight]: '61757', + [Icons.ChevronLeft]: '61758', + [Icons.CalendarSilhouette]: '61759', + [Icons.Bookmark]: '61760', + [Icons.BookmarkFill]: '61761', + [Icons.Arrow]: '61762', + [Icons.ArrowLeft]: '61763', + [Icons.ArrowDown]: '61764', + [Icons.Accepted]: '61765', }; diff --git a/src/assets/icons/dist/icons.woff b/src/assets/icons/dist/icons.woff index cc86215c32fa48038f9555bbd3fbe45dbc57533c..8fd3eb2994d0e82eaa002e4360b5530f7d399d41 100644 GIT binary patch delta 6350 zcmV;<7%}IdHt;kQcTYw}00961000_r01E&B001%^krY3FKx1uTZ~y=ShyVZqi~s-y zDEAx$U1w~0W&i*K6aWAd6aWAupmm>;Luh4TWB>pbC;$KeG5`PoHdwo#`ejy)&Ke`=SI%ux>cVC%51CrVw)j`87ZF*qjVW#oC$v>nPQq5W|?E21r}Li znH5%9W1S5)*mlQ#4ASiYqaSVuv8qo$q+axL^fv6%VX{}aKQl#_;5~-@DG*XL&)K(Ec zP*DR(+B$#yz>t&{k=Butlv29x_nkYlv%9u~;qIO9ywADkeDCipVdu}Ee~Ip(gao8Y zNHRIcmR8t8ot1o+PRdez1zqSbb=#-v*|sFvmhH)tYo%$*!w7baDlz#p(>38G1|jEv zN_UW-krHWbCaf8M+TJq^Eot&df`{)WyCMAE=)MADhJJhfGjanOx{>Me{kGp){)BBh)HZEAEp0?ZeP`%rOs`P8?KmOf`sgkx1CfKT}2imyD5l za)8`GZYTF51vhA&CS{)%sGQtM_0IZ$z+|#O^=6U67m%)zoOjZ$Dvz+P_q(P1ZtV~G z))C966qAY#S;*L)t&T{?kw;WX9Z`QalvE^nM@T6;Tz>G~vTut85j%G}F{JR0Imewb zNL@b9BlEZ!LAoJ({S*${3_f&`Is%A?=ZEC4;mk;er+~y&FRFqZ-N- z+NR8ypmf4uluIU+Ve+QyD=N7=;c`ip?>4zn zS~jJA!ZA&8 zs5uRM-detLx%FV!NIWlTOg6?m>W($OFx@-^BHj_JW4gVy{M&<8Zw!*e8{+9jO*b(~ zH>`cBl|i}arGrbX>|W-=8};&zt$KeMSxM#mFkpl%=Qd!oEsFX>LR2cka(J}@=fNu# z4(nE`+}WbHzsE1^V&PEu78AbZ9O$)INda`nH0hBm$@SzGkcz-bsKB)zL7CSUx!@WK z?_M_4ty$iXSC=nYNI@m)5$j61We8!sfne>ICGQQdq``viTb6J4mHaKKE(w1+AReLL zSl;~s)2q-oV)|H@FP+o86iEu z{rZ=~F)VJ{_odt7PFY&6Yso@98%|7wv(fldaVHj*=UF0%p*S8v!^2SLMqV6KUNorvETRD$RIa@l`>9Bc09Lhxhn z4xaiBE&G4(mwYFvL?!>bI2OSD(iFm!M+GLJ2X%5Zuf+Y)b-ShlyULZ>z;qg@qQ(3p z|J*BiccO;Ab3OC#n~RVk13O89Jeeg+WCiEMGpd6$0fZH3f_Bo78{n9FXknyiYJl_y z`=9}=4yGg2?*tK0qg{X7JZ;+4F$-Rr`aT+Mrx9S$D?rPxV0t<@c@p89XdBzAIO$DK zdy_?(o6~YwRxnGXk}yrfM4gp`%uoiBv+&I!So1*leZ6@E18Q&g;^3%buExP11@YO{ zGlh87be=@J^z5$7lh0Ov!LXGzvmV3K8zdfrLL_nni2^zmcI ziYHE-c!%>DUUVOGOMII1X@S`ye`)fb)?HImQv*H)u$_NALV(FSL-s-GQ>NQ}YYh<& z;4UwW#z2s1K75N-$Qk0ocXfw+crl$MHqI6~=BvnGn*cRO`R8&6^rm5A+vtvJIhpHF z6S$}ee6X9WYOffToc4I~jMD2Q5*Q5RW;gl3{0bP+X}%S(dD5X`RJn?&uXEwm;KVfI z_%s}Tvs{0ErB*IEAQ-IUTs{jXmF<+uHOc>GqB{Zaj<6PFVJ%eh>q4EyVZ-+i$~7T` zH)ev$K3c$KiS4~UP9qhKJj?Q; z#S#@vd4f9CveR>$WoB|_dj>7=$Zt=1|FEf-3!VDTuoH(q-qe)$3G5hgpK{k`1~pmS zgkI&UONDDPLCXsfns)~-uiHqc`&!15#HW9Q5Cza?51DHi89FF@PbtqAe*#tmys2Q) zQ*VQv#Kgn*+J%DsHiCPHwmRs?23f|a4~XW`FNqWI=GrYVZo9qtrG2cwIKR+f^Mm>h z219`0vraeZR^eAulrmecy)A7<&H5c^ynNEAnv_yot-Y;mP$5<0ckk8DeI;R`?J9o_ z!xp7qFt(e9!Uoo*%5!)?35cHaKc*e>7UVGUGXpl-Jkaev@4r_ELrt`pTqK7PF5K{5O&!4C;OMUX8^vdWKHukT#^AT~xiOt5GmQUh zWp8zF^jv7*2w~S5RlD4X|{zem;VEDL26BA|^%7 z4pDlD=%RnC37V$W2+*CEv>B{}wOn zjyxQba`g;PPS3d#fnv=EPY zzL4`gY(<+OJ_Q|A9>#%@^IzY>^Z)bfcs}+S* zn_o7SxWW-7eg&iF^I8NqnFV?6v=T;Oi1BL;mFw6wS|dMzRTjx1^zeUx-}N5|5dF81 z_4B{9oByeGTmoJ*V8uzG>2e9=_6mLo6q5L>6XS6dxHbq5X}dubkN37#e9SJ5SH?^B zAh|jOYXBsxXmuja#|n&5`UBUB{3!6H^aIEsnQboL?T;57r#N2ClkINA7!x8Y+O4P% zQO?A`j`&Z&@lQyd^tFFglz=@n+@9WSlHVMpo$eAwyKqZ`&BDf$5|ZrVLOP%H!Bpz@ z7wb$V{W;d2jCxbEm9cVE0FRb2X*%8l7q+qX2EZpKtBp~cS=dgCjmX=*%>en!{4rBS z7L6Lw#49tk^=)~6;H6wpE~)V{w-o)`O0eEoEVYFwHi{2SN(FyM#c8qb7Ydz5aiDMC zf<2xAda3ES3How6P6}M5g!ZT6zP=Smt8Uu~^#Q|0tH3L+y}wiU?ijj`o&yZjKwydOqztP>ZsP2cIv52^qx zcRE-H-8v5q{nmf&8}Bv}{Q3*-HnM&$HGo4g6fw}L$xwE7ub6NePGt{r>?<(;*EZj5 z%z~IWJhl?D)y>b|a6?{5QzZAA|kh(DuxT!+Ys4*VVU9U@}vW zJD?_QhaWE@JgL-4tob3Q!V;(9NBQ9oG?$O*+%XY}W4eDOKL>JJ$6G=&p)r~7EFEUD z^?R(KTyDZX^F&+a&2lSgCh-1do?IIsO!638E>B#t0(^cG`8c_UJVw5WD-6So$N_%t zmklCI8{!ZvxnRuwl%ethGE1a3FuWeS&xT8RmsPD12Co z>NS}gLD>){sv2RKj44HJ%A{hy!N782mWHcTDW-q(j2>YIv|1WoV^Ygd@CExV(*^Q` zd902wj^MIKjG_F>b(90VJ*~ZV478#2Zwo-3j(x$QDjhQJfGwrt`a9`21#k2l!dP3Y z&eyrPkr~bD$=xj)8Nw(9Od2=dd!Hd1OHD%r^GtZCb(BPro9{~4J7KR{AdNC)f(Jc-3@AQ@-#Yp>ysM)+dU{@pJ$TCo;A+rFH1xKIl_02uC*3G=3m*pP`Coq$ zN?A&Y3+eP`@~QVlr)hq%um}cC8C(NYsX^VP4Puee!b{TEH0H z5+XvMKKcT$Th;?I3T-=#Z(gkp3xZ0PD? z^4QG6VLrMZ47UO?hCP3{@c;h+{W~V!000000000i0BiuJ0Q3PQ0g3`70!#vQ0=xrK z1CRsE1QG<61mFcA1&{@}1`-A`2FM2b2QUX@2Ydp$NQ2>c0p38D$`3VI5{3i=CB z3v>&d3(yQg473d74HOMz4VVqY4x$d?4{8sN555oX5H=9j5d;kjH?qFkZw1$KKuYGJ_hzvOjj8LM& z7!ypfi7lMMX>8*Rc5oKwa2^+M5tncoS8x^Aa2+>r6Sr_1cW@W?a32rw5RdQ}Pw*5q zp5ZxO;3anP3a{}7Z}AR)@9_a2@d=;t1z)j;Z}^UV{1{YAof;Ly(vFrQSZ(LiW2~c| z+oJQv36-ZHVl#@J_b#MKkA_;ZDOQmawW27?H4{SEH(6MR(RomDR4?Ch(* zME6(9eP?WWW&i*KAOHXpqW}OU{GY0-{b*%jWB>pb!~g&QG5`PoHdwo#`eZ~y={7vKN@03QGV03ZQb0IP0cZDjxe7ytkO0UZDU0rC{v!uW7+b94Xz86W@v z0sQ~~0{FAYaLkhk0cn3T{QrNML7GvD!2l@Ch@yxI0DK1wvH*CT?bPRS+fWol;X{$4 zBr4~ebIv(Sw%Lg5b3y*)7Epow7RP0noDUCJ+~vF(Uy)&2S^$3~9jx>X;0%51CrVw*nt87RFDgA6gu2%~?DG0p^&Ofk(2v&=Ei z0*frM%nGZlvCamYY?Zs)<-5Z!d+c+-VcEqoC!BJ|dAWPRC0AT?!!38*^S~odJoCaU zZ@lxtXW34h|DT~8nm_+tb@RkjKf@l8wW+)dRZDrQRj=}%RBe&9Ph{;ESqDVcj`IFg zgR0MmM6zLJr`3OmNH!{xjfrIABH4sUHYt)#iDc6v*^EdwE0WELWb-1~f=IR~k}Zj3 z%Ocr|NVY1Ht%+poBH4yWwkeWriDcU%*^cTx?~2^tQ+>WKGJ7C0dnht{BrD`I+?nQrk4Ai{c-bH#JBE3(M-Zzoncah!?kzQAP{sq}!w&DN)0C=38T6>Hn#d)u)u1CM8yJx0* zcjvvcGrfCzx9fe(^m5$o-2sd6Ee-;6yu_UWV;;gHhj0ugiERb2!HO`l6O_oZgXH{y zgrg`9v6O#sLP{bFMJOl+>?D{!IIu&4aDpYJPlcK7bg!EWzY&#vmK`X0aU zt0nBzsZ%e~J(Q4uR0&BY=h*TpTdcE^&(cX*iqEHu{pD`^v3j;ENp@xX^5ha}n(|5{ zdq$O*{Hf`h@DPKLQ$MA9$j?ZLw8$<(vcxY&P8I>r|a>BtTEgPbEJj%j*M;K1{i6#pV56Hx7Vm|ZvJA!$+z>HQ{larFGJ z&^GxMtgA-4r>_j=g{g2}g&CatvFdUf$LaD)o>YZt+NPN}z5~zHr~#7~mE4cZ-!Ii~ zE8BlA*f!B~!d{Y7q)hgZKCF33!qB~?MO?RpWp`n|epW6?%qgI-3;jjd7pO^-{3}Xv zcb&$~@}-41F1!Zh>#(3%5jb*P1Y%t}ftbnnVbD1>Y%T#-GxU)2!!$W_ONjs@itjliVD>&Fm_X>l6z4e!rmkXgAqME`=E;eTu7|qp;>xx>%?A9t@7Z57WfS zl0Jbss`M7=CcQ;lb}Z{b@v+uQ3zjjxcE#FsJwC`iGjanOx{>MegSOvV`J`<+)HZ)@ z+%DX=y!bl2mPm`5GMQPMo?e@|GOkNA7z>p0?JJ@2m}4F?oj9oCJJlf8MIvD>|4bG6 zUou7($RTn$xslw39NeIFnv{K7pmK7a>Xr530F%iA)r&TZvhRvT5j(dzF{JQ} zIX63Fkh*+Y9Q2OzX1~+B=1u8PUN!|d+sr(ZG@A*MDaj+lD|p6bz^nW+osECEJhFzx zHC?P?wu;$?(v3S`nT6DnGC*R1#Ovf#K0cCv;8K~UlBQIarQ~NYvsvC{Z8l(101D6b z9I2eo6G8}V9Q^!{{1xyV$&ib1AqCpQ<GT(urjOw5S68r64DjPv@ybu>^lD3)&5YF;%jg zqEx0`5ZdK#2GtpgZ?;Msw2xw&^%r3P5aJ~3#|cWa8uA!zQ)Wz1I$o7^-Mv~lPe%>+`%61HV9W?Ql)1Z9j0(UO(} zgIYGXonPOTPma3Yi9>&PtAoAT4SO|4X5jQ-o8t09Nwyb2i^;*6!BMHjRkl3GCVf^n zelfN#9Mcqso712tTPqi=wC)QViRUGa$;OyR-Lb}l)6K(RA|0_lrrTR9zcpy}#vn<& z;W@pa`6edmmbuS1bE(es)WKP1cF%F*t+-~-PV0}Nq;h!}2tt3BOB;yU4xsZfAu1JN zIlNkd{os`fhj}Yi?(D!l-{+@yvG7&+78AbZZNLSufo^PocI=T0$Ytajuqq%)8i=6H zMVrwUx#Axx%wD$KN7V<~F>lDL%V#a5s2s7NhA*}ZA&fVXZ2Yq1z3G)SS+sr2^6frq zD|J@V0rLX=#`1s8&kEx^I1UigFO~f7AbHr-;77q5j#6_uWSSGYG;RCvzCAg_M|dXh z0WbWBR7gfh56*t`%V8Uqwypc@ZE>e8E!VYVA)XBcz3(NB?5yVg&kD%cJ zsB#pBfG14PN;1iR~YR#5!9B}Diy5&`|q%D8{A}R||c>E9QyLRo{wd)32 zOTL!Ws3C2?!Qc9EF}KOtdMGcu`cs`K6w} z3G;`5llPGG$Qs}cl9k(X1Pj`LrLyg2bScS^8|tQQ`RpwDMFWrPQ77Ve2bJJCzg+eo z#hQD#5d44G`;#ZXOUwS>`6b^8DpAS*9=;3Y9%%|;%A*1kz!5q*npcwCt_^TO1y+?C zvjOxRn4+cpBmc}RdAA|LxotD^@7s%zAp@MLK%dN#WwMH6;vUsOo4|n;Xo5I%C=IYp zJw#|JLN(C-fUg=L>Hxi=ejZdnjdpGGglSX9EO>uu>iYJWU;-oh{?M)VC?vBV|S-~igO2RY^6LnG!GD96mPQo{b;0*!a_x0kD47k1Bi-V(% zxgH097{n*nUoOP!rt<{i`V;GfsBL)kLUJ+rIQayis}F-nw@jg6%wT}d`~lc*3Vz!-c(NqxfHNN+d6r~71&}Oz*z=A% zzV93#q>mmuR=nkwTi)Y*h8NvO+!CMWd|F_($X}eivvvE_)D#)wPteT|5fHM@P<($- z`;_T!-`cd)eE97P3!gqCta(E`2B({zgIp%99U)u;ZNBL)S2mY#I zV%zA>Ydx9UP!pu6339NPtm~)(8aeGT<{72uNhAmu=*@2Ok%d(N(P_REz&z>DFsj_d z)HkK@B5(p5aeM+czgaH7S}T_vPz-<8&0IbMkji#S<(lMwJ<*+jXHQrQval8^`3<2? z;%md__scaQgg1sTf6Rkyt<2?~BEB?nYfuZ}MYOKC-NrV#zWl?;bF$FK=s^J%q1gd= zJH?;^Rs%bv=PI@p##R_>80Rx%FK_6=)S*KM4}LHKU86LnoI3kBODIhk-{*foF^1{K zCnm=A8U7dW*z0hHB{;*~fP^l_RSz(BHVR1;=$6=%8fl~UCLqr?@giWynj3~=VR$X_ z(4U`;yq9;H;g;>%79S)}21ytu!F;aF>CrqrhI!z;d1!(T_etC2+=Lf&GSD->qBGJ$zP{2qTiLhvwp{W)|*WDJ(6k3JG+@C4_mDoY&)>mvd#OKk7; zaTuv+?7GhUv7`7<=g0X+SG!!<7E>)hx14=;kocb~Ckar-5k+T`VXbZr%2gpak3g1kK zs8Q9Lr@aHTm89+7KxZar$fa8rl@2Y@QgVhIMhJ1i`!#offPtOzvTn`8naeu<*}V@eD#)nj$CJQ6KL_6`w_PKI)6M;dVYxjDxzgRX3OsX{ z=~-%0SvnUeTYP_s`}{$5yRvUYCu3gPww%Y@jdnqNmh;cbVVqa5f03NObNxd}))o*X zKL-cBY<0LBNxls}-LVmuGvPRl8f`=H2?Z-GT6SD$+hH|VN;@{=IVv3BWoih^C~(+4 zcpMShh1k6ZcCX-4CzsWqg3kRJ_}^p@Z^e&5<1*NqxO;yREMIWc7LE+8!(jd<;=*G= ztP08m09uGgGGEAL9+sjZh)=-=4Wik(sOv0X$m9r0IBzT-e6On?N6*tTsk%W??riHX?8DE(7#0^T$jT zSu|=y6R*zHHkal3ftPYYxunJ`+*0&!D#2!BvD6l#*eKpRDHUuLr^UKoD0CXdfxUeP z*7$!i@Jmg{P0*LqaZ->fCA2>k_w}txT6F{Gi^3IObOLwd?KlAb{(>{+yd1i|d4plx zVES%I58bB`_G^uRrZ>DC_5110;VGLlFa;nhbSk_xuT`;Z*ja#J&pSe|`JS z&@8BlD+jkj700QJZik-UelawQmqkAr-VWulng0eI`eVTV4UK0;65dOPxvsvo1ISE0 z?tq!J9e#5W>2alwW6cja6_z*wf0SSOk><)VojWEXaZI=5`#?_UcuPno^hxF`ONW1% zZ1Wy4D3_bC&OFhmyjgA~%>3+=p{R`4 zIMO0g?qC-lail*o$1KJUy5Z+MrkwCRM8Z`Zz3G_W#I%Ow>NuT4?-RV!&oM9b!QjJG zRL{xW2+D>q(bNdTWK1b)QzjMr4F<@GS(>g>rI^k$dW0F!YH510Ni9Rc7aV`IOc&S_ z#<4oWID*q2F^2jpw^0tr_O$leG0=wEzb)YCbnFW@Rq2p%2e6cm>(A3~3Et>8gt4(v zU8r+$1v8q{lY3huy6dmYaqM>b*7>#(kGF#gf*_gfz-spRp@oesPBT zz7G>y*`YJC9kJYPvk3|)5+4T4hz+m?SyrR^Z_I(KPx zdhPPHX-cQprkgcCnuvjoLk{w#qGBU$t+bk1%V=dy+cq6Z35W4thVlOcv{;3709)WL zEoB3(Ih$XJ4OcYcg?2K!bqD1Vxo^8sPz|1fzk1|8Ozv@)COdSEsSbjeFygMWsFmIHgAJ=+!VnUQ6hi6NF6?`B2OMZJk0x4 z9{x*6)RwAYUXT3)@^g5#fbqL!JP5t}=qJ2kS@+5)wCymGS6XA%y~usx`5Wens z7eA+-pB6?5*0#L+`P1JW{Lcr-*f?qHI|ao1EyPRd;9j|{)1*}%1S{78I#C(8;BnaN zpsb(YcsFpLcY}YoqR_2Ykq;v@AQ93}J?;j9JNU+b(lPmQ9S2+rGYwqY_@6JTh!9@M zZm%1-mvYOv^ob{MoIqW7oeExegN^^o7|Y(M0#w_ulsI@$C~N3%U>q0FUlwkjK(Clf zj_R5=zwSD2n>2KvfRBECV?&z8fdhsq!D8tT%kRLyPriQ#ej3SgzD2H05m+UE%lU=e zG5OxT+;sSzhHG5NmCMgNkGqO*zWa=RH|O;Mrvt#eW81qopYh$-$sg%=M@UXXJM|62 z4uWlP^+r8!F4$m@M*v6OOxa@Esr?~0zLly3tyu)3-!(aR^-bfy*VxNuxeewSS z$FH&gc$_d}U}Rum0OGR+TlUBE+k9o`Tw6$2SlS`Hgq|3bs#-f$aa{QSe*lq@DK-EA0000004xA(0Hy%+0VDy60we;&0_+1616%|0 z1TX|_1hNG-1%L&>1~3L#2C@dy2WSVH2ha!v2pkB1R0zHaHVK>x8VW)RkP8|MVhfrJ z@C+0TJPdFQ;tf;{gblO~1P(Y3WDi0Qf)EN2E)YBrY!I9fnZjzJR_zd9F*hd#KeHdOgQKIlG&H(d&o zRY_{yf2(QXg{P20LK!FLn=7n4+rzj$tdmBs&v~nD$62!4l`YZIOVx@M7FQ(2Y3i(tAjzzMZR7*Of`asiS)RRUl zMK-5aXj7@wN-b0BQn`igySk-Zw{NHxA-F|td1x9liHC0>`q;eWIZ1^N0126=Slhqjpf#GwSq!~Y-ZeLr(kz{UbkEL|d{V1asayi|c$ zL3;``sUpuiz;03<` zL(eX(C^d)HSL?!>5&$Z#RdTXD`5+X5Mj_wLY#&&ujcx4`B07!L?i~bKHdV94wG4}f zMRFPccK@EX!z3i(O%e+LCA!?3+nZ9IjXo&YGXH#kq5S+~1Q)=Ta_3kkk_Ak(;fmI< z)lRWikP4R!`~T~FU8SI$lyIcb)^yl_rlHHAd*74uubyRpN&c=S`#04O$}Y&CRWvmR z07surz?9KR1j`hxJGkZ4en^gFXHGCjxCd6X&$?*% zt)r`_Z(s<8!4XIl8iU2*2}BZ^LZ#7>jP&1mCX3DC^7sOwNGw50Wpag5rPgS5dV|qq zwiphgj^t$*DyQ%`f&}xi5*jPvu@V_8FJt9(th|kt_p$OZRzCOM%SM}gZ*<5{=6!{q z@E1@46L5hLNP!Y)fe~1N6L>)oL_rc{K@n6z6Li54OdB&mT3N@o_Z-=dD|mu01VSi8 zLM$XgDr7<~6!z;?%04Qg78;=yI-wT^VH74|78YR@HenYI;dJJPEkES~-k|#oy^rJ+ z|H3E~l@#kjT^L_P6E4AZ)PODKW9v9p8J&5)7e9_sjz-NOYQ2bm*yOP@kp>GG6@zu0 zoGBq;ci@u{3J*u9Y@d?Pv2v&^Mc!}C4pL@|POgpj0u zbx4vqIXv9Ny^QAM*w_eDxX8y63FS%2ayS&RlgNies*i;;S+vMvC_r;5f;* zpyHBD;wOFzAhMODQL&KnP>3N;g13o3OH0Q0X&vz+>ATx>aA?a54ZwX*kPS}t^|N(Y zV#0+U@;O@4EvlN1GkBuSl}88B@2j?j$FHeGjVZhP@hURQ;%g4kn+@)>zyr3Ja26s% zyM)Ws1{4)XtMYAfh-xREjs6`Qieo@XJ?SW`semSINkzV=Ru>T~u1>b9F9IK@fB{E? z*iKll>xuHuLHY5F{(T_UO;^agtyS4im$Fb%HEYPC!K5r3K?ePSutx&{*u#;yZs`w2 z@d=rV#`i%S`c)TAuyjnm)C*yA(Jvo}74LgTou0dD0o2ZgzLh=z=VtNy$!qymUx~|P zPMa#;an!;j!9CMKN&uMv=x+! z&PsMaSiFeCh?fBR4(Pbl3QJ;HhMXLo7%>ic08LDxOs$(6+qiBxbM;zS z;Lm8Z@w0MQ&k7toPNV4~XNK38`VK#%vptlU0Vr<(wya~KgK zuMUP*Ydy2Y`ivYOVxYa-_udlls%{=F;SgwdinAn5 z2JO>P+I_JRYQ!RtfmrGPSvk*omMs{7Z%}F(`y%tHopxQI2a6B9)83i5F7Ha=4y;}@ z*tBVQ`^emQgo!XYk=OW5 zPd;XKSea6xXZoJF$11u;S0NK=zf^Ubb8d%7>J1pl>Fi`@NZMF?!u;hTs`1-24{}5p zWbvX&Zyx;<>3wovqMW$T$dFKBm*MCDwh*G4=d*{R;-h)?1UtIiwkT1`nXdpaZ2Y^p zrCH~4$)Vp+dDpgR^vC`V9wWOrQtE#su^xB<^EF3O5z#PZk}<3iW6oX%{FDS(J&r{@ z9@F!FiXWAObjS02d+)kMY@W_f3y<$3HT$$!HEmBxPNuRlpqt(mYOTS>!O>}T-V+xI zAc!_q3A7=+HXjNy`pUGTVllVUX6?XwIBtFK%$9z2@Hd7;2{Svcsh4oKO*|xvdbh7S z^|0y|j|i)-OIj+A@kbXC-5|)+0(p9=xD3CcK7JrP?153>?=B)WL1R~xREk(JGn#41 zGQZAY@LCK7i}h3I&Q1gRN~bz@P&u)FW8RR3eZazdJvXDY`6b0BOYU%#%>KY3RH01a zJ_y>dKlvmOfG6OgWVgj_Ys=J-V*hDbw-F79UaF4<{B{rw^3@#FTv%}TjyRt9A?u;E$ zbpOEo`4jv3T78-Joknk={i2`txK9aIKcctU7Jg%+aq8u5^ndiWmv!;rHY%I;)5C++ zF_TD?heo{%dc!!nMsirB|U zqQV~SKa9V^d(2GP)B>Iju)~=)mT!<}l(dzaWF!f71~Z)P3`_siS9+Y4m-tftl5a+? za{OYCbo#(l;=sE7Bmge@`S$JkC30YQ5tEdG)jAjl%3SZkf{|K zNBoO}cTE=7l40RA)?)Ed8mm!0i-pxVO9rg%K)=vO3v{p4JY|@tHLvL8bD~vu*1A7R zW}elS>g2OJ%dm~CE3JLT$Wi;P(T89a&w*tv9%^Y~^h}c_6d#-)G@;Z|?)>xfOOr`Y zYG*`es)w9>>GQu*%Ppl73=;;^-H>Wl$5daBm{P8N!|;{EjD(*rv5T_Dsw}Wq+dquW z{ylcAZXUsujVQl|IWy(QzSEY|C66tS{im_L6_1N9FES?WwKSO0Z_c>GBZZOe0ad6G zTwex83VtCy(C!ju3u@rYbOB6936ZN`3 zOhRy-WU55BOL(w)GKKXhiZZM-}{B#Vya z*$o+apUou20o}`UUEmCSNSsaAAJn__jY8Dm8R&z*PRja``cGAAM9`<;P!$!Vn^nm| zQf1v_!9lh^15?(D=Kp7HV8pOq3Ok?UtYn zd5{Te|2}l+t=KK+#dpOETi%L^O^Vst`TUmm&KH>9EHEjh#a1&45=wPvx&OFxVdvaC zpVfhUlnt;qhY!FK-k8T|>@I!Wt^qLex}-&$W*2f^w8|g$)b;^N*2$DE$&LCsfK$?vMU~yII-$6Jtg8{Q^%w7oES8MM?@| z*jMZvdQif{~H092fyRI^Cv#`%9A=IS)&ZY(8Lv+fMmP z?7*Ib!wOBpK093tB+@aZXW-KX)uEm{@;dVu^ZJo=U;-;2hC#%S z?P}Tiq^>_hxbQf_MZ83Z*CS$;I6U;NL5)zMD+1Y}%L#=^gAGHh^}S6qt(7j%j7k6z&uo&z|B^ z=sL#2)X^!)?`R5QS|zn=mP_xdoK?*KX}x$73(DTSH3-8AE1_~}>!-17U6JvXjl85u zR$hp#xW6DEwfCA6Zln*|gfvvZk9yzxJC}_#sVmxExci3;9-`}EVFgQ&@?K%{h=x}EWZ%ZkT3t+xuL*rFWAueubkhIk=j?`tNNC-`pEjU79(ss zGC{<2)NtI4Q)Kzy8;hJn%CF-Fj0E}Gn9PL8d1K@!2R0N02Txq^L3fCY!bo?cCHMyy zH>z>N7ZLlSbKltMw?3pOJo%=g8{~)Oc7`G`1Acb;f;alTOZK~|L_p+sVy~#*v1rl= zaYPY&hhFUMkcQ1g9(3cnhUPAuv^{J)EKMDp#VhT6!2o*#0>bS^StdbZFU#P?|Fs38 z1A)ww)j8-oTGp3mDiJts-I#Yvc{<{^YvZbXs*B2Bwb3;#FEwRgVYu+Ef+D4;U^xL; zZ9=0=spQQ`Zw95{(a3AM^GCsYZ^$mFW)~#+ijzbAW|!}ldw6b3eJWO5PpXVcVi@6O z+yqwMt{~4yBhxM-JgkQR(i=g{XUtO^A*Q(0+zf~Ld9x#9yffAuVxMZhk)0aim|~7~ z4mwRq7(|tOZ-2Sp!g^~NdlIIN5g_X3+gEkFeyop7dgxPCtq)KR{N=Dg= zMtHEUY=(D1bm1*iC4ou(KE^NP|7x3?`=ZR4e~Yy=GIBWKCTto1%CtE*cO#4p?jfvr zHEt!saTly`;nHh_C3a>S;iK>zSh#9oWD(^o6ON4>E`@BDGQ0 zdlh;;*UPP^6)&g@bT9jnVq9*fk#^mV4(0fEStSRC13g9bMzK#kZ98DUsRoFg{!Y$Z z9OT|k<4#c$0BikLG+}7!6#d5K265WYr%f0lkjDFI!2Bu1onoH=``<_t(?*PN2^FHN zrNt#y2rhVaS~lO7Wkth*RHD??$t4Z8QODW|A6F~H^kKu=UCT7@Qq%i`z@onX+k5T) z0Q5zD7bIbUe@7BLffrq7h2H>|fWE?c5hUY0O}}q2@VEDyF2N^|@eql$XJ250q{afc zWE}vh7tl>m{zoEw4GaVAk|rRZXLZ}T0kt|2r;)^XUNfJQh+zN#a_vQbh=lK19n~zC z{3Z@A_vo=cGoGzKu)`lBkZ+`Z?7JqCv56`nu_W7e(SM@gV(U|haJ!Gv?-u+3)=U>| zl1H*FRXjNh6Forr`^6v7&>sN%(t0jG1_oeESliQQMZ`ri1OSe}r*Q1v*|(sjZ`!{Z zB82y@1(T%AUs>UKH~`GIcPv)TzVZ{}#aUqCkF4>PeHQ}QL*M(_u<`$k(SGYSu@xSa z`t}m_WL+|Xq}mLd@c`c+`11g^61H#%#2v;28FwYcB3aU9>sanhgIl>l<73Y@?Af*Ax4 zTwR(oN&XUvJR=x-=l*iT`s}V|I&Ee9!Z8pxHl(Cr5MkdoLOvn2?var zOy`;!Pw6qM@mIUEi9K=L~KXo zJc6MR1RaHH!BNsE+qBrCWmn40yqhN?Q6nW0>69#%2=!!aVB07ws0@3%pLhB5{M`P$sO@d< zzPFSOU9gE?Y7DFo=9>Y(kUh*{4{R`)_7CkJSR<@{7#X1b(+>Pq3xEy)*#Ez&nki~- zsdMf$ERxIkbKBE)n1m#}NrC}D`oZ;a>Sr=fp@2>ZB@jea_u$%Xj2bvO7Tt z4orEefX)uXY9|C$BehaHk`Dgoquq0WKX91-UT4`#huR%qfLr9E1FDKNg+9o;|NSRh zhIK4yce36+k{ytj6*T3>2LPp$YUiqymXFW@gz3X&D#WU&1371$4hzsqV&35mWYc<3 zo5N!oLP~=N@x8wgfu;i!=O1(uJa&M=Ab;OOZSfMIQH({NwI&jMO+EL61W+B@5r%Jv7Y!vcYgxm6n4Ox zB$xC-YF!A@=a)c(RXdE3$rZ}myI)h+(A3n@*3s3|hr-|pBnpke;_w6_iA!#ss6#QeqCp+A73G;YCo|(G>XIzU^g|S0lzTi>KUk3JXh5yG z{!p<-WJcvI_8Iz_w|`G0k0?R}jjIEMArvO66T%e;bIhz=XsRj~wL6*U$pM3am{Yh+ z1ZrEEvMRPRA;xhLF?5uJC($a%OMD0QOL9)=W>HD)@YFj}R86G{p607~(o1 zq7>35<()T8uMIz4*x^6B_;Wmee!Khl+z)jimxPGLXO1x`n*baU=OJfruoN2zz@=0e z^Vv3KU2QBpk^n@S1}dATYvW--OnVj58Ns{~#AksaO z*OB83I%jYbgOqavMqh`ib>s57CMsR_g+S+W1VRF>MiRtE9bvJ0$NPq{9GBC-Lnvf7I;n zvZt8gAD#)P4gh*5=NchChN5qI4@-4V0dQUCA3KYzsw<1{yCLUc>?cCR5#VTvzuRgg zJRD==mZ4qDxGk#=O)9E=5f9mVc1e282u;I#Yrpy=S9-}bjW`x?d$w&^QBNi(JK*FK zq@T)+^|Cil$KC6W%0B%R#>I?XVTP;t3bOK6;5Z`|7|t^)>HUJrY+ZtmNJfu2_0y!=~z98&8`f`J$kA38JP~c%M_rfM?V= z1nc;=TZOM7EHA)+tqx^;O=SKjwn z4xa*9fg|0^jMX_~=u9{1Dw3p<8mXo`i~Yq;xwe?1vmWcVH?RC;wTQE3n73o( zc7UJ*fm5T?Uww2qt5XPxw0yQqubzG{`%>&ZQyzNr?R-tv*-Wk- zI2bmKh&3A&=5;P2jUIou9BEq~5JS#<29Rq?zB9R%1Z=uwFf6FNZW~ohybcw>;bF10 zr&K-&CHISf`J5A8l7n`N+deE4V}@-z{F@me0`7}+e~i^O;$Ar-t}vYWaP7Lo9h|CZ z;_-E)Y@L?nY^*8K!BhwYmWFpxNr@!rw09bFDXR9QrN|Cb-j;<*b8}}nXQG&rQ*Si& zOzT>K0d*(-_(?SXj{ofUK26xnY`+%o2b|%7Y?B4O+LwIOV)@mhNAs>oTO`}ZJrGQA zeQP(?*1I(c{s2=nxwd8g>!avFFJBLbF8#wpk2+HxbWW4Rlrb@!W|=!5GvrmrojUt% zcUuR7=8E2h)>7*xuOfPyWntg4=pD?cGRBy)moWP`+EalkW* z0z(W)ng7+-Ps*`htAVFwgE=|V9k2*`P9Sl4iKrS1{eErHf>i~Tz0Vl09MiIeVLIKB zp1w-HuRWvre^ajge+`QsI7=9(g&wypLR*?NmgUA>Tc1~{Nzi=T+&1$pEAcT#;3f7< zv$mSsnxK;@=^xUtD%*~!W;G?s*#%|6S+NTt?j)ui+ZsOqOFu2>n|4!Eths3?YzuYo zJMBR2cTyV*FKPw^)ACoc1KE}N!L$L!0TA;7FwYJVKT4n!(nBfKc_%3ksdOeoOZ5SD za%lGd5lhUXW!>jU9=GH@E1dOyOe(BGe(XIbobyVg5*!_nWguayeTqHxoOuB@3uWs9 zY_SEWxk4|}(urM?1Ms!O#kw+Gft~axxwhWeRdwZrYC+h~!e8VtrW)9Yg zS9!PYiu+i+$h@6ZtP`*3TyGOmS3K)2BgP+d$GhO>uYzj{ZgE8!Jri|V@K)W8J&IkW zzQ6X}>`MmIw#RKx3zB_r?)y8f)K%QW(4!UGt(n2IVq`W0pkHyre;q43Mg#Hl%5 zWENOe^W-i$eqP_d!h5|H=Xw9o5fb? zXA86SRRwgI9)r{xb_!K=Nfl|ZVhTmfbz-XY%zE{dG7lX;Ofv@qCYn1a9pY#~K~z(* zN@^-qiptHB)LseKG*jF~sg|RVBh8j#!gWC5X)TxF8eQOMMRz=lxyk$^0C9GKNU!;>I zY1TCSh{Poo%8~ZvNuW5a4^*7f-&JiJpR6NM7hC$O}-4*Wt z)m7_NCjxu#l^QM-_& zbn9mhB$dMyz|8eJid?8Q67NMSt(luObK3o#PM{?nG5&@Gh6c3e;UO8b)SDxE4s6xgKhBf_OO0?z@Y{XIAq&IEW=iD zJOLj0#M_B2>Q1yx)rsvrQBgZGFs-h|;|19(Up+mH`MVu<`l?*{MXBbF@s8$iV?rq; zO!SsoN|myg$`eMP9LUn9D4nlo)PxhD8FM}Si;n`zH?XAxwvFK^s)C__i6-TAI0_DM zYpfW={S`t#tuN@BF@zs)LimYpw0jF8QEP$+zBkA=Ia{`Cb8Pae?u0pXvu+d{msw_= zj`ao=`3S zWZz>ia;fxe#>LF0Q-j}9Kg3iC^7OHOy?@%+LHr-rCl@ed&Z;#=3@6-#%%v|Iz_LY! zzBjF0BPfDfqqUXY&r*e&`b3ZW;r&LDf+rG?!+nb{QJ5fU+dC)xB(+UyxTdescm9s@%8cLA(N^1%@_x12 zNL90rbf=+vXmJM)b5cF#-Io7QdOZ9M|B8j(sY6uvg)966^3zgV6uR?Ah6YLl%@TaD z$bmXKN-4+)Bb>ac6Dn}rypFJ}z`P3TeO7XKP)eZTxYA8xorYUdAB!8;lQJWd7)At` z0D+a(NUyiBk2Bd0gBt1r=M_Vjn&&q*_T`#BSR zPpf`unxM14$LzEEjK^~`5Gk1@F=FhXIKHjUT2v#pTr{M86AO1}$1O=9WkMlkGG5aZ zA_q%LMw@3fDtzcDCNQDlF8q4(FSZGJpNNd}_e57YBQ_ucL_+3&BJIq}TL?o@Wa8>Jv#Dx!0?zgvoeE^^v)*g!SriRLrxivEA(oWo zqk#2#U2m``!*PnF%b(e7JAS0GGa@_kSgOsm2|(r%{}#3(U6T0s zQM3yk{acJ5$&36hEhp6f=!))fTveyvl{SMapt2-qEI&#VuVO8UV|e3fxC1i+hI^-B z=qLaIb$~%M3OLjP0n-tIW_WE8mDNSPhXJPqA-1DHs*}Q9l>8v6Rw|H7BOSM}?>Ril zpJkmDi4;imGOm8LjFt*Oo_xvWyp-&7E@7t)=WUy`i94*6YX#N1f%FPK#$VEG@H~)x zL~b)5=k$J_Zm@6Q1ubCQ@4iQyvIqXoCHiqXqDk-38eh65LIcJhg5SW$v~X;AI-lOY zyVTMgO&ra<#^Qa4fq$|X!7%`E6LwpSmrRmR zy)J>sMpi;&fTSUs>skW7h*LFQ%*t>-zsg z#^1dYSQ42?m9<6EQbiVus9Z}{GY=K%i=d2>U`QVCk>^X6fnlmD*5?>4Wo2EmKk5%tf5vw9Ptl%g7fY3JyZk zozwZ5u4m`xnqH{I^w;N?rheyFn%|M@K$qql_Y`g5PB(d#~tZcU&@f z`C+dvYGRdR!DgIC{J-p~DzBmp3Q4k}YPw-sw&Qv}nU?MRtL8K3vkby0PSPwd%BpVK zu3xU!o9%9YIG)az>+Sw{zTThj?{j`FoSa~p5xuV9A{^Q!Q4!RHqUpdbA)^Rd$ws9Q7C#^P#eX1U77g%xU z7Q70lL1 - + + + + diff --git a/src/assets/icons/source/warning-sign.svg b/src/assets/icons/source/warning-sign.svg index 96c555c55..2abc980b1 100644 --- a/src/assets/icons/source/warning-sign.svg +++ b/src/assets/icons/source/warning-sign.svg @@ -1,3 +1,5 @@ - - + + + + diff --git a/src/assets/styles/overrides/button.scss b/src/assets/styles/overrides/button.scss index 51b267d27..515112eb6 100644 --- a/src/assets/styles/overrides/button.scss +++ b/src/assets/styles/overrides/button.scss @@ -289,6 +289,18 @@ } } +.collections-heading-btn { + .p-button { + --p-button-primary-color: #008b7b; + background-color: var(--p-button-primary-color); + color: var.$white; + + @media (max-width: 575px) { + width: 100%; + } + } +} + .secondary-add-btn .p-button.p-button-secondary { --p-button-secondary-color: var(--dark-blue-1); } diff --git a/src/assets/styles/overrides/multiselect.scss b/src/assets/styles/overrides/multiselect.scss new file mode 100644 index 000000000..95e0d08e2 --- /dev/null +++ b/src/assets/styles/overrides/multiselect.scss @@ -0,0 +1,34 @@ +@use "../variables" as var; +@use "../mixins" as mix; + +.p-multiselect { + border-color: var(--p-multiselect-border-color); +} + +.p-multiselect-header { + .p-inputtext { + height: mix.rem(38px); + } +} + +.p-multiselect-option { + color: var.$dark-blue-1; + + span { + white-space: wrap; + } + + &:hover { + background: var.$bg-blue-3; + } + + &.p-multiselect-option-selected { + background: var.$bg-blue-2; + } +} + +.p-multiselect-filter-container { + .p-iconfield { + display: flex; + } +} diff --git a/src/assets/styles/overrides/paginator.scss b/src/assets/styles/overrides/paginator.scss index f9c844196..9b6d24f4a 100644 --- a/src/assets/styles/overrides/paginator.scss +++ b/src/assets/styles/overrides/paginator.scss @@ -131,3 +131,9 @@ p-select { } } } + +.collections-paginator { + .p-paginator { + justify-content: end; + } +} diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss index f0f7d706d..395c5336f 100644 --- a/src/assets/styles/styles.scss +++ b/src/assets/styles/styles.scss @@ -37,4 +37,5 @@ @use "./overrides/tooltip"; @use "./overrides/toast"; @use "./overrides/primeflex-override"; +@use "./overrides/multiselect"; @use "./components/advisory-board"; From d18f53d2df92d5af1df314a8c61a364323cad77a Mon Sep 17 00:00:00 2001 From: Roman Nastyuk Date: Mon, 2 Jun 2025 20:42:30 +0300 Subject: [PATCH 2/3] feat(design-collections-page): added help dialog, fixed comments --- .../collections/collections.component.html | 6 +- .../collections/collections.component.scss | 54 ++++------ .../collections/collections.component.ts | 22 +++- .../collections-filter-chips.component.ts | 12 ++- .../collections-filters.component.scss | 2 +- .../collections-filters.component.ts | 39 +------ .../collections-help-dialog.component.html | 8 ++ .../collections-help-dialog.component.scss | 7 ++ .../collections-help-dialog.component.spec.ts | 22 ++++ .../collections-help-dialog.component.ts | 12 +++ .../collections-main-content.component.ts | 11 +- .../collections-main-content/index.ts | 1 + ...ollections-search-result-card.component.ts | 4 +- .../collections-search-results.component.ts | 77 +------------ .../collections-search-results/index.ts | 1 + .../features/collections/components/index.ts | 9 ++ .../models/collections-filters.model.ts | 13 +++ src/app/features/collections/models/index.ts | 1 + .../collections/store/collections.model.ts | 15 +-- .../store/collections.selectors.ts | 4 +- src/app/features/collections/utils/index.ts | 2 + .../collections/utils/mocked-data.const.ts | 102 ++++++++++++++++++ src/assets/i18n/en.json | 5 + src/assets/styles/overrides/button.scss | 4 +- .../styles/overrides/confirmation-dialog.scss | 5 +- 25 files changed, 262 insertions(+), 176 deletions(-) create mode 100644 src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.html create mode 100644 src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.scss create mode 100644 src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.spec.ts create mode 100644 src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.ts create mode 100644 src/app/features/collections/components/collections-main-content/index.ts create mode 100644 src/app/features/collections/components/collections-search-results/index.ts create mode 100644 src/app/features/collections/components/index.ts create mode 100644 src/app/features/collections/models/collections-filters.model.ts create mode 100644 src/app/features/collections/utils/mocked-data.const.ts diff --git a/src/app/features/collections/collections.component.html b/src/app/features/collections/collections.component.html index 66b8eb9fd..5c99a411a 100644 --- a/src/app/features/collections/collections.component.html +++ b/src/app/features/collections/collections.component.html @@ -1,5 +1,5 @@ -
-
+
+

Collection Title

@@ -17,6 +17,8 @@

Collection Title

height="36" width="36" class="cursor-pointer" + (click)="openHelpDialog()" + (keydown.enter)="openHelpDialog()" />
diff --git a/src/app/features/collections/collections.component.scss b/src/app/features/collections/collections.component.scss index 45e015896..1b8a768d2 100644 --- a/src/app/features/collections/collections.component.scss +++ b/src/app/features/collections/collections.component.scss @@ -2,47 +2,39 @@ @use "assets/styles/mixins" as mix; :host { - border: 2px solid var.$white; + --collection-bg-color: #013b5c; display: flex; flex-direction: column; flex: 1; - margin-top: mix.rem(64px); - background: #013b5c; - .collections-sub-header { - margin: mix.rem(48px) mix.rem(28px); + .collections { + background: var(--collection-bg-color); + border: 2px solid var.$white; + border-top: none; - .collections-icon { - font-size: mix.rem(42px); - } + .collections-sub-header { + margin: mix.rem(48px) mix.rem(28px); - @media (max-width: 575px) { - margin-bottom: mix.rem(20px); + .collections-icon { + font-size: mix.rem(42px); + } } - } - .search-input-container { - margin: 0 mix.rem(28px) mix.rem(48px) mix.rem(28px); - position: relative; + .search-input-container { + margin: 0 mix.rem(28px) mix.rem(48px) mix.rem(28px); + position: relative; - img { - position: absolute; - right: mix.rem(4px); - top: mix.rem(4px); - z-index: 1; + img { + position: absolute; + right: mix.rem(4px); + top: mix.rem(4px); + z-index: 1; + } } - } - - .content-container { - background: var.$white; - padding: mix.rem(28px); - } - - @media (min-width: 576px) and (max-width: 1199px) { - margin-top: mix.rem(36px); - } - @media (max-width: 575px) { - margin-top: 0; + .content-container { + background: var.$white; + padding: mix.rem(28px); + } } } diff --git a/src/app/features/collections/collections.component.ts b/src/app/features/collections/collections.component.ts index 9fa7d2062..30ae6aaee 100644 --- a/src/app/features/collections/collections.component.ts +++ b/src/app/features/collections/collections.component.ts @@ -1,22 +1,36 @@ -import { TranslatePipe } from '@ngx-translate/core'; +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { Button } from 'primeng/button'; +import { DialogService } from 'primeng/dynamicdialog'; import { NgOptimizedImage } from '@angular/common'; -import { ChangeDetectionStrategy, Component, signal } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormControl } from '@angular/forms'; -import { CollectionsMainContentComponent } from '@osf/features/collections/components/collections-main-content/collections-main-content.component'; import { SearchInputComponent } from '@shared/components'; +import { CollectionsHelpDialogComponent, CollectionsMainContentComponent } from './components'; + @Component({ selector: 'osf-collections', imports: [NgOptimizedImage, SearchInputComponent, TranslatePipe, Button, CollectionsMainContentComponent], templateUrl: './collections.component.html', styleUrl: './collections.component.scss', + providers: [DialogService], changeDetection: ChangeDetectionStrategy.OnPush, }) export class CollectionsComponent { - protected searchValue = signal(''); + protected dialogService = inject(DialogService); + protected translateService = inject(TranslateService); protected searchControl = new FormControl(''); + + openHelpDialog() { + this.dialogService.open(CollectionsHelpDialogComponent, { + focusOnShow: false, + header: this.translateService.instant('collections.helpDialog.header'), + closeOnEscape: true, + modal: true, + closable: true, + }); + } } diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts index 0355dc9fe..a33896b4c 100644 --- a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts +++ b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts @@ -1,4 +1,4 @@ -import { select, Store } from '@ngxs/store'; +import { createDispatchMap, select } from '@ngxs/store'; import { PrimeTemplate } from 'primeng/api'; import { Chip } from 'primeng/chip'; @@ -16,16 +16,18 @@ import { CollectionsSelectors, SetCollectedTypeFilters, SetProgramAreaFilters } }) export class CollectionsFilterChipsComponent { protected activeFilters = select(CollectionsSelectors.getAllFilters); - - constructor(private store: Store) {} + protected actions = createDispatchMap({ + setProgramAreaFilters: SetProgramAreaFilters, + setCollectedTypeFilters: SetCollectedTypeFilters, + }); protected onRemoveProgramAreaFilter(removedFilter: string): void { const currentFilters = this.activeFilters().programArea.filter((filter) => filter !== removedFilter); - this.store.dispatch(new SetProgramAreaFilters(currentFilters)); + this.actions.setProgramAreaFilters(currentFilters); } protected onRemoveCollectedTypeFilter(removedFilter: string): void { const currentFilters = this.activeFilters().collectedType.filter((filter) => filter !== removedFilter); - this.store.dispatch(new SetCollectedTypeFilters(currentFilters)); + this.actions.setCollectedTypeFilters(currentFilters); } } diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.scss b/src/app/features/collections/components/collections-filters/collections-filters.component.scss index 814224024..70e03e0e1 100644 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.scss +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.scss @@ -10,7 +10,7 @@ padding: 0 mix.rem(20px); display: flex; flex-direction: column; - row-gap: 0.8rem; + gap: mix.rem(12px); height: fit-content; } } diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.ts b/src/app/features/collections/components/collections-filters/collections-filters.component.ts index a7edd142e..fa84205e9 100644 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.ts +++ b/src/app/features/collections/components/collections-filters/collections-filters.component.ts @@ -8,8 +8,8 @@ import { MultiSelect, MultiSelectChangeEvent } from 'primeng/multiselect'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { CollectionsSelectors } from '@osf/features/collections/store'; -import { SetCollectedTypeFilters, SetProgramAreaFilters } from '@osf/features/collections/store/collections.actions'; +import { CollectionsSelectors, SetCollectedTypeFilters, SetProgramAreaFilters } from '@osf/features/collections/store'; +import { COLLECTED_TYPE_FILTERS_OPTIONS, PROGRAM_AREA_FILTERS_OPTIONS } from '@osf/features/collections/utils'; @Component({ selector: 'osf-collections-filters', @@ -27,39 +27,8 @@ export class CollectionsFiltersComponent { }); // Mocked filter options data - protected programAreaFilterOptions = [ - { label: 'Public Policy', value: 'Public Policy' }, - { label: 'Child Welfare', value: 'Child Welfare' }, - { label: 'Criminal Justice', value: 'Criminal Justice' }, - { label: 'Medicine', value: 'Medicine' }, - { label: 'Public Health', value: 'Public Health' }, - { label: 'Social Work', value: 'Social Work' }, - { label: 'Nursing', value: 'Nursing' }, - { label: 'Education', value: 'Education' }, - { label: 'Law & Jurisprudence', value: 'Law & Jurisprudence' }, - { label: 'N/A', value: 'N/A' }, - ]; - - protected collectedTypeFilterOptions = [ - { label: 'Experiments', value: 'Experiments' }, - { label: 'Interviews', value: 'Interviews' }, - { label: 'Grounded Theory', value: 'Grounded Theory' }, - { label: 'Action Research', value: 'Action Research' }, - { label: 'Case Studies', value: 'Case Studies' }, - { label: 'Direct Observation', value: 'Direct Observation' }, - { label: 'Document Analysis', value: 'Document Analysis' }, - { label: 'Interpretive Research', value: 'Interpretive Research' }, - { label: 'Participatory Action Research', value: 'Participatory Action Research' }, - { label: 'Event-Sampling', value: 'Event-Sampling' }, - { label: 'Surveys', value: 'Surveys' }, - { label: 'Quasi-Experiments', value: 'Quasi-Experiments' }, - { label: 'Ethnography', value: 'Ethnography' }, - { label: 'Social Network Analysis', value: 'Social Network Analysis' }, - { label: 'Critical Research Methods', value: 'Critical Research Methods' }, - { label: 'Design Research', value: 'Design Research' }, - { label: 'Discourse Analysis', value: 'Discourse Analysis' }, - { label: 'Research Synthesis', value: 'Research Synthesis' }, - ]; + protected readonly programAreaFilterOptions = PROGRAM_AREA_FILTERS_OPTIONS; + protected readonly collectedTypeFilterOptions = COLLECTED_TYPE_FILTERS_OPTIONS; setProgramAreaFilters($event: MultiSelectChangeEvent): void { const filters = $event.value; diff --git a/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.html b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.html new file mode 100644 index 000000000..b1380cba9 --- /dev/null +++ b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.html @@ -0,0 +1,8 @@ +
+

+ {{ 'collections.helpDialog.message' | translate }} + {{ 'collections.helpDialog.linkText' | translate }}. +

+
diff --git a/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.scss b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.scss new file mode 100644 index 000000000..fd23f1af8 --- /dev/null +++ b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.scss @@ -0,0 +1,7 @@ +@use "assets/styles/variables" as var; + +.dialog-content { + border-top: 1px solid var.$grey-2; + border-bottom: 1px solid var.$grey-2; + line-height: 2; +} diff --git a/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.spec.ts b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.spec.ts new file mode 100644 index 000000000..4b4f68aae --- /dev/null +++ b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CollectionsHelpDialogComponent } from './collections-help-dialog.component'; + +describe('CollectionsHelpDialogComponent', () => { + let component: CollectionsHelpDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CollectionsHelpDialogComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(CollectionsHelpDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.ts b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.ts new file mode 100644 index 000000000..c337e8ec7 --- /dev/null +++ b/src/app/features/collections/components/collections-help-dialog/collections-help-dialog.component.ts @@ -0,0 +1,12 @@ +import { TranslatePipe } from '@ngx-translate/core'; + +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'osf-collections-help-dialog', + imports: [TranslatePipe], + templateUrl: './collections-help-dialog.component.html', + styleUrl: './collections-help-dialog.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CollectionsHelpDialogComponent {} diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts index 1ce992531..322f0bbd4 100644 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts @@ -9,23 +9,24 @@ import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@a import { toSignal } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; -import { CollectionsFilterChipsComponent } from '@osf/features/collections/components/collections-filter-chips/collections-filter-chips.component'; -import { CollectionsFiltersComponent } from '@osf/features/collections/components/collections-filters/collections-filters.component'; -import { CollectionsSearchResultsComponent } from '@osf/features/collections/components/collections-search-results/collections-search-results.component'; +import { CollectionsFilterChipsComponent, CollectionsFiltersComponent } from '@osf/features/collections/components'; import { CollectionsSelectors } from '@osf/features/collections/store'; import { SORT_OPTIONS } from '@osf/features/collections/utils/sort-options.const'; import { IS_WEB } from '@shared/utils'; +import { CollectionsSearchResultsComponent } from '../collections-search-results'; + @Component({ selector: 'osf-collections-main-content', + standalone: true, imports: [ NgOptimizedImage, Select, FormsModule, + TranslatePipe, + CollectionsFilterChipsComponent, CollectionsFiltersComponent, CollectionsSearchResultsComponent, - CollectionsFilterChipsComponent, - TranslatePipe, ], templateUrl: './collections-main-content.component.html', styleUrl: './collections-main-content.component.scss', diff --git a/src/app/features/collections/components/collections-main-content/index.ts b/src/app/features/collections/components/collections-main-content/index.ts new file mode 100644 index 000000000..1dc736ffc --- /dev/null +++ b/src/app/features/collections/components/collections-main-content/index.ts @@ -0,0 +1 @@ +export { CollectionsMainContentComponent } from './collections-main-content.component'; diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts index 7209eaad2..d1e1bdc7a 100644 --- a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts +++ b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts @@ -3,8 +3,8 @@ import { TranslatePipe } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; -import { CollectionSearchResultCard } from '@osf/features/collections/models/collection-search-result-card.models'; -import { SUBMISSION_ATTRIBUTES } from '@osf/features/collections/utils/submission-attributes.const'; +import { CollectionSearchResultCard } from '@osf/features/collections/models'; +import { SUBMISSION_ATTRIBUTES } from '@osf/features/collections/utils'; @Component({ selector: 'osf-collections-search-result-card', diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts index 71eb6b152..f172ae96e 100644 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts @@ -3,84 +3,17 @@ import { Paginator } from 'primeng/paginator'; import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { CollectionsSearchResultCardComponent } from '@osf/features/collections/components/collections-search-result-card/collections-search-result-card.component'; -import { CollectionSearchResultCard } from '@osf/features/collections/models/collection-search-result-card.models'; +import { CollectionsSearchResultCardComponent } from '@osf/features/collections/components'; +import { CollectionSearchResultCard } from '@osf/features/collections/models'; +import { SEARCH_RESULT_CARDS_DATA } from '@osf/features/collections/utils'; @Component({ selector: 'osf-collections-search-results', - imports: [DataView, CollectionsSearchResultCardComponent, Paginator], + imports: [DataView, Paginator, CollectionsSearchResultCardComponent], templateUrl: './collections-search-results.component.html', styleUrl: './collections-search-results.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class CollectionsSearchResultsComponent { - // Mocked search results data - protected searchResults: CollectionSearchResultCard[] = [ - { - id: '1', - title: 'Pseudo-Random Sonications For Brain HIFU', - description: - 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', - dateCreated: new Date('2019-01-28'), - dateModified: new Date('2019-01-28'), - category: 'Research', - contributors: [ - { id: '1', name: 'Lin Wang' }, - { id: '2', name: 'Roman Nastyuk' }, - ], - programArea: 'Technica', - status: 'Completed', - collectedType: '', - dataType: '', - disease: '', - gradeLevels: '', - issue: '', - reviewsState: '', - schoolType: '', - studyDesign: '', - volume: '', - }, - { - id: '2', - title: 'Simulation Of Transcranial FUS Propagation', - description: - "While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, there are currently no precise tools for patient's selection and treatment planning. in this project, focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders", - dateCreated: new Date('2019-01-28'), - dateModified: new Date('2019-01-28'), - category: 'Research', - contributors: [{ id: '1', name: 'Lin Wang' }], - programArea: 'Technica', - status: 'Active', - collectedType: '', - dataType: '', - disease: '', - gradeLevels: '', - issue: '', - reviewsState: '', - schoolType: '', - studyDesign: '', - volume: '', - }, - { - id: '3', - title: 'Sonications For Brain HIFU', - description: - 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', - dateCreated: new Date('2019-01-28'), - dateModified: new Date('2019-01-28'), - category: 'Research', - contributors: [{ id: '2', name: 'Roman Nastyuk' }], - programArea: 'Technica', - status: 'Completed', - collectedType: '', - dataType: '', - disease: '', - gradeLevels: '', - issue: '', - reviewsState: '', - schoolType: '', - studyDesign: '', - volume: '', - }, - ]; + protected searchResults: CollectionSearchResultCard[] = SEARCH_RESULT_CARDS_DATA; } diff --git a/src/app/features/collections/components/collections-search-results/index.ts b/src/app/features/collections/components/collections-search-results/index.ts new file mode 100644 index 000000000..46aae45b1 --- /dev/null +++ b/src/app/features/collections/components/collections-search-results/index.ts @@ -0,0 +1 @@ +export { CollectionsSearchResultsComponent } from './collections-search-results.component'; diff --git a/src/app/features/collections/components/index.ts b/src/app/features/collections/components/index.ts new file mode 100644 index 000000000..43899a75d --- /dev/null +++ b/src/app/features/collections/components/index.ts @@ -0,0 +1,9 @@ +// Export leaf components directly (no internal dependencies) +export { CollectionsFilterChipsComponent } from './collections-filter-chips/collections-filter-chips.component'; +export { CollectionsFiltersComponent } from './collections-filters/collections-filters.component'; +export { CollectionsHelpDialogComponent } from './collections-help-dialog/collections-help-dialog.component'; +export { CollectionsSearchResultCardComponent } from './collections-search-result-card/collections-search-result-card.component'; + +// Export components with dependencies through their individual barrels +export { CollectionsMainContentComponent } from './collections-main-content'; +export { CollectionsSearchResultsComponent } from './collections-search-results'; diff --git a/src/app/features/collections/models/collections-filters.model.ts b/src/app/features/collections/models/collections-filters.model.ts new file mode 100644 index 000000000..a46209d6c --- /dev/null +++ b/src/app/features/collections/models/collections-filters.model.ts @@ -0,0 +1,13 @@ +export interface CollectionsFilters { + programArea: string[]; + status: string[]; + collectedType: string[]; + dataType: string[]; + disease: string[]; + gradeLevels: string[]; + issue: string[]; + reviewsState: string[]; + schoolType: string[]; + studyDesign: string[]; + volume: string[]; +} diff --git a/src/app/features/collections/models/index.ts b/src/app/features/collections/models/index.ts index 5fc921fd5..3f2eb70df 100644 --- a/src/app/features/collections/models/index.ts +++ b/src/app/features/collections/models/index.ts @@ -1,2 +1,3 @@ export * from './collection-search-result-card.models'; export * from './collections.models'; +export * from './collections-filters.model'; diff --git a/src/app/features/collections/store/collections.model.ts b/src/app/features/collections/store/collections.model.ts index b3d8ddde2..a83c87c5c 100644 --- a/src/app/features/collections/store/collections.model.ts +++ b/src/app/features/collections/store/collections.model.ts @@ -1,19 +1,6 @@ +import { CollectionsFilters } from '@osf/features/collections/models'; import { AsyncStateModel } from '@osf/shared/models/store'; -export interface CollectionsFilters { - programArea: string[]; - status: string[]; - collectedType: string[]; - dataType: string[]; - disease: string[]; - gradeLevels: string[]; - issue: string[]; - reviewsState: string[]; - schoolType: string[]; - studyDesign: string[]; - volume: string[]; -} - export interface CollectionsStateModel { bookmarksId: AsyncStateModel; filters: CollectionsFilters; diff --git a/src/app/features/collections/store/collections.selectors.ts b/src/app/features/collections/store/collections.selectors.ts index fb09b395d..7f8c27039 100644 --- a/src/app/features/collections/store/collections.selectors.ts +++ b/src/app/features/collections/store/collections.selectors.ts @@ -1,6 +1,8 @@ import { Selector } from '@ngxs/store'; -import { CollectionsFilters, CollectionsStateModel } from './collections.model'; +import { CollectionsFilters } from '@osf/features/collections/models'; + +import { CollectionsStateModel } from './collections.model'; import { CollectionsState } from './collections.state'; export class CollectionsSelectors { diff --git a/src/app/features/collections/utils/index.ts b/src/app/features/collections/utils/index.ts index 5161b6f95..de5ab9ae8 100644 --- a/src/app/features/collections/utils/index.ts +++ b/src/app/features/collections/utils/index.ts @@ -1 +1,3 @@ +export * from './mocked-data.const'; export * from './sort-options.const'; +export * from './submission-attributes.const'; diff --git a/src/app/features/collections/utils/mocked-data.const.ts b/src/app/features/collections/utils/mocked-data.const.ts new file mode 100644 index 000000000..0cb330780 --- /dev/null +++ b/src/app/features/collections/utils/mocked-data.const.ts @@ -0,0 +1,102 @@ +export const SEARCH_RESULT_CARDS_DATA = [ + { + id: '1', + title: 'Pseudo-Random Sonications For Brain HIFU', + description: + 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [ + { id: '1', name: 'Lin Wang' }, + { id: '2', name: 'Roman Nastyuk' }, + ], + programArea: 'Technica', + status: 'Completed', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, + { + id: '2', + title: 'Simulation Of Transcranial FUS Propagation', + description: + "While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, there are currently no precise tools for patient's selection and treatment planning. in this project, focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders", + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [{ id: '1', name: 'Lin Wang' }], + programArea: 'Technica', + status: 'Active', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, + { + id: '3', + title: 'Sonications For Brain HIFU', + description: + 'While transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired transcranial high intensity focused ultrasound is used in clinics for treating essential tremor and proposed for many other brain disorders, this promising treatment modality requires high energy resulting eventually in undesired ', + dateCreated: new Date('2019-01-28'), + dateModified: new Date('2019-01-28'), + category: 'Research', + contributors: [{ id: '2', name: 'Roman Nastyuk' }], + programArea: 'Technica', + status: 'Completed', + collectedType: '', + dataType: '', + disease: '', + gradeLevels: '', + issue: '', + reviewsState: '', + schoolType: '', + studyDesign: '', + volume: '', + }, +]; + +export const PROGRAM_AREA_FILTERS_OPTIONS = [ + { label: 'Public Policy', value: 'Public Policy' }, + { label: 'Child Welfare', value: 'Child Welfare' }, + { label: 'Criminal Justice', value: 'Criminal Justice' }, + { label: 'Medicine', value: 'Medicine' }, + { label: 'Public Health', value: 'Public Health' }, + { label: 'Social Work', value: 'Social Work' }, + { label: 'Nursing', value: 'Nursing' }, + { label: 'Education', value: 'Education' }, + { label: 'Law & Jurisprudence', value: 'Law & Jurisprudence' }, + { label: 'N/A', value: 'N/A' }, +]; + +export const COLLECTED_TYPE_FILTERS_OPTIONS = [ + { label: 'Experiments', value: 'Experiments' }, + { label: 'Interviews', value: 'Interviews' }, + { label: 'Grounded Theory', value: 'Grounded Theory' }, + { label: 'Action Research', value: 'Action Research' }, + { label: 'Case Studies', value: 'Case Studies' }, + { label: 'Direct Observation', value: 'Direct Observation' }, + { label: 'Document Analysis', value: 'Document Analysis' }, + { label: 'Interpretive Research', value: 'Interpretive Research' }, + { label: 'Participatory Action Research', value: 'Participatory Action Research' }, + { label: 'Event-Sampling', value: 'Event-Sampling' }, + { label: 'Surveys', value: 'Surveys' }, + { label: 'Quasi-Experiments', value: 'Quasi-Experiments' }, + { label: 'Ethnography', value: 'Ethnography' }, + { label: 'Social Network Analysis', value: 'Social Network Analysis' }, + { label: 'Critical Research Methods', value: 'Critical Research Methods' }, + { label: 'Design Research', value: 'Design Research' }, + { label: 'Discourse Analysis', value: 'Discourse Analysis' }, + { label: 'Research Synthesis', value: 'Research Synthesis' }, +]; diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 8a4640067..83f044d3d 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -559,6 +559,11 @@ "buttons": { "addToCollection": "Add to Collection" }, + "helpDialog": { + "header": "Search help", + "message": "OSF Search provides a powerful discovery tool to help you find data, papers, analysis plans, and more content across the research lifecycle. OSF Collections have some specialized filters, which you can learn more about on our ", + "linkText": "help page" + }, "searchInput": { "placeholder": "Enter search term(s) here" }, diff --git a/src/assets/styles/overrides/button.scss b/src/assets/styles/overrides/button.scss index 515112eb6..4f32eb2ad 100644 --- a/src/assets/styles/overrides/button.scss +++ b/src/assets/styles/overrides/button.scss @@ -283,7 +283,7 @@ .p-button { box-shadow: none; - @media (max-width: 575px) { + @media (max-width: var.$breakpoint-sm) { padding: 0; } } @@ -295,7 +295,7 @@ background-color: var(--p-button-primary-color); color: var.$white; - @media (max-width: 575px) { + @media (max-width: var.$breakpoint-sm) { width: 100%; } } diff --git a/src/assets/styles/overrides/confirmation-dialog.scss b/src/assets/styles/overrides/confirmation-dialog.scss index 50efc3b59..c047aca97 100644 --- a/src/assets/styles/overrides/confirmation-dialog.scss +++ b/src/assets/styles/overrides/confirmation-dialog.scss @@ -1,12 +1,13 @@ @use "../variables" as var; +@use "../mixins" as mix; .p-dialog-mask { z-index: 2103 !important; } .p-dialog { - min-height: 212px; - width: 450px; + min-height: mix.rem(224px); + width: mix.rem(550px); margin: 1rem; .p-dialog-header { From 20a47153ecf05b30b158b6b617fe420ee5ee22e0 Mon Sep 17 00:00:00 2001 From: Roman Nastyuk Date: Tue, 3 Jun 2025 12:02:52 +0300 Subject: [PATCH 3/3] feat(design-collections-page): fixed circular dependency imports issue --- src/app/features/collections/collections.component.ts | 3 +-- .../collections-main-content.component.ts | 7 ++++--- .../components/collections-main-content/index.ts | 1 - .../collections-search-results.component.ts | 3 ++- .../components/collections-search-results/index.ts | 1 - src/app/features/collections/components/index.ts | 7 ++----- 6 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 src/app/features/collections/components/collections-main-content/index.ts delete mode 100644 src/app/features/collections/components/collections-search-results/index.ts diff --git a/src/app/features/collections/collections.component.ts b/src/app/features/collections/collections.component.ts index 30ae6aaee..763278786 100644 --- a/src/app/features/collections/collections.component.ts +++ b/src/app/features/collections/collections.component.ts @@ -7,10 +7,9 @@ import { NgOptimizedImage } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormControl } from '@angular/forms'; +import { CollectionsHelpDialogComponent, CollectionsMainContentComponent } from '@osf/features/collections/components'; import { SearchInputComponent } from '@shared/components'; -import { CollectionsHelpDialogComponent, CollectionsMainContentComponent } from './components'; - @Component({ selector: 'osf-collections', imports: [NgOptimizedImage, SearchInputComponent, TranslatePipe, Button, CollectionsMainContentComponent], diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts index 322f0bbd4..b4524bce7 100644 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts +++ b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts @@ -9,12 +9,13 @@ import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@a import { toSignal } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; -import { CollectionsFilterChipsComponent, CollectionsFiltersComponent } from '@osf/features/collections/components'; import { CollectionsSelectors } from '@osf/features/collections/store'; -import { SORT_OPTIONS } from '@osf/features/collections/utils/sort-options.const'; +import { SORT_OPTIONS } from '@osf/features/collections/utils'; import { IS_WEB } from '@shared/utils'; -import { CollectionsSearchResultsComponent } from '../collections-search-results'; +import { CollectionsFilterChipsComponent } from '../collections-filter-chips/collections-filter-chips.component'; +import { CollectionsFiltersComponent } from '../collections-filters/collections-filters.component'; +import { CollectionsSearchResultsComponent } from '../collections-search-results/collections-search-results.component'; @Component({ selector: 'osf-collections-main-content', diff --git a/src/app/features/collections/components/collections-main-content/index.ts b/src/app/features/collections/components/collections-main-content/index.ts deleted file mode 100644 index 1dc736ffc..000000000 --- a/src/app/features/collections/components/collections-main-content/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CollectionsMainContentComponent } from './collections-main-content.component'; diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts index f172ae96e..1c816c7bb 100644 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts +++ b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts @@ -3,10 +3,11 @@ import { Paginator } from 'primeng/paginator'; import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { CollectionsSearchResultCardComponent } from '@osf/features/collections/components'; import { CollectionSearchResultCard } from '@osf/features/collections/models'; import { SEARCH_RESULT_CARDS_DATA } from '@osf/features/collections/utils'; +import { CollectionsSearchResultCardComponent } from '../collections-search-result-card/collections-search-result-card.component'; + @Component({ selector: 'osf-collections-search-results', imports: [DataView, Paginator, CollectionsSearchResultCardComponent], diff --git a/src/app/features/collections/components/collections-search-results/index.ts b/src/app/features/collections/components/collections-search-results/index.ts deleted file mode 100644 index 46aae45b1..000000000 --- a/src/app/features/collections/components/collections-search-results/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CollectionsSearchResultsComponent } from './collections-search-results.component'; diff --git a/src/app/features/collections/components/index.ts b/src/app/features/collections/components/index.ts index 43899a75d..61ceb51e6 100644 --- a/src/app/features/collections/components/index.ts +++ b/src/app/features/collections/components/index.ts @@ -1,9 +1,6 @@ -// Export leaf components directly (no internal dependencies) export { CollectionsFilterChipsComponent } from './collections-filter-chips/collections-filter-chips.component'; export { CollectionsFiltersComponent } from './collections-filters/collections-filters.component'; export { CollectionsHelpDialogComponent } from './collections-help-dialog/collections-help-dialog.component'; +export { CollectionsMainContentComponent } from './collections-main-content/collections-main-content.component'; export { CollectionsSearchResultCardComponent } from './collections-search-result-card/collections-search-result-card.component'; - -// Export components with dependencies through their individual barrels -export { CollectionsMainContentComponent } from './collections-main-content'; -export { CollectionsSearchResultsComponent } from './collections-search-results'; +export { CollectionsSearchResultsComponent } from './collections-search-results/collections-search-results.component';