diff --git a/angular-frontend/src/app/components/applications-list/applications-list.scss b/angular-frontend/src/app/components/applications-list/applications-list.scss
index 01c7031..05a41d5 100644
--- a/angular-frontend/src/app/components/applications-list/applications-list.scss
+++ b/angular-frontend/src/app/components/applications-list/applications-list.scss
@@ -9,10 +9,12 @@
======================================== */
.page-bg {
background-color: #e9ecef;
+ min-width: 1080px;
}
.content-width {
- width: 1080px;
+ max-width: 1080px;
+ width: 100%;
}
/* ========================================
@@ -32,6 +34,7 @@
.hero-stat-value {
color: #A3CDCC;
+ font-size: 3.5rem;
}
.hero-stat-label {
@@ -67,16 +70,24 @@
======================================== */
.overlay-image-container {
position: absolute;
- right: 28%;
- top: 150px;
+ top: -35px;
+ left: 45%;
+ transform: translateX(-50%);
z-index: 5;
}
.overlay-image {
- max-width: 450px;
+ width: 450px;
height: auto;
}
+/* ========================================
+ SECTION TITLES
+ ======================================== */
+.section-title {
+ font-size: 1.75rem;
+}
+
/* ========================================
DESCRIPTION TEXT
======================================== */
@@ -235,6 +246,20 @@
transition: opacity 0.3s ease;
}
+/* ========================================
+ MORE APPS RESPONSIVE GRID
+ ======================================== */
+.apps-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
+ gap: 1.5rem;
+}
+
+.apps-grid .app-card {
+ width: 100%;
+ min-width: unset;
+}
+
/* ========================================
STATUS BADGES
======================================== */
@@ -410,7 +435,8 @@
border: 0;
border-top: 1px solid #6c757d;
margin: 3rem auto;
- width: 1080px;
+ max-width: 1080px;
+ width: 100%;
}
/* ========================================
diff --git a/angular-frontend/src/app/components/applications-list/applications-list.ts b/angular-frontend/src/app/components/applications-list/applications-list.ts
index 55c7b4a..469990d 100644
--- a/angular-frontend/src/app/components/applications-list/applications-list.ts
+++ b/angular-frontend/src/app/components/applications-list/applications-list.ts
@@ -4,7 +4,7 @@
* Licensed under the EUPL-1.2 or later.
*/
-import { Component, OnInit, signal, computed, ViewChild, ViewChildren, ElementRef, AfterViewInit, QueryList } from '@angular/core';
+import { Component, OnInit, OnDestroy, signal, computed, ViewChild, ViewChildren, ElementRef, AfterViewInit, QueryList } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router';
@@ -23,7 +23,7 @@ import { AuthService } from '../../services/auth.service';
templateUrl: './applications-list.html',
styleUrls: ['./applications-list.scss']
})
-export class ApplicationsList implements OnInit, AfterViewInit {
+export class ApplicationsList implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('scrollContainer') scrollContainer!: ElementRef
;
@ViewChild('scrollContainerMore') scrollContainerMore!: ElementRef;
@ViewChildren('featuredCard') featuredCards!: QueryList>;
@@ -75,6 +75,9 @@ export class ApplicationsList implements OnInit, AfterViewInit {
protected showLoginRequiredMessage = signal(false);
protected dropdownPosition = signal<{ top: number; left: number } | null>(null);
+ private activeChipElement: HTMLElement | null = null;
+ private scrollListener: (() => void) | null = null;
+
protected filterState = signal({
trending: false,
categories: [],
@@ -255,17 +258,15 @@ export class ApplicationsList implements OnInit, AfterViewInit {
protected toggleDropdown(filterType: string, event: MouseEvent): void {
if (this.openDropdown() === filterType) {
- this.openDropdown.set(null);
- this.dropdownPosition.set(null);
+ this.closeDropdown();
} else {
const target = event.currentTarget as HTMLElement;
- const rect = target.closest('.filter-chip')?.getBoundingClientRect();
+ const chip = target.closest('.filter-chip') as HTMLElement | null;
- if (rect) {
- this.dropdownPosition.set({
- top: rect.bottom + 8,
- left: rect.left
- });
+ if (chip) {
+ this.activeChipElement = chip;
+ this.updateDropdownPosition();
+ this.attachScrollListener();
}
this.openDropdown.set(filterType);
}
@@ -274,6 +275,34 @@ export class ApplicationsList implements OnInit, AfterViewInit {
protected closeDropdown(): void {
this.openDropdown.set(null);
this.dropdownPosition.set(null);
+ this.activeChipElement = null;
+ this.detachScrollListener();
+ }
+
+ private updateDropdownPosition(): void {
+ if (!this.activeChipElement) return;
+ const rect = this.activeChipElement.getBoundingClientRect();
+ this.dropdownPosition.set({
+ top: rect.bottom + 8,
+ left: rect.left
+ });
+ }
+
+ private attachScrollListener(): void {
+ this.detachScrollListener();
+ this.scrollListener = () => this.updateDropdownPosition();
+ window.addEventListener('scroll', this.scrollListener, true);
+ }
+
+ private detachScrollListener(): void {
+ if (this.scrollListener) {
+ window.removeEventListener('scroll', this.scrollListener, true);
+ this.scrollListener = null;
+ }
+ }
+
+ ngOnDestroy(): void {
+ this.detachScrollListener();
}
protected clearTrendingFilter(): void {
diff --git a/angular-frontend/src/app/components/filter-modal/filter-modal.ts b/angular-frontend/src/app/components/filter-modal/filter-modal.ts
index 6f445b4..fa13436 100644
--- a/angular-frontend/src/app/components/filter-modal/filter-modal.ts
+++ b/angular-frontend/src/app/components/filter-modal/filter-modal.ts
@@ -123,6 +123,7 @@ export class FilterModal implements OnInit {
protected toggleTrending(): void {
this.trending.set(!this.trending());
+ this.closeModal();
}
protected toggleCategory(categoryName: string): void {
@@ -133,6 +134,7 @@ export class FilterModal implements OnInit {
current.add(categoryName);
}
this.selectedCategories.set(current);
+ this.closeModal();
}
protected toggleCapability(capability: string): void {
@@ -143,6 +145,7 @@ export class FilterModal implements OnInit {
current.add(capability);
}
this.selectedCapabilities.set(current);
+ this.closeModal();
}
protected toggleAppStatus(status: string): void {
@@ -153,6 +156,7 @@ export class FilterModal implements OnInit {
current.add(status);
}
this.selectedAppStatus.set(current);
+ this.closeModal();
}
protected isCategorySelected(categoryName: string): boolean {
@@ -175,6 +179,7 @@ export class FilterModal implements OnInit {
current.add(version);
}
this.selectedMidpointVersions.set(current);
+ this.closeModal();
}
protected isMidpointVersionSelected(version: string): boolean {
@@ -189,6 +194,7 @@ export class FilterModal implements OnInit {
current.add(method);
}
this.selectedIntegrationMethods.set(current);
+ this.closeModal();
}
protected isIntegrationMethodSelected(method: string): boolean {
@@ -203,6 +209,7 @@ export class FilterModal implements OnInit {
current.add(maintainer);
}
this.selectedMaintainers.set(current);
+ this.closeModal();
}
protected isMaintainerSelected(maintainer: string): boolean {
diff --git a/angular-frontend/src/app/components/upload-form-main/upload-form-main.html b/angular-frontend/src/app/components/upload-form-main/upload-form-main.html
index 1b2c805..632ecdb 100644
--- a/angular-frontend/src/app/components/upload-form-main/upload-form-main.html
+++ b/angular-frontend/src/app/components/upload-form-main/upload-form-main.html
@@ -39,6 +39,10 @@
}
+
+