diff --git a/src/app/app.config.ts b/src/app/app.config.ts index a477915a3..012c16ab5 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -10,13 +10,14 @@ import { provideHttpClient } from '@angular/common/http'; import { ConfirmationService } from 'primeng/api'; import { AuthState } from '@core/store/auth'; import { HomeState } from '@core/store/home'; +import { ResourceFiltersState } from '@shared/components/resources/resource-filters/store/resource-filters.state'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideStore( - [AuthState, HomeState], + [AuthState, HomeState, ResourceFiltersState], withNgxsReduxDevtoolsPlugin({ disabled: false }), ), providePrimeNG({ diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index f103b6436..01f4f50bc 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,4 +1,6 @@ import { Routes } from '@angular/router'; +import { provideStates } from '@ngxs/store'; +import { ResourceFiltersState } from '@shared/components/resources/resource-filters/store/resource-filters.state'; export const routes: Routes = [ { @@ -71,6 +73,14 @@ export const routes: Routes = [ (mod) => mod.settingsRoutes, ), }, + { + path: 'search', + loadComponent: () => + import('./features/search/search.component').then( + (mod) => mod.SearchComponent, + ), + providers: [provideStates([ResourceFiltersState])], + }, ], }, ]; diff --git a/src/app/features/search/data.ts b/src/app/features/search/data.ts new file mode 100644 index 000000000..c53ac5a84 --- /dev/null +++ b/src/app/features/search/data.ts @@ -0,0 +1,318 @@ +import { Resource } from '@osf/features/search/models/resource.entity'; +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; + +export const resources: Resource[] = [ + { + id: 'https://osf.io/wrfgp', + resourceType: ResourceType.File, + dateCreated: new Date('2025-01-10'), + dateModified: new Date('2025-01-14'), + creators: [ + { + id: 'https://osf.io/a6t2x', + name: 'Lívia Rodrigues de Lima Pires', + }, + ], + fileName: 'dadosAnalisados.rds', + from: { + id: 'https://osf.io/e86jf', + name: 'Tese', + }, + }, + { + id: 'https://osf.io/4crzf', + resourceType: ResourceType.Project, + dateCreated: new Date('2025-01-15'), + dateModified: new Date('2025-01-18'), + creators: [ + { + id: 'https://osf.io/4fy2t', + name: 'Jane Simpson', + }, + { + id: 'https://osf.io/5jv47', + name: 'Wendy Francis', + }, + { + id: 'https://osf.io/6a5yb', + name: 'Daniel Wadsworth', + }, + { + id: 'https://osf.io/6g7nc', + name: 'Kristen Tulloch', + }, + { + id: 'https://osf.io/7a3tm', + name: 'Dr Tamara Sysak', + }, + { + id: 'https://osf.io/b8tvg', + name: 'PJ Humphreys', + }, + { + id: 'https://osf.io/n2hyv', + name: 'Alison Craswell', + }, + { + id: 'https://osf.io/qtnc8', + name: 'Apil Gurung', + }, + { + id: 'https://osf.io/qvuw6', + name: 'Karen Watson', + }, + { + id: 'https://osf.io/zwu3t', + name: 'Helen Szabo', + }, + ], + title: + 'Intergenerational community home sharing for older adults and university students: A scoping review protocol.', + description: + 'The objective of this scoping review is to review programs designed to facilitate matches between older adults residing within the community and university students. This protocol provides an overview of the topic, justification for and methods to be implemented in the conduct and reporting of the scoping review.', + }, + { + id: 'https://osf.io/pgmhr', + resourceType: ResourceType.File, + dateCreated: new Date('2025-01-17'), + dateModified: new Date('2025-01-17'), + creators: [{ id: 'https://osf.io/65nk7', name: 'Aline Miranda Ferreira' }], + fileName: 'Scoping review protocol.pdf', + license: 'MIT License', + from: { + id: 'https://osf.io/4wks9', + name: 'Instruments for Measuring Pain, Functionality, and Quality of Life Following Knee Fractures: A Scoping Review', + }, + }, + { + id: 'https://osf.io/f7h5v', + resourceType: ResourceType.File, + dateCreated: new Date('2025-01-29'), + dateModified: new Date('2025-01-29'), + creators: [{ id: 'https://osf.io/d7rtw', name: 'David P. Goldenberg' }], + fileName: 'PCB.zip', + from: { + id: 'https://osf.io/qs7r9', + name: 'Design Files', + }, + }, + { + id: 'https://osf.io/3ua54', + resourceType: ResourceType.Project, + dateCreated: new Date('2025-03-16'), + dateModified: new Date('2025-03-16'), + creators: [{ id: 'https://osf.io/uby48', name: 'Aadit Nair Sajeev' }], + title: + 'Unemployment of Locals in Kochi due to the Augmented Influx of Migrant Workers', + description: + 'This project page includes supplementals like interview transcript for a case study into the unemployment of locals due to increasing influx of migrant workers into the state.', + }, + { + id: 'https://osf.io/xy9qn', + resourceType: ResourceType.Project, + dateCreated: new Date('2025-03-16'), + dateModified: new Date('2025-03-16'), + creators: [ + { + id: 'https://osf.io/x87gf', + name: 'Doctor Jack Samuel Egerton MSci EngD', + }, + ], + title: 'Stone functions (tetration)', + }, + { + id: 'https://osf.io/cpm64', + resourceType: ResourceType.Registration, + dateCreated: new Date('2025-01-10'), + dateModified: new Date('2025-01-10'), + creators: [ + { + id: 'https://osf.io/4fy2t', + name: 'Simran Khanna', + }, + { + id: 'https://osf.io/5jv47', + name: 'Devika Shenoy', + }, + { + id: 'https://osf.io/6a5yb', + name: 'Steph Hendren', + }, + { + id: 'https://osf.io/6g7nc', + name: 'Christian Zirbes', + }, + { + id: 'https://osf.io/7a3tm', + name: 'Anthony Catanzano', + }, + { + id: 'https://osf.io/b8tvg', + name: 'Rachelle Shao', + }, + { + id: 'https://osf.io/n2hyv', + name: 'Sofiu Ogunbiyi', + }, + { + id: 'https://osf.io/qtnc8', + name: 'Evelyn Hunter', + }, + { + id: 'https://osf.io/qvuw6', + name: 'Katie Radulovacki', + }, + { + id: 'https://osf.io/zwu3t', + name: 'Muhamed Sanneh', + }, + ], + title: + 'A Scoping Review and Meta-analysis Exploring the Associations between Socioeconomic Identity and Management of Pediatric Extremity Fracture', + description: + 'The incidence and management of extremity fractures in pediatric patients can be influenced by social and financial deprivation. Previous studies have highlighted that the social determinants of health, such as socioeconomic status, race, and insurance type, are independently associated with the incidence of pediatric fractures . [1, 2] This underscores the need to understand how these factors specifically affect fracture management in pediatric populations.\n\nIn addition to incidence, socioeconomic status has been shown to impact the timing and type of treatment for fractures. Vazquez et al. demonstrated that adolescents from poor socioeconomic backgrounds were more likely to experience delayed surgical fixation of femoral fractures, which was associated with worse outcomes, including longer hospital stays and higher healthcare costs.[2] Similarly, Evans et al. reported that children from socially deprived areas had worse perceived function and pain outcomes after upper extremity fractures, even after receiving orthopedic treatment.[3] These findings suggest that social deprivation not only affects initial access to care but also influences recovery and long-term outcomes.\n\nThe proposed scoping review and meta-analysis will systematically evaluate the existing literature to map out the extent and nature of the impact of social and financial deprivation on extremity fracture management in pediatric patients. By including a wide range of sociodemographic variables and outcomes, this review aims to provide a comprehensive understanding of the disparities in fracture care. This will inform future research and policy-making to address these inequities and improve healthcare delivery for socially and economically disadvantaged pediatric populations.\n\n[1] Dy CJ, Lyman S, Do HT, Fabricant PD, Marx RG, Green DW. Socioeconomic factors are associated with frequency of repeat emergency department visits for pediatric closed fractures. J Pediatr Orthop. 2014;34(5):548-551. doi:10.1097/BPO.0000000000000143\n[2] Ramaesh R, Clement ND, Rennie L, Court-Brown C, Gaston MS. Social deprivation as a risk factor for fractures in childhood. Bone Joint J. 2015;97-B(2):240-245. doi:10.1302/0301-620X.97B2.34057\n[3] Vazquez S, Dominguez JF, Jacoby M, et al. Poor socioeconomic status is associated with delayed femoral fracture fixation in adolescent patients. Injury. 2023;54(12):111128. doi:10.1016/j.injury.2023.111128', + license: 'No license', + publisher: { + id: 'https://osf.io/registries/osf', + name: 'OSF Registries', + }, + registrationTemplate: 'Generalized Systematic Review Registration', + doi: 'https://doi.org/10.17605/OSF.IO/CPM64', + }, + { + id: 'https://osf.io/8tk45', + resourceType: ResourceType.Registration, + dateCreated: new Date('2025-03-06'), + dateModified: new Date('2025-03-06'), + creators: [ + { + id: 'https://osf.io/45kpt', + name: 'Laura A. King', + }, + { + id: 'https://osf.io/cuqrk', + name: 'Erica A. Holberg', + }, + ], + title: 'Consequentialist Criteria: Money x Effort (Between)', + description: + "This is the first of two studies aimed at testing whether the effect of amount of money raised for a good cause is present in within person comparisons, but null when utilizing a between person design. In previous studies, we have found that success in achieving an agent's morally good aim and high cost to agent for doing the right thing are salient to moral evaluators when the explicit contrast to failure or low cost is made (within person), but not particularly salient to moral evaluation when the explicit contrast is not drawn (between person). In this study, we are interested to determine the relative presence and strength of amount of money raised (a consequentialist criterion for moral evaluation) and effort put forth (a non-consequentialist moral criterion centered on the agent's will) when this is not explicitly contrasted because using a between-person design. In a pilot study, we found no effect of money upon moral goodness. There was an effect of money upon effort for the low condition ($50). We want to see how results are altered if we add an explicit factor for effort. Does amount of money have null effect upon perceived moral goodness? Does effort have a larger effect upon perceived moral goodness than amount of money raised? \n\nParticipants will read scenarios reflecting a 3 (money: extremely high vs. high vs. low) x 3 (effort: high vs. no mention vs. low) design. In all 9 scenarios, participants will rate the moral goodness of a person who raises money for and then runs in a 5K for a good cause, where the conditions vary as described above. They also will answer how likely it is that the target would undertake a similar volunteer commitment in the future.", + publisher: { + id: 'https://osf.io/registries/osf', + name: 'OSF Registries', + }, + registrationTemplate: 'OSF Preregistration', + license: 'No license', + doi: 'https://doi.org/10.17605/OSF.IO/8TK45', + }, + { + id: 'https://osf.io/wa6yf', + resourceType: ResourceType.File, + dateCreated: new Date('2025-01-14'), + dateModified: new Date('2025-01-14'), + creators: [ + { + id: 'https://osf.io/6nkxv', + name: 'Kari-Anne B. Næss', + }, + { + id: 'https://osf.io/b2g9q', + name: 'Frida Johanne Holmen ', + }, + { + id: 'https://osf.io/j6hd5', + name: 'Thormod Idsøe', + }, + ], + from: { + id: 'https://osf.io/tbzv6', + name: 'A Cross-sectional Study of Inference-making Comparing First- and Second Language Learners in Early Childhood Education and Care', + }, + fileName: 'Model_FH_prereg_140125.pdf', + license: 'No license', + }, + { + id: 'https://osf.io/4hg87', + resourceType: ResourceType.ProjectComponent, + dateCreated: new Date('2025-01-04'), + dateModified: new Date('2025-01-04'), + creators: [ + { + id: 'https://osf.io/2x5kc', + name: 'Bowen Wang-Kildegaard', + }, + ], + title: 'Dataset and Codes', + }, + { + id: 'https://osf.io/87vyr', + resourceType: ResourceType.Preprint, + dateCreated: new Date('2025-02-20'), + dateModified: new Date('2025-02-20'), + creators: [ + { + id: 'https://osf.io/2x5kc', + name: 'Eric L. Olson', + }, + ], + title: 'Evaluative Judgment Across Domains', + description: + 'Keberadaan suatu organisme pada suatu tempat dipengaruhi oleh faktor lingkungan dan makanan. Ketersediaan makanan dengan kualitas yang cocok dan kuantitas yang ukup bagi suatu organisme akan meningkatkan populasi cepat. Sebaliknya jika keadaan tersebut tidak mendukung maka akan dipastikan bahwa organisme tersebut akan menurun. Sedangkan faktor abiotik meliputi suhu, kelembaban, cahaya, curah hujan, dan angin. Suhu mempengaruhi aktivitas serangga serta perkembangannya. Serangga juga tertarik pada gelombang cahaya tertentu. Serangga ada yang menerima intensitas cahaya yang tinggi dan aktif pada siang hari (diurnal) dan serangga ada yang aktif menerima intensitas cahaya rendah pada malam hari (nokturnal). Metode yang digunakan yaitu metode Light trap. Hail yang didapatkan bahwa komponen lingkungan (biotik dan abiotik) akan mempengaruhi kelimpahan dan keanekaragaman spesies pada suatu tempat sehingga tingginya kelimpahan individu tiap jenis dapat dipakai untuk menilai kualitas suatu habitat. Sehingga tidak semua serangga yang aktif pada siang hari tidak dapat aktif di malam hari karena efek adanya sinar tergantung sepenuhnya pada kondisi temperature dan kelembaban disekitar.', + provider: { + id: 'https://osf.io/preprints/osf', + name: 'Open Science Framework', + }, + conflictOfInterestResponse: 'Author asserted no Conflict of Interest', + license: 'No License', + doi: 'https://doi.org/10.31227/osf.io/fcs5r', + }, + { + id: 'https://osf.io/87vyr', + resourceType: ResourceType.Preprint, + dateCreated: new Date('2025-02-20'), + dateModified: new Date('2025-02-20'), + creators: [ + { + id: 'https://osf.io/2x5kc', + name: 'Fitha Kaamiliyaa Hamka', + }, + ], + title: + 'Identifikasi Serangga Nokturnal di Bukit Samata Kabupaten Gowa, Sulawesi Selatan', + description: + 'Keberadaan suatu organisme pada suatu tempat dipengaruhi oleh faktor lingkungan dan makanan. Ketersediaan makanan dengan kualitas yang cocok dan kuantitas yang ukup bagi suatu organisme akan meningkatkan populasi cepat. Sebaliknya jika keadaan tersebut tidak mendukung maka akan dipastikan bahwa organisme tersebut akan menurun. Sedangkan faktor abiotik meliputi suhu, kelembaban, cahaya, curah hujan, dan angin. Suhu mempengaruhi aktivitas serangga serta perkembangannya. Serangga juga tertarik pada gelombang cahaya tertentu. Serangga ada yang menerima intensitas cahaya yang tinggi dan aktif pada siang hari (diurnal) dan serangga ada yang aktif menerima intensitas cahaya rendah pada malam hari (nokturnal). Metode yang digunakan yaitu metode Light trap. Hail yang didapatkan bahwa komponen lingkungan (biotik dan abiotik) akan mempengaruhi kelimpahan dan keanekaragaman spesies pada suatu tempat sehingga tingginya kelimpahan individu tiap jenis dapat dipakai untuk menilai kualitas suatu habitat. Sehingga tidak semua serangga yang aktif pada siang hari tidak dapat aktif di malam hari karena efek adanya sinar tergantung sepenuhnya pada kondisi temperature dan kelembaban disekitar.', + provider: { + id: 'https://osf.io/preprints/osf', + name: 'Open Science Framework', + }, + conflictOfInterestResponse: 'Author asserted no Conflict of Interest', + license: 'No License', + doi: 'Keberadaan suatu organisme pada suatu tempat dipengaruhi oleh faktor lingkungan dan makanan. Ketersediaan makanan dengan kualitas yang cocok dan kuantitas yang ukup bagi suatu organisme akan meningkatkan populasi cepat. Sebaliknya jika keadaan tersebut tidak mendukung maka akan dipastikan bahwa organisme tersebut akan menurun. Sedangkan faktor abiotik meliputi suhu, kelembaban, cahaya, curah hujan, dan angin. Suhu mempengaruhi aktivitas serangga serta perkembangannya. Serangga juga tertarik pada gelombang cahaya tertentu. Serangga ada yang menerima intensitas cahaya yang tinggi dan aktif pada siang hari (diurnal) dan serangga ada yang aktif menerima intensitas cahaya rendah pada malam hari (nokturnal). Metode yang digunakan yaitu metode Light trap. Hail yang didapatkan bahwa komponen lingkungan (biotik dan abiotik) akan mempengaruhi kelimpahan dan keanekaragaman spesies pada suatu tempat sehingga tingginya kelimpahan individu tiap jenis dapat dipakai untuk menilai kualitas suatu habitat. Sehingga tidak semua serangga yang aktif pada siang hari tidak dapat aktif di malam hari karena efek adanya sinar tergantung sepenuhnya pada kondisi temperature dan kelembaban disekitar.', + }, + { + id: 'https://osf.io/cegxv', + resourceType: ResourceType.User, + title: 'Amelia Jamison', + publicProjects: 2, + publicRegistrations: 0, + publicPreprints: 0, + }, + { + id: 'https://osf.io/cegxv', + resourceType: ResourceType.User, + title: 'Cristal Alvarez', + publicProjects: 2, + publicRegistrations: 0, + publicPreprints: 0, + orcid: 'https://orcid.org/0000-0003-2697-7146', + }, + { + id: 'https://osf.io/cegxv', + resourceType: ResourceType.User, + title: 'Rohini Ganjoo', + publicProjects: 16, + publicRegistrations: 6, + publicPreprints: 3, + orcid: 'https://orcid.org/0000-0003-2697-7146', + }, +]; diff --git a/src/app/features/search/models/link-item.entity.ts b/src/app/features/search/models/link-item.entity.ts new file mode 100644 index 000000000..58978169c --- /dev/null +++ b/src/app/features/search/models/link-item.entity.ts @@ -0,0 +1,4 @@ +export interface LinkItem { + id: string; + name: string; +} diff --git a/src/app/features/search/models/resource-tab.enum.ts b/src/app/features/search/models/resource-tab.enum.ts new file mode 100644 index 000000000..beff65657 --- /dev/null +++ b/src/app/features/search/models/resource-tab.enum.ts @@ -0,0 +1,8 @@ +export enum ResourceTab { + All, + Projects, + Registrations, + Preprints, + Files, + Users, +} diff --git a/src/app/features/search/models/resource-type.enum.ts b/src/app/features/search/models/resource-type.enum.ts new file mode 100644 index 000000000..4750fc6bd --- /dev/null +++ b/src/app/features/search/models/resource-type.enum.ts @@ -0,0 +1,9 @@ +export enum ResourceType { + Null, + File, + Project, + Registration, + Preprint, + ProjectComponent, + User, +} diff --git a/src/app/features/search/models/resource.entity.ts b/src/app/features/search/models/resource.entity.ts new file mode 100644 index 000000000..905d3b1e6 --- /dev/null +++ b/src/app/features/search/models/resource.entity.ts @@ -0,0 +1,24 @@ +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; +import { LinkItem } from '@osf/features/search/models/link-item.entity'; + +export interface Resource { + id: string; + resourceType: ResourceType; + dateCreated?: Date; + dateModified?: Date; + creators?: LinkItem[]; + fileName?: string; + title?: string; + description?: string; + from?: LinkItem; + license?: string; + publisher?: LinkItem; + registrationTemplate?: string; + doi?: string; + provider?: LinkItem; + conflictOfInterestResponse?: string; + publicProjects?: number; + publicRegistrations?: number; + publicPreprints?: number; + orcid?: string; +} diff --git a/src/app/features/search/search.component.html b/src/app/features/search/search.component.html new file mode 100644 index 000000000..be9758979 --- /dev/null +++ b/src/app/features/search/search.component.html @@ -0,0 +1,97 @@ +
+ better-research + +
+ +
+ + @if (!isMobile()) { + + All + Projects + Registrations + Preprints + Files + Users + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/features/search/search.component.scss b/src/app/features/search/search.component.scss new file mode 100644 index 000000000..7d99fd2e6 --- /dev/null +++ b/src/app/features/search/search.component.scss @@ -0,0 +1,15 @@ +@use "assets/styles/variables" as var; + +:host { + .search-container { + margin: 6.2rem 1.7rem 0.4rem 1.7rem; + position: relative; + + img { + position: absolute; + right: 0.3rem; + top: 0.3rem; + z-index: 1; + } + } +} diff --git a/src/app/features/search/search.component.spec.ts b/src/app/features/search/search.component.spec.ts new file mode 100644 index 000000000..69681568f --- /dev/null +++ b/src/app/features/search/search.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SearchComponent } from './search.component'; + +describe('SearchComponent', () => { + let component: SearchComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SearchComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(SearchComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/search/search.component.ts b/src/app/features/search/search.component.ts new file mode 100644 index 000000000..24dc53c68 --- /dev/null +++ b/src/app/features/search/search.component.ts @@ -0,0 +1,88 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + inject, + signal, +} from '@angular/core'; +import { SearchInputComponent } from '@shared/components/search-input/search-input.component'; +import { DropdownModule } from 'primeng/dropdown'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { Tab, TabList, TabPanel, TabPanels, Tabs } from 'primeng/tabs'; +import { NgOptimizedImage } from '@angular/common'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { IS_XSMALL } from '@shared/utils/breakpoints.tokens'; +import { AutoCompleteModule } from 'primeng/autocomplete'; +import { AccordionModule } from 'primeng/accordion'; +import { TableModule } from 'primeng/table'; +import { DataViewModule } from 'primeng/dataview'; +import { ResourcesComponent } from '@shared/components/resources/resources.component'; +import { ResourceTab } from '@osf/features/search/models/resource-tab.enum'; +import { Resource } from '@osf/features/search/models/resource.entity'; +import { resources } from '@osf/features/search/data'; + +@Component({ + selector: 'osf-search', + imports: [ + SearchInputComponent, + DropdownModule, + ReactiveFormsModule, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, + NgOptimizedImage, + AutoCompleteModule, + FormsModule, + AccordionModule, + TableModule, + DataViewModule, + ResourcesComponent, + ], + templateUrl: './search.component.html', + styleUrl: './search.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SearchComponent { + protected searchValue = signal(''); + protected selectedTab = 0; + protected readonly isMobile = toSignal(inject(IS_XSMALL)); + + protected readonly resources = signal(resources); + protected readonly searchedResources = computed(() => { + const search = this.searchValue().toLowerCase(); + return this.resources().filter( + (resource: Resource) => + resource.title?.toLowerCase().includes(search) || + resource.fileName?.toLowerCase().includes(search) || + resource.description?.toLowerCase().includes(search) || + resource.creators + ?.map((p) => p.name.toLowerCase()) + .some((name) => name.includes(search)) || + resource.dateCreated + ?.toLocaleDateString('en-US', { + month: 'long', + day: 'numeric', + year: 'numeric', + }) + .toLowerCase() + .includes(search) || + resource.dateModified + ?.toLocaleDateString('en-US', { + month: 'long', + day: 'numeric', + year: 'numeric', + }) + .toLowerCase() + .includes(search) || + resource.from?.name.toLowerCase(), + ); + }); + + onTabChange(index: number): void { + this.selectedTab = index; + } + + protected readonly ResourceTab = ResourceTab; +} diff --git a/src/app/shared/components/resources/resource-card/resource-card.component.html b/src/app/shared/components/resources/resource-card/resource-card.component.html new file mode 100644 index 000000000..139448223 --- /dev/null +++ b/src/app/shared/components/resources/resource-card/resource-card.component.html @@ -0,0 +1,132 @@ +
+ + + +
+

{{ ResourceType[item().resourceType] }}

+ +
+ @if (item().resourceType === ResourceType.File) { +

{{ item().fileName }}

+ } @else { +

{{ item().title }}

+ } + @if (item().orcid) { + + orcid + + } +
+ + @if (item().creators?.length) { +
+ @for ( + creator of item().creators!.slice(0, 4); + track creator.id; + let i = $index + ) { + {{ creator.name }} + @if (i < item().creators!.length - 1 && i < 3) { + , + } + } + @if (item().creators!.length > 4) { + and {{ item().creators!.length - 4 }} more + } +
+ } + + @if (item().from) { + + } + +

+ Date created: {{ item().dateCreated | date: "MMMM d, y" }} | Date + modified: {{ item().dateModified | date: "MMMM d, y" }} +

+ + @if (item().resourceType === ResourceType.Registration) { + + } +
+
+ +
+ @if (item().description) { +

Description: {{ item().description }}

+ } + + @if (item().publisher) { + +

Registration provider:

+ {{ item().publisher?.name }} +
+ } + + @if (item().registrationTemplate) { +

+ Registration Template: {{ item().registrationTemplate }} +

+ } + + @if (item().provider) { + +

Provider:

+ {{ item().provider?.name }} +
+ } + + @if (item().conflictOfInterestResponse) { +

+ Conflict of Interest response: + {{ item().conflictOfInterestResponse }} +

+ } + + +

URL:

+ {{ item().id }} +
+ + @if (item().doi) { + +

DOI:

+ {{ item().doi }} +
+ } +
+
+
+
+
diff --git a/src/app/shared/components/resources/resource-card/resource-card.component.scss b/src/app/shared/components/resources/resource-card/resource-card.component.scss new file mode 100644 index 000000000..460f77cac --- /dev/null +++ b/src/app/shared/components/resources/resource-card/resource-card.component.scss @@ -0,0 +1,68 @@ +@use "../../../../../assets/styles/variables" as var; + +.resource { + display: flex; + flex-direction: column; + border: 1px solid var.$grey-2; + border-radius: 8px; + padding: 1.7rem; + row-gap: 0.85rem; + + h2 { + &:hover { + text-decoration: underline; + } + } + + a { + font-weight: bold; + display: inline; + + &:hover { + text-decoration: underline; + } + } + + .orcid-icon { + height: 16px; + } + + .type { + width: fit-content; + background: var.$grey-3; + font-weight: bold; + padding: 4px 12px 4px 12px; + border-radius: 4px; + } + + p { + color: var.$dark-blue-1; + font-weight: 400; + display: inline; + } + + .icon-container { + color: var.$dark-blue-1; + display: flex; + align-items: center; + column-gap: 0.3rem; + + &:hover { + text-decoration: none; + color: var.$pr-blue-1; + } + } + + .description { + display: block; + line-height: 2rem; + } + + .content { + display: flex; + flex-direction: column; + row-gap: 1rem; + border-top: 1px solid var.$grey-2; + padding-top: 1rem; + } +} diff --git a/src/app/shared/components/resources/resource-card/resource-card.component.spec.ts b/src/app/shared/components/resources/resource-card/resource-card.component.spec.ts new file mode 100644 index 000000000..9490eaf44 --- /dev/null +++ b/src/app/shared/components/resources/resource-card/resource-card.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ResourceCardComponent } from './resource-card.component'; + +describe('ResourceCardComponent', () => { + let component: ResourceCardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ResourceCardComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ResourceCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/resources/resource-card/resource-card.component.ts b/src/app/shared/components/resources/resource-card/resource-card.component.ts new file mode 100644 index 000000000..896cc8ac2 --- /dev/null +++ b/src/app/shared/components/resources/resource-card/resource-card.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { + Accordion, + AccordionContent, + AccordionHeader, + AccordionPanel, +} from 'primeng/accordion'; +import { DatePipe, NgOptimizedImage } from '@angular/common'; +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; +import { Resource } from '@osf/features/search/models/resource.entity'; + +@Component({ + selector: 'osf-resource-card', + imports: [ + Accordion, + AccordionContent, + AccordionHeader, + AccordionPanel, + DatePipe, + NgOptimizedImage, + ], + templateUrl: './resource-card.component.html', + styleUrl: './resource-card.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ResourceCardComponent { + item = input.required(); + + protected readonly ResourceType = ResourceType; +} diff --git a/src/app/shared/components/resources/resource-filters/resource-filters.component.html b/src/app/shared/components/resources/resource-filters/resource-filters.component.html new file mode 100644 index 000000000..fc35123ae --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/resource-filters.component.html @@ -0,0 +1,145 @@ + + + Creator + +
+

Filter creators by typing their name below

+ + [(ngModel)]="creator" [suggestions]="filteredCreators()" + (completeMethod)="setCreator($event)" + +
+
+
+ + + Date Created + +
+

+ Please select the creation date from the dropdown below +

+ + +
+
+
+ + + Funder + +
+

+ Please select the funder from the dropdown below or start typing for + find it +

+ + +
+
+
+ + + Subject + +
+

+ Please select the subject from the dropdown below or start typing for + find it +

+ + +
+
+
+ + + License + +
+

+ Please select the license from the dropdown below or start typing for + find it +

+ + +
+
+
+ + + Resource Type + +
+

+ Please select the resource type from the dropdown below or start + typing for find it +

+ + +
+
+
+ + + Institution + +
+

+ Please select the institution from the dropdown below or start typing + for find it +

+ + +
+
+
+ + + Provider + +
+

+ Please select the provider from the dropdown below or start typing for + find it +

+ + +
+
+
+ + + Part of Collection + +
+

+ Please select the part of collection from the dropdown below or start + typing for find it +

+ + +
+
+
+
diff --git a/src/app/shared/components/resources/resource-filters/resource-filters.component.scss b/src/app/shared/components/resources/resource-filters/resource-filters.component.scss new file mode 100644 index 000000000..6b72be59f --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/resource-filters.component.scss @@ -0,0 +1,20 @@ +@use "../../../../../assets/styles/variables" as var; + +:host { + border: 1px solid var.$grey-2; + border-radius: 12px; + padding: 0 1.7rem 0 1.7rem; + width: 30%; + height: fit-content; + + .content-body { + display: flex; + flex-direction: column; + row-gap: 1.5rem; + padding-bottom: 1.5rem; + + p { + font-weight: 300; + } + } +} diff --git a/src/app/shared/components/resources/resource-filters/resource-filters.component.spec.ts b/src/app/shared/components/resources/resource-filters/resource-filters.component.spec.ts new file mode 100644 index 000000000..a6959486d --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/resource-filters.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ResourceFiltersComponent } from './resource-filters.component'; + +describe('ResourceFiltersComponent', () => { + let component: ResourceFiltersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ResourceFiltersComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ResourceFiltersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/resources/resource-filters/resource-filters.component.ts b/src/app/shared/components/resources/resource-filters/resource-filters.component.ts new file mode 100644 index 000000000..4b17d3220 --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/resource-filters.component.ts @@ -0,0 +1,50 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + inject, + model, +} from '@angular/core'; +import { + Accordion, + AccordionContent, + AccordionHeader, + AccordionPanel, +} from 'primeng/accordion'; +import { + AutoComplete, + AutoCompleteCompleteEvent, + AutoCompleteModule, +} from 'primeng/autocomplete'; +import { Store } from '@ngxs/store'; +import { SetCreator } from '@shared/components/resources/resource-filters/store/resource-filters.actions'; + +@Component({ + selector: 'osf-resource-filters', + imports: [ + Accordion, + AccordionContent, + AccordionHeader, + AccordionPanel, + AutoComplete, + AutoCompleteModule, + ], + templateUrl: './resource-filters.component.html', + styleUrl: './resource-filters.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ResourceFiltersComponent { + readonly #store = inject(Store); + + creator = model(''); + creators: string[] = []; + filteredCreators = computed(() => { + return this.creators.filter((creator) => + creator.toLowerCase().includes(this.creator().toLowerCase()), + ); + }); + + setCreator(event: AutoCompleteCompleteEvent) { + this.#store.dispatch(new SetCreator(event.query)); + } +} diff --git a/src/app/shared/components/resources/resource-filters/store/index.ts b/src/app/shared/components/resources/resource-filters/store/index.ts new file mode 100644 index 000000000..6c3ba20b4 --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/store/index.ts @@ -0,0 +1,4 @@ +export * from './resource-filters.model'; +export * from './resource-filters.actions'; +export * from './resource-filters.selectors'; +export * from './resource-filters.state'; diff --git a/src/app/shared/components/resources/resource-filters/store/resource-filters.actions.ts b/src/app/shared/components/resources/resource-filters/store/resource-filters.actions.ts new file mode 100644 index 000000000..a4b8ab400 --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/store/resource-filters.actions.ts @@ -0,0 +1,46 @@ +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; + +export class SetCreator { + static readonly type = '[Resource Filters] Set Creator'; + constructor(public payload: string) {} +} + +export class SetDateCreated { + static readonly type = '[Resource Filters] Set DateCreated'; + constructor(public payload: Date) {} +} + +export class SetFunder { + static readonly type = '[Resource Filters] Set Funder'; + constructor(public payload: string) {} +} + +export class SetSubject { + static readonly type = '[Resource Filters] Set Subject'; + constructor(public payload: string) {} +} + +export class SetLicense { + static readonly type = '[Resource Filters] Set License'; + constructor(public payload: string) {} +} + +export class SetResourceType { + static readonly type = '[Resource Filters] Set Resource Type'; + constructor(public payload: ResourceType) {} +} + +export class SetInstitution { + static readonly type = '[Resource Filters] Set Institution'; + constructor(public payload: string) {} +} + +export class SetProvider { + static readonly type = '[Resource Filters] Set Provider'; + constructor(public payload: string) {} +} + +export class SetPartOfCollection { + static readonly type = '[Resource Filters] Set PartOfCollection'; + constructor(public payload: string) {} +} diff --git a/src/app/shared/components/resources/resource-filters/store/resource-filters.model.ts b/src/app/shared/components/resources/resource-filters/store/resource-filters.model.ts new file mode 100644 index 000000000..7da4e749b --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/store/resource-filters.model.ts @@ -0,0 +1,13 @@ +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; + +export interface ResourceFiltersStateModel { + creator: string; + dateCreated: Date; + funder: string; + subject: string; + license: string; + resourceType: ResourceType; + institution: string; + provider: string; + partOfCollection: string; +} diff --git a/src/app/shared/components/resources/resource-filters/store/resource-filters.selectors.ts b/src/app/shared/components/resources/resource-filters/store/resource-filters.selectors.ts new file mode 100644 index 000000000..64b0f654f --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/store/resource-filters.selectors.ts @@ -0,0 +1,51 @@ +import { ResourceFiltersState } from '@shared/components/resources/resource-filters/store/resource-filters.state'; +import { Selector } from '@ngxs/store'; +import { ResourceFiltersStateModel } from '@shared/components/resources/resource-filters/store/resource-filters.model'; +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; + +export class ResourceFiltersSelectors { + @Selector([ResourceFiltersState]) + static getCreator(state: ResourceFiltersStateModel): string { + return state.creator; + } + + @Selector([ResourceFiltersState]) + static getDateCreated(state: ResourceFiltersStateModel): Date { + return state.dateCreated; + } + + @Selector([ResourceFiltersState]) + static getFunder(state: ResourceFiltersStateModel): string { + return state.funder; + } + + @Selector([ResourceFiltersState]) + static getSubject(state: ResourceFiltersStateModel): string { + return state.subject; + } + + @Selector([ResourceFiltersState]) + static getLicense(state: ResourceFiltersStateModel): string { + return state.license; + } + + @Selector([ResourceFiltersState]) + static getResourceType(state: ResourceFiltersStateModel): ResourceType { + return state.resourceType; + } + + @Selector([ResourceFiltersState]) + static getInstitution(state: ResourceFiltersStateModel): string { + return state.institution; + } + + @Selector([ResourceFiltersState]) + static getProvider(state: ResourceFiltersStateModel): string { + return state.provider; + } + + @Selector([ResourceFiltersState]) + static getPartOfCollection(state: ResourceFiltersStateModel): string { + return state.partOfCollection; + } +} diff --git a/src/app/shared/components/resources/resource-filters/store/resource-filters.state.ts b/src/app/shared/components/resources/resource-filters/store/resource-filters.state.ts new file mode 100644 index 000000000..02b5f095b --- /dev/null +++ b/src/app/shared/components/resources/resource-filters/store/resource-filters.state.ts @@ -0,0 +1,90 @@ +import { ResourceFiltersStateModel } from '@shared/components/resources/resource-filters/store/resource-filters.model'; +import { Action, State, StateContext } from '@ngxs/store'; +import { + SetCreator, + SetDateCreated, + SetFunder, + SetInstitution, + SetLicense, + SetPartOfCollection, + SetProvider, + SetResourceType, + SetSubject, +} from '@shared/components/resources/resource-filters/store/resource-filters.actions'; +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; + +@State({ + name: 'resourceFilters', + defaults: { + creator: '', + dateCreated: new Date(), + funder: '', + subject: '', + license: '', + resourceType: ResourceType.Null, + institution: '', + provider: '', + partOfCollection: '', + }, +}) +export class ResourceFiltersState { + @Action(SetCreator) + setCreator(ctx: StateContext, action: SetCreator) { + ctx.patchState({ creator: action.payload }); + } + + @Action(SetDateCreated) + setDateCreated( + ctx: StateContext, + action: SetDateCreated, + ) { + ctx.patchState({ dateCreated: action.payload }); + } + + @Action(SetFunder) + setFunder(ctx: StateContext, action: SetFunder) { + ctx.patchState({ funder: action.payload }); + } + + @Action(SetSubject) + setSubject(ctx: StateContext, action: SetSubject) { + ctx.patchState({ subject: action.payload }); + } + + @Action(SetLicense) + setLicense(ctx: StateContext, action: SetLicense) { + ctx.patchState({ license: action.payload }); + } + + @Action(SetResourceType) + setResourceType( + ctx: StateContext, + action: SetResourceType, + ) { + ctx.patchState({ resourceType: action.payload }); + } + + @Action(SetInstitution) + setInstitution( + ctx: StateContext, + action: SetInstitution, + ) { + ctx.patchState({ institution: action.payload }); + } + + @Action(SetProvider) + setProvider( + ctx: StateContext, + action: SetProvider, + ) { + ctx.patchState({ provider: action.payload }); + } + + @Action(SetPartOfCollection) + setPartOfCollection( + ctx: StateContext, + action: SetPartOfCollection, + ) { + ctx.patchState({ partOfCollection: action.payload }); + } +} diff --git a/src/app/shared/components/resources/resources.component.html b/src/app/shared/components/resources/resources.component.html new file mode 100644 index 000000000..bca8489e9 --- /dev/null +++ b/src/app/shared/components/resources/resources.component.html @@ -0,0 +1,31 @@ +
+

10 000+ results

+
+

Sort by:

+ +
+
+ +
+ + + +
+ @for (item of items; track item.id) { + + } +
+
+
+
diff --git a/src/app/shared/components/resources/resources.component.scss b/src/app/shared/components/resources/resources.component.scss new file mode 100644 index 000000000..4cd392977 --- /dev/null +++ b/src/app/shared/components/resources/resources.component.scss @@ -0,0 +1,30 @@ +@use "assets/styles/variables" as var; + +:host { + h3 { + color: var.$pr-blue-1; + } + + .sorting-container { + display: flex; + align-items: center; + + h3 { + color: var.$dark-blue-1; + font-weight: 400; + text-wrap: nowrap; + margin-right: 0.5rem; + } + } + + .resources-container { + width: 70%; + + .resources-list { + width: 100%; + display: flex; + flex-direction: column; + row-gap: 0.85rem; + } + } +} diff --git a/src/app/shared/components/resources/resources.component.spec.ts b/src/app/shared/components/resources/resources.component.spec.ts new file mode 100644 index 000000000..fec111b58 --- /dev/null +++ b/src/app/shared/components/resources/resources.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ResourcesComponent } from './resources.component'; + +describe('ResourcesComponent', () => { + let component: ResourcesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ResourcesComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ResourcesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/resources/resources.component.ts b/src/app/shared/components/resources/resources.component.ts new file mode 100644 index 000000000..baeb7bfad --- /dev/null +++ b/src/app/shared/components/resources/resources.component.ts @@ -0,0 +1,83 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + inject, + input, +} from '@angular/core'; +import { TabOption } from '@shared/entities/tab-option.interface'; +import { Resource } from '@osf/features/search/models/resource.entity'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { IS_XSMALL } from '@shared/utils/breakpoints.tokens'; +import { ResourceType } from '@osf/features/search/models/resource-type.enum'; +import { DropdownModule } from 'primeng/dropdown'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ResourceFiltersComponent } from '@shared/components/resources/resource-filters/resource-filters.component'; +import { AutoCompleteModule } from 'primeng/autocomplete'; +import { AccordionModule } from 'primeng/accordion'; +import { TableModule } from 'primeng/table'; +import { DataViewModule } from 'primeng/dataview'; +import { ResourceCardComponent } from '@shared/components/resources/resource-card/resource-card.component'; +import { ResourceFiltersSelectors } from '@shared/components/resources/resource-filters/store/resource-filters.selectors'; +import { Store } from '@ngxs/store'; +import { ResourceTab } from '@osf/features/search/models/resource-tab.enum'; + +@Component({ + selector: 'osf-resources', + imports: [ + DropdownModule, + FormsModule, + ResourceFiltersComponent, + ReactiveFormsModule, + AutoCompleteModule, + AccordionModule, + TableModule, + DataViewModule, + ResourceCardComponent, + ], + templateUrl: './resources.component.html', + styleUrl: './resources.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ResourcesComponent { + selectedTab = input.required(); + searchedResources = input.required(); + protected readonly filteredResources = computed(() => { + return this.searchedResources().filter((resources) => { + switch (this.selectedTab()) { + case ResourceTab.Projects: + return ( + resources.resourceType === ResourceType.Project || + resources.resourceType === ResourceType.ProjectComponent + ); + case ResourceTab.Registrations: + return resources.resourceType === ResourceType.Registration; + case ResourceTab.Preprints: + return resources.resourceType === ResourceType.Preprint; + case ResourceTab.Files: + return resources.resourceType === ResourceType.File; + case ResourceTab.Users: + return resources.resourceType === ResourceType.User; + default: + return true; + } + }); + }); + + protected readonly isMobile = toSignal(inject(IS_XSMALL)); + defaultTabValue = 0; + + protected selectedSortTab = this.defaultTabValue; + protected readonly sortTabOptions: TabOption[] = [ + { label: 'Relevance', value: 0 }, + { label: 'Date created (newest)', value: 1 }, + { label: 'Date created (oldest)', value: 2 }, + { label: 'Date modified (newest)', value: 3 }, + { label: 'Date modified (oldest)', value: 4 }, + ]; + + readonly #store = inject(Store); + protected readonly creator = this.#store.selectSignal( + ResourceFiltersSelectors.getCreator, + ); +} diff --git a/src/assets/styles/overrides/accordion.scss b/src/assets/styles/overrides/accordion.scss new file mode 100644 index 000000000..e5ffab605 --- /dev/null +++ b/src/assets/styles/overrides/accordion.scss @@ -0,0 +1,61 @@ +@use "assets/styles/variables" as var; + +.p-accordion { + display: flex; + flex-direction: column; + + .p-accordionheader { + height: 5.1rem; + color: var.$dark-blue-1; + font-weight: 700; + padding: 0; + display: flex; + + .p-iconwrapper { + transform: rotate(180deg); + + svg { + color: var.$grey-1; + } + } + } + + .p-accordioncontent-content { + padding: 0; + } +} + +.accordion-auto-height { + .p-accordion { + .p-accordionheader { + height: auto; + } + .p-accordionpanel { + border: none; + } + .p-accordioncontent-content { + padding: 1.2rem 0 0 0; + } + } +} + +.resource { + .p-accordion { + .p-accordionheader { + .p-iconwrapper { + transform: rotate(180deg); + background: var.$bg-blue-3; + height: 2.3rem; + min-width: 2.3rem; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + + svg { + color: var.$pr-blue-1; + } + } + } + } +} diff --git a/src/assets/styles/overrides/dropdown.scss b/src/assets/styles/overrides/dropdown.scss index bbd7a0baf..27ebe2b28 100644 --- a/src/assets/styles/overrides/dropdown.scss +++ b/src/assets/styles/overrides/dropdown.scss @@ -20,3 +20,19 @@ } } } + +.no-border-dropdown { + .p-dropdown { + border: none; + font-size: 1rem; + + .p-select-label { + padding: 0; + } + + .p-select-overlay { + right: 0; + left: auto; + } + } +} diff --git a/src/assets/styles/overrides/paginator.scss b/src/assets/styles/overrides/paginator.scss new file mode 100644 index 000000000..851a57673 --- /dev/null +++ b/src/assets/styles/overrides/paginator.scss @@ -0,0 +1,81 @@ +@use "assets/styles/variables" as var; + +.p-paginator { + background: white; + padding: 0.8rem 0 0 0; + row-gap: 0.8rem; +} + +.p-paginator-page { + color: var.$dark-blue-1; + border-radius: 4px; + background: white; + + &:hover { + background: var.$bg-blue-2; + } +} + +.p-paginator-page-selected { + color: white; + border-radius: 4px; + background: var.$pr-blue-1; + + &:hover { + background: var.$pr-blue-1; + } +} + +.p-paginator-next, +.p-paginator-last, +.p-paginator-first, +.p-paginator-prev { + color: var.$grey-1; + border-radius: 4px; +} + +.p-paginator-next:hover, +.p-paginator-last:hover, +.p-paginator-first:hover, +.p-paginator-prev:hover { + color: var.$dark-blue-1; +} + +.p-paginator-next:not(.p-disabled):hover, +.p-paginator-last:not(.p-disabled):hover, +.p-paginator-first:not(.p-disabled):hover, +.p-paginator-prev:not(.p-disabled):hover { + background: white; +} + +.p-select-overlay { + background: white; + border: 1px solid var.$grey-2; + color: var.$dark-blue-1; +} + +.p-select-option { + &.p-select-option-selected { + background-color: white; + color: var.$dark-blue-1; + + &:hover { + background: var.$bg-blue-3; + color: var.$dark-blue-1; + } + } + + &:not(.p-select-option-selected):not(.p-disabled).p-focus { + background: var.$bg-blue-3; + color: var.$dark-blue-1; + } +} + +p-select { + background: white; + border: 1px solid var.$grey-2; + + span { + color: var.$dark-blue-1; + } +} diff --git a/src/assets/styles/overrides/table.scss b/src/assets/styles/overrides/table.scss index 8bdf63328..1370f54b6 100644 --- a/src/assets/styles/overrides/table.scss +++ b/src/assets/styles/overrides/table.scss @@ -37,86 +37,6 @@ text-overflow: ellipsis; } } - - .p-paginator { - background: white; - padding: 0.8rem 0 0 0; - row-gap: 0.8rem; - } - - .p-paginator-page { - color: var.$dark-blue-1; - border-radius: 4px; - background: white; - - &:hover { - background: var.$bg-blue-2; - } - } - - .p-paginator-page-selected { - color: white; - border-radius: 4px; - background: var.$pr-blue-1; - - &:hover { - background: var.$pr-blue-1; - } - } - - .p-paginator-next, - .p-paginator-last, - .p-paginator-first, - .p-paginator-prev { - color: var.$grey-1; - border-radius: 4px; - } - - .p-paginator-next:hover, - .p-paginator-last:hover, - .p-paginator-first:hover, - .p-paginator-prev:hover { - color: var.$dark-blue-1; - } - - .p-paginator-next:not(.p-disabled):hover, - .p-paginator-last:not(.p-disabled):hover, - .p-paginator-first:not(.p-disabled):hover, - .p-paginator-prev:not(.p-disabled):hover { - background: white; - } - - .p-select-overlay { - background: white; - border: 1px solid var.$grey-2; - color: var.$dark-blue-1; - } - - .p-select-option { - &.p-select-option-selected { - background-color: white; - color: var.$dark-blue-1; - - &:hover { - background: var.$bg-blue-3; - color: var.$dark-blue-1; - } - } - - &:not(.p-select-option-selected):not(.p-disabled).p-focus { - background: var.$bg-blue-3; - color: var.$dark-blue-1; - } - } - - p-select { - background: white; - border: 1px solid var.$grey-2; - - span { - color: var.$dark-blue-1; - } - } } .addon-table { diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss index 1fde6e6d3..d8c2c31e9 100644 --- a/src/assets/styles/styles.scss +++ b/src/assets/styles/styles.scss @@ -21,6 +21,8 @@ @use "./overrides/iconfield"; @use "./overrides/datepicker"; @use "./overrides/select"; +@use "./overrides/accordion"; +@use "./overrides/paginator"; @layer base, primeng, reset;