diff --git a/package-lock.json b/package-lock.json index 4f2016fe..90274470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -324,6 +324,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -452,6 +453,7 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.12.tgz", "integrity": "sha512-9hsdWF4gRRcVJtPcCcYLaX1CIyM9wUu6r+xRl6zU5hq8qhl35hig6ounz7CXFAzLf0WDBdM16bPHouVGaG76lg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -519,6 +521,7 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.12.tgz", "integrity": "sha512-vabJzvrx76XXFrm1RJZ6o/CyG32piTB/1sfFfKHdlH1QrmArb8It4gyk9oEjZ1IkAD0HvBWlfWmn+T6Vx3pdUw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -535,6 +538,7 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.12.tgz", "integrity": "sha512-vwI8oOL/gM+wPnptOVeBbMfZYwzRxQsovojZf+Zol9szl0k3SZ3FycWlxxXZGFu3VIEfrP6pXplTmyODS/Lt1w==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -556,6 +560,7 @@ "integrity": "sha512-1F8M7nWfChzurb7obbvuE7mJXlHtY1UG58pcwcomVtpPb+kPavgAO8OEvJHYBMV+bzSxkXt5UIwL9lt9jHUxZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "7.23.9", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -632,6 +637,7 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.12.tgz", "integrity": "sha512-MuFt5yKi161JmauUta4Dh0m8ofwoq6Ino+KoOtkYMBGsSx+A7dSm+DUxxNwdj7+DNyg3LjVGCFgBFnq4g8z06A==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -666,6 +672,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.12.tgz", "integrity": "sha512-DYY04ptWh/ulMHzd+y52WCE8QnEYGeIiW3hEIFjCN8z0kbIdFdUtEB0IK5vjNL3ejyhUmphcpeT5PYf3YXtqWQ==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -750,6 +757,7 @@ "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -2950,6 +2958,7 @@ "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", "license": "MIT", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" }, @@ -3283,6 +3292,7 @@ "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", "license": "SEE LICENSE IN LICENSE", + "peer": true, "engines": { "node": "^16.13.0 || >=18.10.0" }, @@ -4401,6 +4411,7 @@ "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -4796,6 +4807,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4872,6 +4884,7 @@ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5479,6 +5492,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -6572,15 +6586,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/cytoscape": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", - "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", - "optional": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/cytoscape-cose-bilkent": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", @@ -6998,15 +7003,6 @@ "node": ">=12" } }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "optional": true, - "engines": { - "node": ">=12" - } - }, "node_modules/d3-shape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", @@ -7670,6 +7666,7 @@ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -9852,7 +9849,8 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/jest-worker": { "version": "27.5.1", @@ -10046,6 +10044,7 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -10126,6 +10125,7 @@ "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "jasmine-core": "^4.1.0" }, @@ -10324,6 +10324,7 @@ "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -10730,6 +10731,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -12860,6 +12862,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -13704,6 +13707,7 @@ "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -13785,6 +13789,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -13854,6 +13859,7 @@ "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -15559,6 +15565,7 @@ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15866,6 +15873,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -16407,6 +16415,7 @@ "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", @@ -16483,6 +16492,7 @@ "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -16614,6 +16624,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -16867,7 +16878,8 @@ "version": "0.14.10", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", - "license": "MIT" + "license": "MIT", + "peer": true } } } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 2ca64b4b..e81c2c53 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,28 +1,28 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import { QuoteListComponent } from "src/app/features/quotes/pages/quote-list/quote-list.component"; +import { AboutDomeComponent } from "src/app/pages/about-dome/about-dome.component"; +import { BlogEntryDetailComponent } from "src/app/pages/dome-blog/blog-entry-detail/blog-entry-detail.component"; +import { DomeBlogComponent } from "src/app/pages/dome-blog/dome-blog.component"; +import { EntryFormComponent } from "src/app/pages/dome-blog/entry-form/entry-form.component"; +import { UsageSpecsComponent } from "src/app/pages/usage-specs/usage-specs.component"; +import { AuthGuard } from './guard/auth.guard'; +import { quoteGuardGuard } from './guard/quote-guard.guard'; +import { AdminComponent } from "./pages/admin/admin.component"; +import { CatalogsComponent } from "./pages/catalogs/catalogs.component"; +import { CheckoutComponent } from "./pages/checkout/checkout.component"; +import { ContactUsFormComponent } from "./pages/contact-us/contact-us-form.component"; import { DashboardComponent } from './pages/dashboard/dashboard.component'; -import { ProductInventoryComponent } from './pages/product-inventory/product-inventory.component'; -import { ProductInvDetailComponent } from './pages/product-inventory/inventory-items/product-inv-detail/product-inv-detail.component'; -import { SearchComponent } from "./pages/search/search.component"; +import { OrganizationDetailsComponent } from "./pages/organization-details/organization-details.component"; import { ProductDetailsComponent } from "./pages/product-details/product-details.component"; +import { ProductInvDetailComponent } from './pages/product-inventory/inventory-items/product-inv-detail/product-inv-detail.component'; +import { ProductInventoryComponent } from './pages/product-inventory/product-inventory.component'; +import { ProductOrdersComponent } from './pages/product-orders/product-orders.component'; import { SearchCatalogComponent } from "./pages/search-catalog/search-catalog.component"; -import { CatalogsComponent } from "./pages/catalogs/catalogs.component"; +import { SearchComponent } from "./pages/search/search.component"; +import { SellerOfferingsComponent } from "./pages/seller-offerings/seller-offerings.component"; import { ShoppingCartComponent } from "./pages/shopping-cart/shopping-cart.component"; -import {CheckoutComponent} from "./pages/checkout/checkout.component"; import { UserProfileComponent } from "./pages/user-profile/user-profile.component"; -import { SellerOfferingsComponent } from "./pages/seller-offerings/seller-offerings.component"; -import { AdminComponent } from "./pages/admin/admin.component"; -import { ContactUsFormComponent } from "./pages/contact-us/contact-us-form.component"; -import { AuthGuard } from './guard/auth.guard'; -import { quoteGuardGuard } from './guard/quote-guard.guard'; -import { OrganizationDetailsComponent } from "./pages/organization-details/organization-details.component" -import { ProductOrdersComponent } from './pages/product-orders/product-orders.component'; -import {AboutDomeComponent} from "src/app/pages/about-dome/about-dome.component" -import { QuoteListComponent } from "src/app/features/quotes/pages/quote-list/quote-list.component" -import { UsageSpecsComponent } from "src/app/pages/usage-specs/usage-specs.component" -import { DomeBlogComponent } from "src/app/pages/dome-blog/dome-blog.component" -import { BlogEntryDetailComponent } from "src/app/pages/dome-blog/blog-entry-detail/blog-entry-detail.component" -import { EntryFormComponent } from "src/app/pages/dome-blog/entry-form/entry-form.component" @@ -39,64 +39,79 @@ const routes: Routes = [ path: 'search', component: SearchComponent }, - { path: 'search/:id', + { + path: 'search/:id', component: ProductDetailsComponent }, - { path: 'org-details/:id', + { + path: 'org-details/:id', component: OrganizationDetailsComponent }, - { path: 'search/catalogue/:id', - component: SearchCatalogComponent + { + path: 'search/catalogue/:id', + component: SearchCatalogComponent }, - { path: 'catalogues', - component: CatalogsComponent + { + path: 'catalogues', + component: CatalogsComponent }, - { path: 'shopping-cart', - component: ShoppingCartComponent, - canActivate: [AuthGuard], data: { roles: [] } + { + path: 'shopping-cart', + component: ShoppingCartComponent, + canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'checkout', + { + path: 'checkout', component: CheckoutComponent, canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'checkout/:id', + { + path: 'checkout/:id', component: CheckoutComponent, canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'product-inventory', - component: ProductInventoryComponent, - canActivate: [AuthGuard], data: { roles: [] } + { + path: 'product-inventory', + component: ProductInventoryComponent, + canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'product-inventory/:id', - component: ProductInvDetailComponent + { + path: 'product-inventory/:id', + component: ProductInvDetailComponent }, - { path: 'profile', - component: UserProfileComponent, - canActivate: [AuthGuard], data: { roles: [] } + { + path: 'profile', + component: UserProfileComponent, + canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'my-offerings', - component: SellerOfferingsComponent, - canActivate: [AuthGuard], data: { roles: ['seller'] } + { + path: 'my-offerings', + component: SellerOfferingsComponent, + canActivate: [AuthGuard], data: { roles: ['seller'] } }, - { path: 'admin', - component: AdminComponent, - canActivate: [AuthGuard], data: { roles: ['admin', 'certifier'] } + { + path: 'admin', + component: AdminComponent, + canActivate: [AuthGuard], data: { roles: ['admin', 'certifier'] } }, - { path: 'contact-us', + { + path: 'contact-us', component: ContactUsFormComponent }, - { path: 'product-orders', + { + path: 'product-orders', component: ProductOrdersComponent, canActivate: [AuthGuard], data: { roles: [] } }, - { path: 'quote-list', + { + path: 'quote-list', component: QuoteListComponent, canActivate: [AuthGuard, quoteGuardGuard], data: { roles: [] } }, - { + { path: 'tenders', loadChildren: () => import('./features/tenders/tenders.module').then(m => m.TendersModule), - canActivate: [AuthGuard, quoteGuardGuard], + canActivate: [AuthGuard, quoteGuardGuard], data: { roles: [] } }, { @@ -104,20 +119,37 @@ const routes: Routes = [ component: UsageSpecsComponent, canActivate: [AuthGuard], data: { roles: ['seller'] } }, - { path: 'blog', + { + path: 'blog', component: DomeBlogComponent }, - { path: 'blog/:id', + { + path: 'blog/:id', component: BlogEntryDetailComponent }, - { path: 'blog-entry', + { + path: 'blog-entry', component: EntryFormComponent, canActivate: [AuthGuard], data: { roles: ['admin'] } }, - { path: 'blog-entry/:id', + { + path: 'blog-entry/:id', component: EntryFormComponent, canActivate: [AuthGuard], data: { roles: ['admin'] } }, + + { + path: 'landing-page', + children: [{ + path: 'customers', + loadComponent: () => import('./pages/landing-pages/customers/landing-page-customers.component').then(c => c.LandingPageCustomersComponent), + }, + { + path: 'providers', + loadComponent: () => import('./pages/landing-pages/providers/landing-page-providers.component').then(c => c.LandingPageProvidersComponent), + }] + }, + { path: '**', redirectTo: 'dashboard', pathMatch: 'full' }, ] diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9ff29a0b..7d56f3db 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,105 +1,99 @@ +import { NgOptimizedImage } from '@angular/common'; +import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; import { APP_INITIALIZER, NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { BrowserModule } from '@angular/platform-browser'; -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; -import { AppComponent } from './app.component'; -import { GalleryComponent } from "./offerings/gallery/gallery.component"; -import { ExploreDomeComponent } from "./offerings/explore-dome/explore-dome.component"; -import { PlatformBenefitsComponent } from "./offerings/platform-benefits/platform-benefits.component"; -import { HowItWorksComponent } from "./offerings/how-it-works/how-it-works.component"; -import { SearchComponent } from "./pages/search/search.component"; -import { ProductDetailsComponent } from "./pages/product-details/product-details.component"; -import { ProductInventoryComponent } from "./pages/product-inventory/product-inventory.component"; -import { UserProfileComponent } from "./pages/user-profile/user-profile.component"; -import { SellerOfferingsComponent } from "./pages/seller-offerings/seller-offerings.component"; -import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { SharedModule } from "./shared/shared.module"; -import { AppRoutingModule } from './app-routing.module'; +import { PickerComponent } from '@ctrl/ngx-emoji-mart'; +import { FaIconComponent, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateHttpLoader } from "@ngx-translate/http-loader"; -import { HttpClient } from '@angular/common/http'; -import {CategoriesFilterComponent} from "./shared/categories-filter/categories-filter.component"; -import {CardComponent} from "./shared/card/card.component"; -import {BadgeComponent} from "./shared/badge/badge.component"; -import {BillingAccountFormComponent} from "./shared/billing-account-form/billing-account-form.component"; -import { NgOptimizedImage } from '@angular/common'; -import { FaIconComponent } from "@fortawesome/angular-fontawesome"; -import {FormsModule, ReactiveFormsModule} from "@angular/forms"; -import {CategoryItemComponent} from "./shared/category-item/category-item.component"; -import { CartDrawerComponent } from "./shared/cart-drawer/cart-drawer.component"; -import {CategoriesPanelComponent} from "./shared/categories-panel/categories-panel.component"; -import { SearchCatalogComponent } from "./pages/search-catalog/search-catalog.component"; -import { ShoppingCartComponent } from "./pages/shopping-cart/shopping-cart.component"; -import { BillingAddressComponent } from "./pages/checkout/billing-address/billing-address.component"; -import { CatalogsComponent } from "./pages/catalogs/catalogs.component"; -import { CheckoutComponent } from "./pages/checkout/checkout.component"; -import { RequestInterceptor } from './interceptors/requests-interceptor'; -import { MarkdownModule } from 'ngx-markdown'; -import { InventoryProductsComponent } from './pages/product-inventory/inventory-items/inventory-products/inventory-products.component'; -import { UserInfoComponent } from './pages/user-profile/profile-sections/user-info/user-info.component'; -import { OrgInfoComponent } from './pages/user-profile/profile-sections/org-info/org-info.component'; -import { BillingInfoComponent } from './pages/user-profile/profile-sections/billing-info/billing-info.component'; -import { OrderInfoComponent } from './pages/user-profile/profile-sections/order-info/order-info.component'; -import { SellerCatalogsComponent } from './pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component'; -import { SellerProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component'; -import { SellerServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component'; -import { SellerResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component'; -import { SellerOfferComponent } from './pages/seller-offerings/offerings/seller-offer/seller-offer.component'; -import { CreateProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component'; -import { PickerComponent } from '@ctrl/ngx-emoji-mart'; import { NgxFileDropModule } from 'ngx-file-drop'; -import { CreateServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component'; -import { CreateResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component'; -import { CreateOfferComponent } from './pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component'; -import {CategoriesRecursionComponent} from "./shared/categories-recursion/categories-recursion.component"; -import { UpdateProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component'; -import { UpdateResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component'; -import { UpdateServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component'; -import { ChatbotWidgetComponent } from './chatbot-widget/chatbot-widget.component'; -import { UpdateOfferComponent } from './pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component'; -import { CreateCatalogComponent } from './pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component'; -import { UpdateCatalogComponent } from './pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component'; -import { ErrorMessageComponent } from 'src/app/shared/error-message/error-message.component'; +import { MarkdownModule } from 'ngx-markdown'; +import { MatomoInitializationMode, MatomoInitializerService, MatomoModule, MatomoRouterModule } from 'ngx-matomo-client'; import { CartCardComponent } from 'src/app/shared/cart-card/cart-card.component'; +import { ErrorMessageComponent } from 'src/app/shared/error-message/error-message.component'; +import { appConfigFactory } from './app-config-factory'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { ChatbotWidgetComponent } from './chatbot-widget/chatbot-widget.component'; +import { RequestInterceptor } from './interceptors/requests-interceptor'; +import { ContactUsComponent } from './offerings/contact-us/contact-us.component'; +import { ExploreDomeComponent } from "./offerings/explore-dome/explore-dome.component"; +import { FaqComponent } from './offerings/faq/faq.component'; +import { GalleryComponent } from "./offerings/gallery/gallery.component"; +import { HowItWorksComponent } from "./offerings/how-it-works/how-it-works.component"; +import { PlatformBenefitsComponent } from "./offerings/platform-benefits/platform-benefits.component"; import { AdminComponent } from './pages/admin/admin.component'; import { CategoriesComponent } from './pages/admin/categories/categories.component'; import { CreateCategoryComponent } from './pages/admin/categories/create-category/create-category.component'; import { UpdateCategoryComponent } from './pages/admin/categories/update-category/update-category.component'; -import { CategoriesRecursionListComponent } from './shared/categories-recursion-list/categories-recursion-list.component'; -import { ContactUsComponent } from './offerings/contact-us/contact-us.component'; -import { ContactUsFormComponent } from './pages/contact-us/contact-us-form.component'; -import { provideMatomo, MatomoModule, MatomoRouterModule, MatomoConfiguration, MatomoInitializationMode, MatomoInitializerService } from 'ngx-matomo-client'; -import { withRouter } from 'ngx-matomo-client' -import { environment } from 'src/environments/environment'; -import { AppInitService } from './services/app-init.service'; -import { appConfigFactory } from './app-config-factory'; -import { VerificationComponent } from './pages/admin/verification/verification.component'; import { EmailComponent } from './pages/admin/email/email.component'; +import { VerificationComponent } from './pages/admin/verification/verification.component'; +import { CatalogsComponent } from "./pages/catalogs/catalogs.component"; +import { BillingAddressComponent } from "./pages/checkout/billing-address/billing-address.component"; +import { CheckoutComponent } from "./pages/checkout/checkout.component"; +import { ContactUsFormComponent } from './pages/contact-us/contact-us-form.component'; +import { OrganizationDetailsComponent } from './pages/organization-details/organization-details.component'; +import { ProductDetailsComponent } from "./pages/product-details/product-details.component"; +import { InventoryProductsComponent } from './pages/product-inventory/inventory-items/inventory-products/inventory-products.component'; +import { ProductInvDetailComponent } from './pages/product-inventory/inventory-items/product-inv-detail/product-inv-detail.component'; import { InventoryResourcesComponent } from './pages/product-inventory/inventory-resources/inventory-resources.component'; import { InventoryServicesComponent } from './pages/product-inventory/inventory-services/inventory-services.component'; -import { ProductInvDetailComponent } from './pages/product-inventory/inventory-items/product-inv-detail/product-inv-detail.component'; -import { OrganizationDetailsComponent } from './pages/organization-details/organization-details.component'; -import { FaqComponent } from './offerings/faq/faq.component'; +import { ProductInventoryComponent } from "./pages/product-inventory/product-inventory.component"; +import { SearchCatalogComponent } from "./pages/search-catalog/search-catalog.component"; +import { SearchComponent } from "./pages/search/search.component"; +import { CreateCatalogComponent } from './pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component'; +import { SellerCatalogsComponent } from './pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component'; +import { UpdateCatalogComponent } from './pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component'; +import { CreateOfferComponent } from './pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component'; import { NewPricePlanComponent } from './pages/seller-offerings/offerings/seller-offer/new-price-plan/new-price-plan.component'; +import { SellerOfferComponent } from './pages/seller-offerings/offerings/seller-offer/seller-offer.component'; +import { UpdateOfferComponent } from './pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component'; import { UpdatePricePlanComponent } from './pages/seller-offerings/offerings/seller-offer/update-price-plan/update-price-plan.component'; -import { MultipleSelectComponent } from './shared/multiple-select/multiple-select.component'; -import {CharacteristicComponent} from "./shared/characteristic/characteristic.component"; -import {PricePlanDrawerComponent} from "./shared/price-plan-drawer/price-plan-drawer.component"; -import {OfferComponent} from "./shared/forms/offer/offer.component"; -import {CustomOfferComponent} from "./shared/forms/offer/custom-offer/custom-offer.component" -import { ThemeService } from './services/theme.service'; +import { CreateProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component'; +import { SellerProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component'; +import { UpdateProductSpecComponent } from './pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component'; +import { CreateResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component'; +import { SellerResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component'; +import { UpdateResourceSpecComponent } from './pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component'; +import { CreateServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component'; +import { SellerServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component'; +import { UpdateServiceSpecComponent } from './pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component'; +import { SellerOfferingsComponent } from "./pages/seller-offerings/seller-offerings.component"; +import { ShoppingCartComponent } from "./pages/shopping-cart/shopping-cart.component"; +import { BillingInfoComponent } from './pages/user-profile/profile-sections/billing-info/billing-info.component'; +import { OrderInfoComponent } from './pages/user-profile/profile-sections/order-info/order-info.component'; +import { OrgInfoComponent } from './pages/user-profile/profile-sections/org-info/org-info.component'; +import { UserInfoComponent } from './pages/user-profile/profile-sections/user-info/user-info.component'; +import { UserProfileComponent } from "./pages/user-profile/user-profile.component"; +import { AppInitService } from './services/app-init.service'; import { ThemeAwareTranslateLoader } from './services/theme-aware-translate.loader'; -import { RevenueReportComponent } from './shared/revenue-report/revenue-report.component' +import { ThemeService } from './services/theme.service'; +import { BadgeComponent } from "./shared/badge/badge.component"; +import { BillingAccountFormComponent } from "./shared/billing-account-form/billing-account-form.component"; +import { CardComponent } from "./shared/card/card.component"; +import { CategoriesFilterComponent } from "./shared/categories-filter/categories-filter.component"; +import { CategoriesPanelComponent } from "./shared/categories-panel/categories-panel.component"; +import { CategoriesRecursionListComponent } from './shared/categories-recursion-list/categories-recursion-list.component'; +import { CategoriesRecursionComponent } from "./shared/categories-recursion/categories-recursion.component"; +import { CategoryItemComponent } from "./shared/category-item/category-item.component"; +import { CharacteristicComponent } from "./shared/characteristic/characteristic.component"; +import { CustomOfferComponent } from "./shared/forms/offer/custom-offer/custom-offer.component"; +import { OfferComponent } from "./shared/forms/offer/offer.component"; +import { PricePlanDrawerComponent } from "./shared/price-plan-drawer/price-plan-drawer.component"; +import { RevenueReportComponent } from './shared/revenue-report/revenue-report.component'; +import { SharedModule } from "./shared/shared.module"; // Función Factory requerida para crear el cargador con sus dependencias export function createThemeAwareLoader(http: HttpClient, themeService: ThemeService) { return new ThemeAwareTranslateLoader(http, themeService); } -import {AboutDomeComponent} from "src/app/pages/about-dome/about-dome.component" -import { QuotesModule } from "src/app/features/quotes/quotes.module" -import { MarkdownTextareaComponent } from "src/app/shared/forms/markdown-textarea/markdown-textarea.component" -import { ProviderRevenueSharingComponent } from "src/app/pages/user-profile/profile-sections/provider-revenue-sharing/provider-revenue-sharing.component" -import { OperatorRevenueSharingComponent } from "src/app/pages/admin/operator-revenue-sharing/operator-revenue-sharing.component" +import { QuotesModule } from "src/app/features/quotes/quotes.module"; +import { AboutDomeComponent } from "src/app/pages/about-dome/about-dome.component"; +import { OperatorRevenueSharingComponent } from "src/app/pages/admin/operator-revenue-sharing/operator-revenue-sharing.component"; +import { ProviderRevenueSharingComponent } from "src/app/pages/user-profile/profile-sections/provider-revenue-sharing/provider-revenue-sharing.component"; +import { MarkdownTextareaComponent } from "src/app/shared/forms/markdown-textarea/markdown-textarea.component"; @NgModule({ declarations: [ @@ -164,43 +158,43 @@ import { OperatorRevenueSharingComponent } from "src/app/pages/admin/operator-re NewPricePlanComponent, UpdatePricePlanComponent ], - imports: [ - BrowserModule, - FontAwesomeModule, - SharedModule, - AppRoutingModule, - NgOptimizedImage, - FaIconComponent, - FormsModule, - ReactiveFormsModule, - PickerComponent, - NgxFileDropModule, - ChatbotWidgetComponent, - QuotesModule, - MarkdownModule.forRoot(), - TranslateModule.forRoot({ - defaultLanguage: 'en', - loader: { - provide: TranslateLoader, - useFactory: (createThemeAwareLoader), - deps: [HttpClient, ThemeService] - } - }), - CategoriesPanelComponent, - MatomoModule.forRoot({ - mode: MatomoInitializationMode.AUTO_DEFERRED - }), - MatomoRouterModule, - CharacteristicComponent, - PricePlanDrawerComponent, - RevenueReportComponent, - OfferComponent, - CustomOfferComponent, - AboutDomeComponent, - MarkdownTextareaComponent, - ProviderRevenueSharingComponent, - OperatorRevenueSharingComponent - ], + imports: [ + BrowserModule, + FontAwesomeModule, + SharedModule, + AppRoutingModule, + NgOptimizedImage, + FaIconComponent, + FormsModule, + ReactiveFormsModule, + PickerComponent, + NgxFileDropModule, + ChatbotWidgetComponent, + QuotesModule, + MarkdownModule.forRoot(), + TranslateModule.forRoot({ + defaultLanguage: 'en', + loader: { + provide: TranslateLoader, + useFactory: (createThemeAwareLoader), + deps: [HttpClient, ThemeService] + } + }), + CategoriesPanelComponent, + MatomoModule.forRoot({ + mode: MatomoInitializationMode.AUTO_DEFERRED + }), + MatomoRouterModule, + CharacteristicComponent, + PricePlanDrawerComponent, + RevenueReportComponent, + OfferComponent, + CustomOfferComponent, + AboutDomeComponent, + MarkdownTextareaComponent, + ProviderRevenueSharingComponent, + OperatorRevenueSharingComponent + ], providers: [ AppInitService, { diff --git a/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.css b/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.css index 1eb4facf..d57b6496 100644 --- a/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.css +++ b/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.css @@ -1,101 +1,297 @@ +:host { + display: block; +} + .hero-shell { - background: #070f24; - font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans"; + height: 840px; + background: linear-gradient(180deg, #0b1528 0%, #14274a 100%); } .hero-bg { - background: - radial-gradient(900px 520px at 50% 44%, rgba(20, 140, 255, 0.14), rgba(7, 15, 36, 0) 62%), - radial-gradient(1200px 700px at 50% 40%, rgba(0, 210, 255, 0.10), rgba(7, 15, 36, 0) 68%), - linear-gradient(180deg, #070f24 0%, #07102a 40%, #060d22 100%); + background: linear-gradient(180deg, #0b1528 0%, #14274a 100%); +} + +.hero-blur { + position: absolute; + left: 50%; + transform: translateX(-50%); + pointer-events: none; + border-radius: 9999px; +} + +.hero-blur-main { + top: 572px; + width: 800px; + height: 303px; + background: linear-gradient(180deg, #1a3360 0%, #0b1528 100%); + filter: blur(125px); + z-index: 1; +} + +.hero-blur-core { + top: 702px; + width: 284px; + height: 76px; + background: rgba(255, 255, 255, 0.9); + filter: blur(50px); + z-index: 2; } .hero-title { + width: 100%; + max-width: 738px; + margin: 0; font-weight: 800; - letter-spacing: -0.02em; - line-height: 1.05; - font-size: clamp(40px, 4.2vw, 64px); + font-size: 70px; + line-height: 84px; + letter-spacing: 1px; + text-align: center; + color: #ffffff; } .hero-accent { - color: #23b9d8; + color: #00b7e8; } .hero-sub { - color: rgba(255, 255, 255, 0.55); - font-size: 16px; - line-height: 1.7; + width: 100%; + max-width: 738px; + margin-inline: auto; + font-weight: 400; + font-size: 20px; + line-height: 32px; + text-align: center; + color: #ffffff; + opacity: 0.6; +} + +.hero-actions { + height: 48px; } .hero-btn { - height: 52px; - padding: 0 22px; - border-radius: 10px; - font-weight: 700; - font-size: 14px; - letter-spacing: 0.01em; - transition: transform 160ms ease, box-shadow 160ms ease, background-color 160ms ease, border-color 160ms ease; + flex: 1 1 0; + min-height: 48px; + padding: 12px 20px; + border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; - min-width: 260px; -} - -.hero-btn:active { - transform: translateY(1px); + text-align: center; + font-weight: 600; + font-size: 16px; + line-height: 24px; + letter-spacing: 0.5px; + text-decoration: none; + transition: all 0.2s ease; } .hero-btn--primary { - background: #2D58A7; - color: #fff; - box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28); + background: #2d58a7; + color: #ffffff; + border: 2px solid #2d58a7; } .hero-btn--primary:hover { - background: #00ADD3; - box-shadow: 0 22px 55px rgba(0, 0, 0, 0.32); + background: #3565be; + border-color: #3565be; } -.hero-btn--ghost { +.hero-btn--secondary { background: transparent; - border: 1px solid rgba(90, 140, 255, 0.45); - color: rgba(255, 255, 255, 0.92); - box-shadow: 0 12px 34px rgba(0, 0, 0, 0.20); - backdrop-filter: blur(6px); + color: #ffffff; + border: 2px solid #2d58a7; } -.hero-btn--ghost:hover { - border-color: #2D58A7; - color: #2D58A7; - background: white; +.hero-btn--secondary:hover { + background: rgba(45, 88, 167, 0.12); } -.logo-ph { - height: 32px; +.hero-logos { + position: relative; + z-index: 6; + width: 100%; + max-width: 897px; + min-height: 86px; + padding-top: 16px; display: flex; align-items: center; justify-content: center; - border-radius: 999px; - border: 1px solid rgba(255, 255, 255, 0.14); - color: rgba(255, 255, 255, 0.60); - font-weight: 700; - letter-spacing: 0.12em; - font-size: 12px; + gap: 24px; + filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25)); + border-radius: 100px; +} + +.hero-logo-item { + width: 129px; + height: 70px; + border-radius: 16px; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; +} + +.hero-logo-item img { + display: block; + max-width: 100%; + max-height: 100%; + object-fit: contain; +} + +.hero-logo-item--cyfronet img { + max-width: 102px; + max-height: 49px; } .earth-wrapper { position: absolute; - bottom: -2%; left: 50%; + top: 724px; + width: 1994.69px; transform: translateX(-50%); - width: min(1600px, 140vw); + z-index: 3; pointer-events: none; - opacity: 0.95; } .earth-wrapper img { + display: block; width: 100%; height: auto; - display: block; - filter: drop-shadow(0 0 40px rgba(120, 220, 255, 0.35)); +} + +.hero-fade { + position: absolute; + top: 609px; + width: 169px; + height: 85px; + z-index: 7; + pointer-events: none; +} + +.hero-fade-left { + left: 238px; + background: linear-gradient(90deg, #112241 0%, rgba(17, 34, 65, 0.7) 50%, rgba(17, 34, 65, 0) 100%); +} + +.hero-fade-right { + right: 231px; + background: linear-gradient(270deg, #112241 0%, rgba(17, 34, 65, 0.7) 50%, rgba(17, 34, 65, 0) 100%); +} + +@media (max-width: 1279px) { + .hero-shell { + height: auto; + min-height: 840px; + } + + .hero-title { + font-size: 58px; + line-height: 70px; + } + + .earth-wrapper { + width: 1700px; + } + + .hero-fade-left { + left: 80px; + } + + .hero-fade-right { + right: 80px; + } +} + +@media (max-width: 1023px) { + .hero-shell { + min-height: 900px; + } + + .hero-title { + max-width: 700px; + font-size: 48px; + line-height: 58px; + letter-spacing: 0.4px; + } + + .hero-sub { + font-size: 18px; + line-height: 30px; + max-width: 680px; + } + + .hero-actions { + height: auto; + } + + .hero-logos { + max-width: 760px; + gap: 18px; + flex-wrap: wrap; + padding-top: 12px; + } + + .hero-logo-item { + width: 112px; + height: 60px; + } + + .earth-wrapper { + top: 740px; + width: 1500px; + } + + .hero-fade { + display: none; + } +} + +@media (max-width: 767px) { + .hero-shell { + min-height: 920px; + } + + .hero-title { + max-width: 100%; + font-size: 40px; + line-height: 48px; + letter-spacing: 0; + } + + .hero-sub { + max-width: 100%; + font-size: 16px; + line-height: 26px; + } + + .hero-btn { + width: 100%; + } + + .hero-logos { + max-width: 100%; + gap: 16px; + padding-top: 8px; + } + + .hero-logo-item { + width: 96px; + height: 54px; + } + + .earth-wrapper { + top: 760px; + width: 1200px; + } + + .hero-blur-main { + width: 560px; + height: 220px; + } + + .hero-blur-core { + width: 220px; + height: 60px; + } } diff --git a/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.html b/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.html index bb886be2..e7260e3b 100644 --- a/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.html +++ b/src/app/pages/dashboard/dashboard-hero/dashboard-hero.component.html @@ -1,8 +1,19 @@ -
+
+ + + + + + + +
+ class="relative z-[5] mx-auto flex h-[840px] w-full max-w-[1440px] flex-col items-center px-5 pt-[144px] pb-[80px] text-center sm:px-8 lg:px-[160px]"> +

{{ 'DASHBOARD.hero._titleLine1Part1' | translate }} @@ -12,33 +23,46 @@

{{ 'DASHBOARD.hero._titleLine3' | translate }}

-

+

{{ 'DASHBOARD.hero._subtitleLine1' | translate }} {{ 'DASHBOARD.hero._subtitleLine2' | translate }}

- +

diff --git a/src/app/pages/dashboard/dashboard-services/dashboard-services.component.html b/src/app/pages/dashboard/dashboard-services/dashboard-services.component.html index 14c52549..60d1d8db 100644 --- a/src/app/pages/dashboard/dashboard-services/dashboard-services.component.html +++ b/src/app/pages/dashboard/dashboard-services/dashboard-services.component.html @@ -1,13 +1,13 @@
-
+
-

+

{{ "DASHBOARD.marketplace.title" | translate }}

-

+

{{ "DASHBOARD.marketplace.subtitle" | translate }}

@@ -18,9 +18,9 @@

- + @for (productOffering of productOfferings(); track productOffering.id) { -
+
@@ -28,7 +28,6 @@

-

{{ productOffering.name }}

@@ -43,7 +42,6 @@

} -
diff --git a/src/app/pages/dashboard/dashboard-services/dashboard-services.component.ts b/src/app/pages/dashboard/dashboard-services/dashboard-services.component.ts index cc05b45c..ea421be2 100644 --- a/src/app/pages/dashboard/dashboard-services/dashboard-services.component.ts +++ b/src/app/pages/dashboard/dashboard-services/dashboard-services.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit, input } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faArrowRight } from '@fortawesome/pro-regular-svg-icons'; import { TranslateModule } from '@ngx-translate/core'; @@ -13,20 +13,48 @@ import { CarouselComponent } from '../../../shared/carousel/carousel.component'; changeDetection: ChangeDetectionStrategy.OnPush, imports: [FontAwesomeModule, TranslateModule, CarouselComponent] }) -export class DashboardServicesComponent { +export class DashboardServicesComponent implements OnInit { faArrowRight = faArrowRight; productOfferings = input.required(); + visibleItems = 3; + + constructor(private cdr: ChangeDetectorRef) { } + + ngOnInit(): void { + this.updateVisibleItems(); + } + + @HostListener('window:resize') + onResize(): void { + this.updateVisibleItems(); + } + + updateVisibleItems(): void { + const width = window.innerWidth; + + if (width < 768) { + this.visibleItems = 1; + } else if (width < 1024) { + this.visibleItems = 2; + } else { + this.visibleItems = 3; + } + + this.cdr.markForCheck(); + } + + getProductImage(prod: ProductOffering): string { + let images: any[] = []; - getProductImage(prod: ProductOffering) { - let images: any[] = [] if (prod?.attachment) { - let profile = prod?.attachment?.filter(item => item.name === 'Profile Picture') ?? []; - images = prod.attachment?.filter(item => item.attachmentType === 'Picture') ?? []; - if (profile.length != 0) { + const profile = prod.attachment.filter(item => item.name === 'Profile Picture') ?? []; + images = prod.attachment.filter(item => item.attachmentType === 'Picture') ?? []; + + if (profile.length !== 0) { images = profile; } } - return images.length > 0 ? images?.at(0)?.url : 'https://placehold.co/600x400/svg'; - } + return images.length > 0 ? images.at(0)?.url : 'https://placehold.co/600x400/svg'; + } } diff --git a/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.css b/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.css index e888c2e9..804bd4c1 100644 --- a/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.css +++ b/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.css @@ -1,11 +1,216 @@ -.wrapper:hover .text-custom { - font-size: 20px; - line-height: 1; +:host { + display: block; +} + +.stats-section { + background: #ffffff; +} + +.stats-shell { + padding: 80px 160px; +} + +.stats-inner { + gap: 24px; +} + +.stats-heading { + padding-bottom: 40px; +} + +.stats-title { + max-width: 735px; + margin: 0; + font-family: 'Blinker', sans-serif; font-weight: 700; + font-size: 56px; + line-height: 67px; + letter-spacing: 0; + color: #111827; } -.wrapper:hover .num-custom { - font-size: 45px; +.stats-subtitle { + width: 100%; + max-width: 1120px; + margin: 0; + font-family: 'Blinker', sans-serif; + font-weight: 400; + font-size: 24px; + line-height: 29px; + text-align: center; + color: #324153; +} + +.stats-grid { + gap: 24px; +} + +.stats-card { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + min-height: 182px; + padding: 24px 24px 16px; + gap: 8px; + background: #f7f9fd; + border-radius: 16px; + overflow: hidden; + transition: transform 0.35s ease, box-shadow 0.35s ease; +} + +.stats-card::before { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(135deg, #2d58a7 0%, #6f8fc9 100%); + opacity: 0; + transition: opacity 0.35s ease; + z-index: 0; +} + +.stats-card>* { + position: relative; + z-index: 1; +} + +.stats-card:hover::before { + opacity: 1; +} + +.stats-card:hover { + transform: translateY(-2px); + box-shadow: 0 12px 40px rgba(45, 88, 167, 0.25); +} + +.stats-number { + width: 100%; + min-height: 96px; + display: flex; + align-items: flex-end; + font-family: 'Blinker', sans-serif; font-weight: 700; + font-size: 80px; + line-height: 96px; + letter-spacing: 1px; + color: #2d58a7; + transition: color 0.3s ease; +} + +.stats-text { + width: 100%; + margin: 0; + font-family: 'Blinker', sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 19px; + color: #324153; + transition: color 0.3s ease; +} + +.stats-card:hover .stats-number, +.stats-card:hover .stats-text { + color: #ffffff; +} + +@media (max-width: 1279px) { + .stats-shell { + padding: 72px 64px; + } + + .stats-title { + font-size: 48px; + line-height: 58px; + max-width: 680px; + } + + .stats-subtitle { + font-size: 22px; + line-height: 28px; + } + + .stats-number { + font-size: 72px; + line-height: 88px; + min-height: 88px; + } +} + +@media (max-width: 1023px) { + .stats-shell { + padding: 64px 32px; + } + + .stats-heading { + padding-bottom: 32px; + } + + .stats-title { + max-width: 100%; + font-size: 42px; + line-height: 50px; + } + + .stats-subtitle { + font-size: 20px; + line-height: 26px; + } + + .stats-card { + min-height: 170px; + } + + .stats-number { + font-size: 68px; + line-height: 80px; + min-height: 80px; + } +} + +@media (max-width: 767px) { + .stats-shell { + padding: 56px 20px; + } + + .stats-inner { + gap: 20px; + } + + .stats-heading { + gap: 12px; + padding-bottom: 24px; + } + + .stats-title { + font-size: 34px; + line-height: 42px; + } + + .stats-subtitle { + font-size: 18px; + line-height: 24px; + } + + .stats-grid { + gap: 16px; + } + + .stats-card { + min-height: auto; + padding: 20px 20px 16px; + border-radius: 14px; + } + + .stats-number { + min-height: auto; + font-size: 56px; + line-height: 64px; + letter-spacing: 0.5px; + } + .stats-text { + font-size: 15px; + line-height: 20px; + } } diff --git a/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.html b/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.html index 3ef74aa7..53e4197e 100644 --- a/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.html +++ b/src/app/pages/dashboard/dashboard-stats/dashboard-stats.component.html @@ -1,46 +1,47 @@ -
-
- -

- {{ 'DASHBOARD.stats.title' | translate }} -

- -

- {{ 'DASHBOARD.stats.subtitle' | translate }} -

- -
- -
- -
- {{stats().services}} -
- -

- {{ 'DASHBOARD.stats.services' | translate }} +

+
+
+
+

+ {{ 'DASHBOARD.stats.title' | translate }} +

+ +

+ {{ 'DASHBOARD.stats.subtitle' | translate }}

-
- -
- {{stats().providers}} -
- -

- {{ 'DASHBOARD.stats.providers' | translate }} -

+
+
+
+ {{ stats().services }} +
+ +

+ {{ 'DASHBOARD.stats.services' | translate }} +

+
+ +
+
+ 10+ +
+ +

+ {{ 'DASHBOARD.stats.sectors' | translate }} +

+
+ +
+
+ {{ stats().providers }} +
+ +

+ {{ 'DASHBOARD.stats.providers' | translate }} +

+
-
diff --git a/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.html b/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.html index 254b0e13..33d587d1 100644 --- a/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.html +++ b/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.html @@ -55,7 +55,7 @@

- +

@@ -69,7 +69,7 @@

- +

diff --git a/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.ts b/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.ts index bbc2e774..962ae26d 100644 --- a/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.ts +++ b/src/app/pages/dashboard/dashboard-whatsdome/dashboard-whatsdome.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { faEye, faMessages, faRotate, faShieldCheck } from '@fortawesome/pro-regular-svg-icons'; +import { faClipboardCheck } from '@fortawesome/pro-regular-svg-icons'; +import { faEye, faPuzzlePiece, faShieldCheck } from '@fortawesome/pro-solid-svg-icons'; import { TranslateModule } from '@ngx-translate/core'; @Component({ @@ -14,6 +15,6 @@ import { TranslateModule } from '@ngx-translate/core'; export class DashboardWhatsDome { faShieldCheck = faShieldCheck; faEye = faEye; - faRotate = faRotate; - faMessages = faMessages; + faPuzzle = faPuzzlePiece; + faClipboard = faClipboardCheck; } diff --git a/src/app/pages/dashboard/dashboard.component.ts b/src/app/pages/dashboard/dashboard.component.ts index 5eeccd73..61f6f3e8 100644 --- a/src/app/pages/dashboard/dashboard.component.ts +++ b/src/app/pages/dashboard/dashboard.component.ts @@ -39,7 +39,7 @@ export interface IDashboardStats { imports: [TranslateModule, ReactiveFormsModule, FeaturedComponent, NgClass, DashboardWhatsDome, DashboardHeroComponent, DashboardStatsComponent, DashboardServicesComponent, DashboardCustomersComponent, DashboardProvidersComponent, DashboardEcosystemComponent], }) export class DashboardComponent implements OnInit, OnDestroy { - customersLink = 'https://onboard.sbx.evidenceledger.eu/register-customer'; + customersLink = 'landing-page/customers'; providersLink = "https://onboard.sbx.evidenceledger.eu/register-provider"; diff --git a/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.css b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.css new file mode 100644 index 00000000..9d938e46 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.css @@ -0,0 +1,234 @@ +:host { + display: block; + width: 100%; +} + +.buy-options-section { + min-height: 682px; + background: linear-gradient(180deg, #0e1e3c 0%, #14274a 50%, #0e1e3c 100%); +} + +.buy-options-blur { + position: absolute; + border-radius: 999999px; + background: #234481; + opacity: 0.25; + filter: blur(120px); + pointer-events: none; + z-index: 0; +} + +.buy-options-blur-left { + width: 520px; + height: 520px; + left: 0; + top: -40px; +} + +.buy-options-blur-right { + width: 440px; + height: 440px; + right: -80px; + top: 35px; +} + +.buy-card { + box-sizing: border-box; + background: linear-gradient(175.9deg, #14274a 3.34%, #0b1528 97.37%); + border: 0.5px solid #234481; + border-radius: 16px; +} + +.buy-card-line { + position: absolute; + top: 0; + left: 8px; + width: calc(100% - 16px); + height: 2px; + border-radius: 0; + opacity: 0.75; + background: linear-gradient(90deg, + rgba(0, 0, 0, 0) 0%, + #00add3 50%, + rgba(0, 0, 0, 0) 100%); + z-index: 2; +} + +.buy-card-featured { + background: linear-gradient(160deg, #0d2a4a 8.49%, #0b1f3a 91.51%); + border: 0.5px solid rgba(0, 173, 211, 0.3); + box-shadow: 0 0 40px rgba(0, 173, 211, 0.08); +} + +.buy-card-featured .buy-card-line { + left: 0; + width: 100%; + opacity: 1; +} + +.buy-card-badge { + box-sizing: border-box; + background: rgba(0, 173, 211, 0.15); + border: 0.666667px solid rgba(0, 173, 211, 0.25); + color: #00add3; + backdrop-filter: blur(4px); +} + +.buy-card-inner-glow { + position: absolute; + width: 298px; + height: 298px; + left: calc(50% - 149px + 43px); + top: 59px; + background: #00add3; + opacity: 0.11; + filter: blur(80px); + pointer-events: none; + z-index: 1; +} + +.buy-card-title { + position: relative; + z-index: 3; + width: 100%; + min-height: 76px; + display: flex; + flex-direction: column; + justify-content: flex-end; + margin: 0; + font-family: 'Blinker', sans-serif; + font-weight: 700; + font-size: 28px; + line-height: 34px; + color: #ffffff; +} + +.buy-card-text { + position: relative; + z-index: 3; + width: 100%; + margin: 0; + font-family: 'Blinker', sans-serif; + font-weight: 400; + font-size: 18px; + line-height: 30px; + color: #ffffff; +} + +@media (min-width: 640px) { + .buy-card-title { + font-size: 30px; + line-height: 36px; + } + + .buy-card-text { + font-size: 19px; + line-height: 31px; + } +} + +@media (min-width: 1024px) { + .buy-options-blur-right { + width: 440px; + height: 440px; + left: auto; + right: -18px; + top: 35px; + } + + .buy-card-title { + width: 309.33px; + height: 76px; + min-height: 76px; + font-size: 32px; + line-height: 38px; + } + + .buy-card-text { + width: 309.33px; + font-size: 20px; + line-height: 32px; + } + + .buy-card-line { + left: 8px; + width: calc(100% - 16px); + } + + .buy-card-featured .buy-card-line { + left: 0.67px; + width: calc(100% - 1.34px); + } +} + +@media (max-width: 1023.98px) { + .buy-options-blur-left { + width: 360px; + height: 360px; + left: -80px; + top: -40px; + filter: blur(100px); + } + + .buy-options-blur-right { + width: 320px; + height: 320px; + right: -100px; + top: 120px; + filter: blur(100px); + } + + .buy-card-inner-glow { + width: 240px; + height: 240px; + left: auto; + right: -20px; + top: 50%; + transform: translateY(-40%); + filter: blur(70px); + } +} + +@media (max-width: 639.98px) { + .buy-options-section { + min-height: auto; + } + + .buy-options-blur-left { + width: 260px; + height: 260px; + left: -80px; + top: -20px; + filter: blur(80px); + } + + .buy-options-blur-right { + width: 240px; + height: 240px; + right: -80px; + top: 180px; + filter: blur(80px); + } + + .buy-card-title { + min-height: auto; + font-size: 26px; + line-height: 32px; + font-weight: 700; + color: white; + } + + .buy-card-text { + font-size: 17px; + line-height: 28px; + } + + .buy-card-inner-glow { + width: 200px; + height: 200px; + right: -10px; + top: 56%; + transform: translateY(-40%); + filter: blur(60px); + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.html b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.html new file mode 100644 index 00000000..492ea719 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.html @@ -0,0 +1,56 @@ +
+ + + +
+

+ {{ 'LANDINGPAGE.customers.buyOptions._title' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.buyOptions._subtitle' | translate }} +

+
+ +
+ @for (card of cards; track card.key) { +
+ + + @if (card.featured) { + + } + +
+ @if (card.badgeKey) { + + {{ card.badgeKey | translate }} + + } +
+ +
+

+ + {{ ('LANDINGPAGE.customers.buyOptions.cards.' + card.key + '._titleLine1') | translate }} + + + {{ ('LANDINGPAGE.customers.buyOptions.cards.' + card.key + '._titleLine2') | translate }} + +

+ +

+ {{ ('LANDINGPAGE.customers.buyOptions.cards.' + card.key + '._description') | translate }} +

+
+
+ } +
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.ts b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.ts new file mode 100644 index 00000000..6f41c7cf --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-buy-options/landing-customers-buy-options.component.ts @@ -0,0 +1,31 @@ +import { Component } from "@angular/core"; +import { TranslateModule } from '@ngx-translate/core'; + +type BuyOptionCard = { + key: string; + featured?: boolean; + badgeKey?: string; +}; + +@Component({ + selector: "app-landing-customers-buy-options", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-customers-buy-options.component.html", + styleUrl: "./landing-customers-buy-options.component.css" +}) +export class LandingCustomersBuyOptionsComponent { + cards: BuyOptionCard[] = [ + { + key: 'offTheShelf' + }, + { + key: 'tailored', + featured: true, + badgeKey: 'LANDINGPAGE.customers.buyOptions.cards.tailored._badge' + }, + { + key: 'tender' + } + ]; +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.css b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.css new file mode 100644 index 00000000..21f48876 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.css @@ -0,0 +1,178 @@ +:host { + display: block; +} + +.faq-section { + background: #EBF0F7; +} + +.faq-heading { + color: #0B1528; + font-weight: 700; + font-size: 32px; + line-height: 38px; +} + +.faq-card { + background: #FFFFFF; + border-radius: 16px; + padding: 24px; + transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease; + border: 1px solid transparent; +} + +.faq-card--open { + border: 1px solid #D8DADE; + box-shadow: 0 0 16px rgba(0, 0, 0, 0.08); +} + +.faq-question { + width: 100%; + display: flex; + align-items: center; + gap: 24px; + background: transparent; + border: none; + padding: 0; + cursor: pointer; + text-align: left; + font: inherit; + color: inherit; +} + +.faq-question__title { + flex: 1; + color: #0B1528; + font-weight: 700; + font-size: 20px; + line-height: 26px; +} + +.faq-icon { + width: 40px; + height: 40px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + background: #DDE6F6; + color: #2D58A7; + flex-shrink: 0; + transition: background-color 0.25s ease, color 0.25s ease, transform 0.25s ease; +} + +.faq-icon svg { + transition: transform 0.25s ease; +} + +.faq-icon--open { + background: #2D58A7; + color: #FFFFFF; +} + +.faq-answer { + display: grid; + grid-template-rows: 0fr; + opacity: 0; + transition: grid-template-rows 0.35s ease, opacity 0.25s ease, margin-top 0.35s ease; + margin-top: 0; +} + +.faq-answer--open { + grid-template-rows: 1fr; + opacity: 1; + margin-top: 16px; +} + +.faq-answer__inner { + overflow: hidden; +} + +.faq-divider { + height: 1px; + background: #D8DADE; + margin-bottom: 16px; + transform: scaleX(0.96); + transform-origin: left center; + transition: transform 0.35s ease, opacity 0.25s ease; + opacity: 0; +} + +.faq-answer--open .faq-divider { + transform: scaleX(1); + opacity: 1; +} + +.faq-answer__content { + color: #324153; + font-size: 18px; + line-height: 30px; + transform: translateY(-8px); + opacity: 0; + transition: transform 0.35s ease, opacity 0.3s ease; +} + +.faq-answer--open .faq-answer__content { + transform: translateY(0); + opacity: 1; +} + +:host ::ng-deep .faq-answer__content p { + margin: 0 0 16px 0; +} + +:host ::ng-deep .faq-answer__content p:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content ul { + margin: 0 0 16px 0; + padding-left: 28px; + list-style: disc outside; +} + +:host ::ng-deep .faq-answer__content ul:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content li { + display: list-item; + margin: 0 0 12px 0; +} + +:host ::ng-deep .faq-answer__content li:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content strong, +:host ::ng-deep .faq-answer__content b { + font-weight: 700; + color: #0B1528; +} + +:host ::ng-deep .faq-answer__content br { + display: block; + content: ""; + margin-top: 12px; +} + +@media (min-width: 1024px) { + .faq-heading { + font-size: 48px; + line-height: 58px; + } + + .faq-question__title { + font-size: 24px; + line-height: 29px; + } + + .faq-answer__content { + font-size: 20px; + line-height: 32px; + } + + :host ::ng-deep .faq-answer__content ul { + padding-left: 30px; + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.html b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.html new file mode 100644 index 00000000..c32d4c41 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.html @@ -0,0 +1,38 @@ +
+
+
+ +

+ {{ 'LANDINGPAGE.customers.faqs.title' | translate }} +

+ +
+ @for (faq of faqs; track faq.id) { +
+ + +
+
+
+ +
+
+
+
+
+
+ } +
+ +
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.ts b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.ts new file mode 100644 index 00000000..4c2b7763 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-faqs/landing-customers-faqs.component.ts @@ -0,0 +1,66 @@ +import { Component } from "@angular/core"; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faMinus, faPlus } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +type FaqItem = { + id: string; + questionKey: string; + answerKey: string; +}; + +@Component({ + selector: "app-landing-customers-faqs", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-customers-faqs.component.html", + styleUrl: "./landing-customers-faqs.component.css" +}) +export class LandingCustomersFaqsComponent { + + faPlus = faPlus; + faMinus = faMinus; + + openFaqId = ''; + + faqs: FaqItem[] = [ + { + id: 'eligibility', + questionKey: 'LANDINGPAGE.customers.faqs._items.eligibility.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.eligibility.answer' + }, + { + id: 'trustworthiness', + questionKey: 'LANDINGPAGE.customers.faqs._items.trustworthiness.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.trustworthiness.answer' + }, + { + id: 'fee', + questionKey: 'LANDINGPAGE.customers.faqs._items.fee.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.fee.answer' + }, + { + id: 'process', + questionKey: 'LANDINGPAGE.customers.faqs._items.process.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.process.answer' + }, + { + id: 'provider', + questionKey: 'LANDINGPAGE.customers.faqs._items.provider.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.provider.answer' + }, + { + id: 'dispute', + questionKey: 'LANDINGPAGE.customers.faqs._items.dispute.question', + answerKey: 'LANDINGPAGE.customers.faqs._items.dispute.answer' + } + ]; + + toggleFaq(id: string) { + this.openFaqId = this.openFaqId === id ? '' : id; + } + + isOpen(id: string): boolean { + return this.openFaqId === id; + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.css b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.css new file mode 100644 index 00000000..0fda67e1 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.css @@ -0,0 +1,179 @@ +:host { + display: block; +} + +.final-cta-section { + background: #EBF0F7; +} + +.final-cta-shell { + position: relative; + overflow: hidden; + isolation: isolate; + border-radius: 16px; + background: linear-gradient(134.43deg, #234481 -16.9%, #0B1528 40.69%, #1A3360 101.69%); +} + +.final-cta-glow { + position: absolute; + width: 520px; + height: 520px; + left: -91px; + top: -158px; + border-radius: 999999px; + background: #234481; + opacity: 0.25; + filter: blur(120px); + z-index: 0; + pointer-events: none; +} + +.final-cta-content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 40px; + padding: 40px 20px; + text-align: center; +} + +.final-cta-text { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + width: 100%; + max-width: 930px; +} + +.final-cta-title { + margin: 0; + color: #FFFFFF; + font-weight: 700; + font-size: 30px; + line-height: 1.15; + text-align: center; +} + +.final-cta-title-accent { + color: #10B7E8; +} + +.final-cta-description { + margin: 0; + max-width: 760px; + color: #FFFFFF; + font-weight: 400; + font-size: 18px; + line-height: 1.4; + text-align: center; +} + +.final-cta-actions { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 14px; + width: 100%; + max-width: 548px; +} + +.final-cta-btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 48px; + width: 100%; + padding: 12px 20px; + border-radius: 6px; + text-align: center; + text-decoration: none; + font-weight: 600; + font-size: 16px; + line-height: 24px; + letter-spacing: 0.5px; + transition: + background-color 0.2s ease, + border-color 0.2s ease, + color 0.2s ease; +} + +.final-cta-btn--primary { + background: #2D58A7; + color: #FFFFFF; + border: 2px solid #2D58A7; +} + +.final-cta-btn--primary:hover { + background: #18B5D9; + border-color: #18B5D9; +} + +.final-cta-btn--secondary { + background: transparent; + color: #FFFFFF; + border: 2px solid #2D58A7; +} + +.final-cta-btn--secondary:hover { + background: #5B6F8E; + border-color: #2D58A7; +} + +@media (min-width: 640px) { + .final-cta-content { + padding: 52px 24px; + } + + .final-cta-title { + font-size: 36px; + } + + .final-cta-description { + font-size: 20px; + line-height: 1.45; + } + + .final-cta-actions { + flex-direction: row; + justify-content: center; + gap: 24px; + } + + .final-cta-btn { + width: 262px; + } +} + +@media (min-width: 1024px) { + .final-cta-shell { + min-height: 351px; + } + + .final-cta-content { + padding: 64px 24px; + gap: 40px; + } + + .final-cta-text { + gap: 24px; + } + + .final-cta-title { + max-width: 930px; + font-size: 44px; + line-height: 53px; + } + + .final-cta-description { + max-width: 930px; + font-size: 24px; + line-height: 29px; + } + + .final-cta-actions { + width: 548px; + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.html b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.html new file mode 100644 index 00000000..9be942b3 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.html @@ -0,0 +1,32 @@ +
+
+
+ + +
+
+

+ {{ 'LANDINGPAGE.customers.finalCta.titleStart' | translate }} + + {{ 'LANDINGPAGE.customers.finalCta.titleAccent' | translate }} + {{ 'LANDINGPAGE.customers.finalCta.titleEnd' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.finalCta.description' | translate }} +

+
+ + +
+
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.ts b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.ts new file mode 100644 index 00000000..7605b6bb --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-finalCta/landing-customers-finalCta.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from "@angular/core"; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: "app-landing-customers-finalCta", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-customers-finalCta.component.html", + styleUrl: "./landing-customers-finalCta.component.css" +}) +export class LandingCustomersFinalCtaComponent { + url = input.required(); +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.css b/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.css new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.html b/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.html new file mode 100644 index 00000000..90d926d4 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.html @@ -0,0 +1,47 @@ +
+
+
+
+
+
+ +
+
+ + {{ 'LANDINGPAGE.customers.hero._badge' | translate }} + + +

+ {{ 'LANDINGPAGE.customers.hero._titleLine1' | translate }}
+ {{ 'LANDINGPAGE.customers.hero._titleAccent' | translate }} + {{ 'LANDINGPAGE.customers.hero._titleLine2' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.hero._desc' | translate }} +

+ + +
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.ts b/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.ts new file mode 100644 index 00000000..dcc336ec --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-hero/landing-customers-hero.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from "@angular/core"; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: "app-landing-customers-hero", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-customers-hero.component.html", + styleUrl: "./landing-customers-hero.component.css" +}) +export class LandingCustomersHeroComponent { + url = input.required(); +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.css b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.css new file mode 100644 index 00000000..3c2103b8 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.css @@ -0,0 +1,157 @@ +:host { + display: block; + width: 100%; +} + +.procure-steps-section { + background: #ebf0f7; +} + +.procure-steps-grid { + display: grid; + grid-template-columns: 1fr; + gap: 16px; + width: 100%; +} + +.procure-step-card { + position: relative; + isolation: isolate; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-start; + gap: 40px; + width: 100%; + min-height: 240px; + padding: 24px; + overflow: hidden; + background: #f7f9fd; + border: 1px solid rgba(216, 218, 222, 0.6); + border-radius: 16px; +} + +.procure-step-icon { + position: absolute; + right: -14.52px; + bottom: -2.52px; + z-index: 0; + width: 120px; + height: 120px; + color: #2d58a7; + opacity: 0.08; + transform: rotate(-15deg); + pointer-events: none; + font-size: 120px; + line-height: 1; +} + +.procure-step-number { + position: relative; + z-index: 1; + width: 78px; + height: 80px; + display: flex; + align-items: center; + margin: 0; + font-family: 'Blinker', sans-serif; + font-style: normal; + font-weight: 800; + font-size: 96px; + line-height: 115px; + letter-spacing: 1px; + background: linear-gradient(180deg, #1a3360 0%, #00add3 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + color: transparent; +} + +.procure-step-title { + position: relative; + z-index: 1; + width: 178px; + min-height: 72px; + margin: 0; + font-family: 'Blinker', sans-serif; + font-style: normal; + font-weight: 600; + font-size: 20px; + line-height: 24px; + color: #0b1528; +} + +.procure-step-connector { + display: none; + width: 56px; + height: 2px; + align-self: center; + background: linear-gradient(90deg, #ebf0f7 0%, #00add3 50%, #ebf0f7 88.94%); + border-radius: 0; +} + +@media (min-width: 640px) and (max-width: 1023.98px) { + .procure-steps-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 20px; + } + + .procure-step-title { + width: 100%; + max-width: 178px; + } +} + +@media (min-width: 1024px) { + .procure-steps-grid { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; + width: 1120px; + height: 240px; + } + + .procure-step-card { + width: 226px; + height: 240px; + min-height: 240px; + flex: 1 1 0; + } + + .procure-step-connector { + display: block; + flex: 0 0 56px; + } +} + +@media (max-width: 639.98px) { + .procure-step-card { + min-height: 220px; + gap: 28px; + padding: 20px; + } + + .procure-step-icon { + right: -10px; + bottom: -6px; + width: 100px; + height: 100px; + font-size: 100px; + } + + .procure-step-number { + width: 64px; + height: 64px; + font-size: 76px; + line-height: 88px; + } + + .procure-step-title { + width: 100%; + min-height: auto; + font-size: 22px; + line-height: 26px; + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.html b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.html new file mode 100644 index 00000000..f9b341fe --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.html @@ -0,0 +1,38 @@ +
+
+
+

+ {{ 'LANDINGPAGE.customers.procureSteps._titleStart' | translate }} + + {{ 'LANDINGPAGE.customers.procureSteps._titleAccent' | translate }} + +

+ +

+ {{ 'LANDINGPAGE.customers.procureSteps._subtitle' | translate }} +

+
+ +
+ @for (step of steps; track step.key; let i = $index) { +
+ + +
+ {{ i + 1 }} +
+ +

+ {{ ('LANDINGPAGE.customers.procureSteps.items.' + step.key + '._title') | translate }} +

+
+ + @if (i < steps.length - 1) { + } + } +
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.ts b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.ts new file mode 100644 index 00000000..8f894883 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-procure-steps/landing-customers-procure-steps.component.ts @@ -0,0 +1,26 @@ +import { Component } from "@angular/core"; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faBagShopping, faHandshake, faMagnifyingGlass, faUser } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +type ProcureStep = { + key: string; + icon: any; +}; + + +@Component({ + selector: "app-landing-customers-procure-steps", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-customers-procure-steps.component.html", + styleUrl: "./landing-customers-procure-steps.component.css" +}) +export class LandingCustomersProcureStepsComponent { + steps: ProcureStep[] = [ + { key: 'step1', icon: faUser }, + { key: 'step2', icon: faMagnifyingGlass }, + { key: 'step3', icon: faBagShopping }, + { key: 'step4', icon: faHandshake } + ]; +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.css b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.css new file mode 100644 index 00000000..bb8d811c --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.css @@ -0,0 +1,106 @@ +.right-for-you-section { + min-height: 920px; +} + +.right-for-you-layout { + display: grid; + grid-template-columns: 453px 554px; + justify-content: space-between; + align-items: center; + column-gap: 24px; +} + +.right-for-you-copy { + padding-top: 80px; +} + +.right-for-you-watermark { + position: absolute; + left: -124px; + bottom: -142px; + width: 511px; + height: 511px; + opacity: 0.5; + pointer-events: none; + user-select: none; + background-color: #dde6f6; + mask-image: url("/assets/logos/DOME_Icon_White.svg"); + -webkit-mask-image: url("/assets/logos/DOME_Icon_White.svg"); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-position: center; + -webkit-mask-position: center; + mask-size: contain; + -webkit-mask-size: contain; +} + +.right-for-you-cards-col { + display: flex; + justify-content: flex-end; +} + +.right-for-you-scroll { + width: 554px; + max-width: 100%; +} + +.scroll-card { + width: 548px; + max-width: 100%; + background: #ebf0f7; + border-radius: 16px; + padding: 24px; + box-sizing: border-box; + position: relative; + z-index: 2; + transition: + background-color 0.2s ease, + transform 0.2s ease, + box-shadow 0.2s ease; +} + +.scroll-card.is-active { + background: #ebf0f7; +} + +@media (max-width: 1279px) { + .right-for-you-layout { + grid-template-columns: 1fr; + row-gap: 40px; + } + + .right-for-you-copy { + padding-top: 0; + max-width: 640px; + } + + .right-for-you-cards-col { + justify-content: flex-start; + } + + .right-for-you-scroll { + width: 100%; + max-width: 554px; + } + + .scroll-card { + width: 100%; + } +} + +@media (max-width: 640px) { + .right-for-you-section { + min-height: auto; + } + + .right-for-you-watermark { + width: 320px; + left: -90px; + bottom: -100px; + opacity: 0.35; + } + + .right-for-you-scroll { + width: 100%; + } +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.html b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.html new file mode 100644 index 00000000..d0e22356 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.html @@ -0,0 +1,46 @@ +
+
+ +
+
+
+

+ {{ 'LANDINGPAGE.customers.rightForYou._titleStart' | translate }} + + {{ 'LANDINGPAGE.customers.rightForYou._titleAccent' | translate }} + + {{ 'LANDINGPAGE.customers.rightForYou._titleEnd' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.rightForYou._desc' | translate }} +

+
+ +
+ + @for (card of cards; track card.titleKey) { +
+
+
+ +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descKey | translate }} +

+
+
+
+ } +
+
+
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.ts b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.ts new file mode 100644 index 00000000..35da683f --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-rightForYou/landing-customers-rightForYou.component.ts @@ -0,0 +1,65 @@ +import { Component } from "@angular/core"; +import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; +import { + faBuilding, + faFileShield, + faLandmark, + faScaleBalanced, + faShieldHalved +} from "@fortawesome/free-solid-svg-icons"; +import { TranslateModule } from "@ngx-translate/core"; +import { VerticalScrollCardsModule } from '../../../../shared/vertical-scroll-cards/vertical-scroll-cards.module'; + +type RightForYouCard = { + titleKey: string; + descKey: string; + icon: any; +}; + +@Component({ + selector: "app-landingpage-customers-right-for-you", + standalone: true, + imports: [ + TranslateModule, + FontAwesomeModule, + VerticalScrollCardsModule + ], + templateUrl: "./landing-customers-rightForYou.component.html", + styleUrl: "./landing-customers-rightForYou.component.css" +}) +export class LandingpageCustomersRightForYouComponent { + + get scrollHeight(): number { + if (window.innerWidth < 768) return 460 + if (window.innerWidth < 1280) return 540 + return 636 + } + + cards: RightForYouCard[] = [ + { + titleKey: "LANDINGPAGE.customers.rightForYou._regulatedIndustriesTitle", + descKey: "LANDINGPAGE.customers.rightForYou._regulatedIndustriesDesc", + icon: faShieldHalved + }, + { + titleKey: "LANDINGPAGE.customers.rightForYou._enterprisesTitle", + descKey: "LANDINGPAGE.customers.rightForYou._enterprisesDesc", + icon: faBuilding + }, + { + titleKey: "LANDINGPAGE.customers.rightForYou._publicSectorTitle", + descKey: "LANDINGPAGE.customers.rightForYou._publicSectorDesc", + icon: faLandmark + }, + { + titleKey: "LANDINGPAGE.customers.rightForYou._complianceTeamsTitle", + descKey: "LANDINGPAGE.customers.rightForYou._complianceTeamsDesc", + icon: faScaleBalanced + }, + { + titleKey: "LANDINGPAGE.customers.rightForYou._structuredProcurementTitle", + descKey: "LANDINGPAGE.customers.rightForYou._structuredProcurementDesc", + icon: faFileShield + } + ]; +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.css b/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.css new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.html b/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.html new file mode 100644 index 00000000..51f837fe --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.html @@ -0,0 +1,83 @@ +
+
+
+
+
+

+ {{ 'LANDINGPAGE.customers.trusted._titleStart' | translate }} + + {{ 'LANDINGPAGE.customers.trusted._titleAccent' | translate }} + + {{ 'LANDINGPAGE.customers.trusted._titleEnd' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.trusted._desc' | translate }} +

+
+ + @for (item of values; track item.key) { + +
+
+ +
+ + + {{ item.key | translate }} + +
+ } +
+
+ +
+
+
+ @for (card of leftCards; track card.titleKey) { +
+
+ + +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descKey | translate }} +

+
+
+ } +
+ +
+ @for (card of rightCards; track card.titleKey) { +
+
+ + +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descKey | translate }} +

+
+
+ } +
+
+
+
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.ts b/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.ts new file mode 100644 index 00000000..725ceab3 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-trusted/landing-customers-trusted.component.ts @@ -0,0 +1,57 @@ +import { Component } from "@angular/core"; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faCircleCheck, faFileLines, faGlobe, faTableCellsLarge, faThumbsUp, IconDefinition } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +type ValueItem = { + key: string; +}; + +type InfoCard = { + titleKey: string; + descKey: string; + icon: IconDefinition; +}; + +@Component({ + selector: "app-landing-customers-trusted", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-customers-trusted.component.html", + styleUrl: "./landing-customers-trusted.component.css" +}) +export class LandingCustomersTrustedComponent { + faCircleCheck = faCircleCheck; + + values: ValueItem[] = [ + { key: "LANDINGPAGE.customers.trusted.values.trustStandardised" }, + { key: "LANDINGPAGE.customers.trusted.values.evidenceVisible" }, + { key: "LANDINGPAGE.customers.trusted.values.comparisonSimplified" }, + ]; + + leftCards: InfoCard[] = [ + { + titleKey: "LANDINGPAGE.customers.trusted.cards.verifiedServices.title", + descKey: "LANDINGPAGE.customers.trusted.cards.verifiedServices.desc", + icon: faTableCellsLarge, + }, + { + titleKey: "LANDINGPAGE.customers.trusted.cards.trustIndicators.title", + descKey: "LANDINGPAGE.customers.trusted.cards.trustIndicators.desc", + icon: faThumbsUp, + }, + ]; + + rightCards: InfoCard[] = [ + { + titleKey: "LANDINGPAGE.customers.trusted.cards.documentation.title", + descKey: "LANDINGPAGE.customers.trusted.cards.documentation.desc", + icon: faFileLines, + }, + { + titleKey: "LANDINGPAGE.customers.trusted.cards.crossBorderAccess.title", + descKey: "LANDINGPAGE.customers.trusted.cards.crossBorderAccess.desc", + icon: faGlobe, + }, + ]; +} diff --git a/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.css b/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.css new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.html b/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.html new file mode 100644 index 00000000..3fc09da4 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.html @@ -0,0 +1,61 @@ +
+
+
+
+
+
+
+ +
+ +
+ +

+ {{ 'LANDINGPAGE.customers.whyJoin._title' | translate }} +

+ +

+ {{ 'LANDINGPAGE.customers.whyJoin._subtitle' | translate }} +

+ +
+ +
+ + @for (card of cards; track card.titleStartKey) { + +
+ +
+
+ +

+ + {{ card.titleStartKey | translate }} + + + {{ card.titleAccentKey | translate }} + + + {{ card.titleEndKey ? (card.titleEndKey | translate) : '' }} + +

+ +

+ {{ card.descKey | translate }} +

+ +
+ + } + +
+ +
+
diff --git a/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.ts b/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.ts new file mode 100644 index 00000000..faa148ae --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-customers-whyJoin/landing-customers-whyJoin.component.ts @@ -0,0 +1,43 @@ +import { Component } from "@angular/core"; +import { TranslateModule } from "@ngx-translate/core"; + +type WhyJoinCard = { + titleStartKey: string; + titleAccentKey: string; + titleEndKey?: string; + descKey: string; +}; + +@Component({ + selector: "app-landingpage-customers-why-join", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-customers-whyJoin.component.html", +}) +export class LandingpageCustomersWhyJoinComponent { + + cards: WhyJoinCard[] = [ + { + titleStartKey: "LANDINGPAGE.customers.whyJoin._dataTitleStart", + titleAccentKey: "LANDINGPAGE.customers.whyJoin._dataTitleAccent", + descKey: "LANDINGPAGE.customers.whyJoin._dataDesc" + }, + { + titleStartKey: "LANDINGPAGE.customers.whyJoin._crossTitleStart", + titleAccentKey: "LANDINGPAGE.customers.whyJoin._crossTitleAccent", + descKey: "LANDINGPAGE.customers.whyJoin._crossDesc" + }, + { + titleStartKey: "LANDINGPAGE.customers.whyJoin._riskTitleStart", + titleAccentKey: "LANDINGPAGE.customers.whyJoin._riskTitleAccent", + titleEndKey: "LANDINGPAGE.customers.whyJoin._riskTitleEnd", + descKey: "LANDINGPAGE.customers.whyJoin._riskDesc" + }, + { + titleStartKey: "LANDINGPAGE.customers.whyJoin._actionTitleStart", + titleAccentKey: "LANDINGPAGE.customers.whyJoin._actionTitleAccent", + descKey: "LANDINGPAGE.customers.whyJoin._actionDesc" + } + ]; + +} diff --git a/src/app/pages/landing-pages/customers/landing-page-customers.component.css b/src/app/pages/landing-pages/customers/landing-page-customers.component.css new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/landing-pages/customers/landing-page-customers.component.html b/src/app/pages/landing-pages/customers/landing-page-customers.component.html new file mode 100644 index 00000000..65c60249 --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-page-customers.component.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/app/pages/landing-pages/customers/landing-page-customers.component.ts b/src/app/pages/landing-pages/customers/landing-page-customers.component.ts new file mode 100644 index 00000000..c62a5a7c --- /dev/null +++ b/src/app/pages/landing-pages/customers/landing-page-customers.component.ts @@ -0,0 +1,20 @@ +import { Component } from "@angular/core"; +import { LandingCustomersBuyOptionsComponent } from './landing-customers-buy-options/landing-customers-buy-options.component'; +import { LandingCustomersFaqsComponent } from './landing-customers-faqs/landing-customers-faqs.component'; +import { LandingCustomersFinalCtaComponent } from './landing-customers-finalCta/landing-customers-finalCta.component'; +import { LandingCustomersHeroComponent } from "./landing-customers-hero/landing-customers-hero.component"; +import { LandingCustomersProcureStepsComponent } from './landing-customers-procure-steps/landing-customers-procure-steps.component'; +import { LandingpageCustomersRightForYouComponent } from "./landing-customers-rightForYou/landing-customers-rightForYou.component"; +import { LandingCustomersTrustedComponent } from './landing-customers-trusted/landing-customers-trusted.component'; +import { LandingpageCustomersWhyJoinComponent } from "./landing-customers-whyJoin/landing-customers-whyJoin.component"; + +@Component({ + selector: "app-landing-page-customers", + standalone: true, + imports: [LandingCustomersHeroComponent, LandingCustomersTrustedComponent, LandingpageCustomersWhyJoinComponent, LandingpageCustomersRightForYouComponent, LandingCustomersBuyOptionsComponent, LandingCustomersProcureStepsComponent, LandingCustomersFaqsComponent, LandingCustomersFinalCtaComponent], + templateUrl: "./landing-page-customers.component.html", + styleUrl: "./landing-page-customers.component.css" +}) +export class LandingPageCustomersComponent { + ONBOARDING_CUSTOMERS_LINK = "https://onboard.sbx.evidenceledger.eu/register-customer"; +} diff --git a/src/app/pages/landing-pages/providers/landing-page-providers.component.css b/src/app/pages/landing-pages/providers/landing-page-providers.component.css new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-page-providers.component.css @@ -0,0 +1 @@ + diff --git a/src/app/pages/landing-pages/providers/landing-page-providers.component.html b/src/app/pages/landing-pages/providers/landing-page-providers.component.html new file mode 100644 index 00000000..d799d86c --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-page-providers.component.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/app/pages/landing-pages/providers/landing-page-providers.component.ts b/src/app/pages/landing-pages/providers/landing-page-providers.component.ts new file mode 100644 index 00000000..6ea5d3b7 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-page-providers.component.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; +import { LandingPageProvidersFaqsComponent } from './landing-providers-faqs/landing-providers-faqs.component'; +import { LandingPageProvidersFitComponent } from './landing-providers-fit/landing-providers-fit.component'; +import { LandingPageProvidersGrowComponent } from './landing-providers-grow/landing-providers-grow.component'; +import { LandingPageProvidersHeroComponent } from './landing-providers-hero/landing-providers-hero.component'; +import { LandingPageProvidersIncludedComponent } from "./landing-providers-included/landing-providers-included.component"; +import { LandingPageProvidersProcureComponent } from "./landing-providers-procure/landing-providers-procure.component"; +import { LandingPageProvidersTrustComponent } from './landing-providers-trust/landing-providers-trust.component'; +import { LandingPageProvidersWhyComponent } from './landing-providers-why/landing-providers-why.component'; + +@Component({ + selector: "app-landing-page-providers", + standalone: true, + imports: [LandingPageProvidersHeroComponent, LandingPageProvidersTrustComponent, LandingPageProvidersWhyComponent, LandingPageProvidersFitComponent, LandingPageProvidersIncludedComponent, LandingPageProvidersProcureComponent, LandingPageProvidersFaqsComponent, LandingPageProvidersGrowComponent], + templateUrl: "./landing-page-providers.component.html", + styleUrl: "./landing-page-providers.component.css" +}) +export class LandingPageProvidersComponent { + ONBOARDING_PROVIDERS_LINK = "https://onboard.sbx.evidenceledger.eu/register-provider"; + + constructor() { } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.css b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.css new file mode 100644 index 00000000..21f48876 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.css @@ -0,0 +1,178 @@ +:host { + display: block; +} + +.faq-section { + background: #EBF0F7; +} + +.faq-heading { + color: #0B1528; + font-weight: 700; + font-size: 32px; + line-height: 38px; +} + +.faq-card { + background: #FFFFFF; + border-radius: 16px; + padding: 24px; + transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease; + border: 1px solid transparent; +} + +.faq-card--open { + border: 1px solid #D8DADE; + box-shadow: 0 0 16px rgba(0, 0, 0, 0.08); +} + +.faq-question { + width: 100%; + display: flex; + align-items: center; + gap: 24px; + background: transparent; + border: none; + padding: 0; + cursor: pointer; + text-align: left; + font: inherit; + color: inherit; +} + +.faq-question__title { + flex: 1; + color: #0B1528; + font-weight: 700; + font-size: 20px; + line-height: 26px; +} + +.faq-icon { + width: 40px; + height: 40px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + background: #DDE6F6; + color: #2D58A7; + flex-shrink: 0; + transition: background-color 0.25s ease, color 0.25s ease, transform 0.25s ease; +} + +.faq-icon svg { + transition: transform 0.25s ease; +} + +.faq-icon--open { + background: #2D58A7; + color: #FFFFFF; +} + +.faq-answer { + display: grid; + grid-template-rows: 0fr; + opacity: 0; + transition: grid-template-rows 0.35s ease, opacity 0.25s ease, margin-top 0.35s ease; + margin-top: 0; +} + +.faq-answer--open { + grid-template-rows: 1fr; + opacity: 1; + margin-top: 16px; +} + +.faq-answer__inner { + overflow: hidden; +} + +.faq-divider { + height: 1px; + background: #D8DADE; + margin-bottom: 16px; + transform: scaleX(0.96); + transform-origin: left center; + transition: transform 0.35s ease, opacity 0.25s ease; + opacity: 0; +} + +.faq-answer--open .faq-divider { + transform: scaleX(1); + opacity: 1; +} + +.faq-answer__content { + color: #324153; + font-size: 18px; + line-height: 30px; + transform: translateY(-8px); + opacity: 0; + transition: transform 0.35s ease, opacity 0.3s ease; +} + +.faq-answer--open .faq-answer__content { + transform: translateY(0); + opacity: 1; +} + +:host ::ng-deep .faq-answer__content p { + margin: 0 0 16px 0; +} + +:host ::ng-deep .faq-answer__content p:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content ul { + margin: 0 0 16px 0; + padding-left: 28px; + list-style: disc outside; +} + +:host ::ng-deep .faq-answer__content ul:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content li { + display: list-item; + margin: 0 0 12px 0; +} + +:host ::ng-deep .faq-answer__content li:last-child { + margin-bottom: 0; +} + +:host ::ng-deep .faq-answer__content strong, +:host ::ng-deep .faq-answer__content b { + font-weight: 700; + color: #0B1528; +} + +:host ::ng-deep .faq-answer__content br { + display: block; + content: ""; + margin-top: 12px; +} + +@media (min-width: 1024px) { + .faq-heading { + font-size: 48px; + line-height: 58px; + } + + .faq-question__title { + font-size: 24px; + line-height: 29px; + } + + .faq-answer__content { + font-size: 20px; + line-height: 32px; + } + + :host ::ng-deep .faq-answer__content ul { + padding-left: 30px; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.html b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.html new file mode 100644 index 00000000..8c953207 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.html @@ -0,0 +1,38 @@ +
+
+
+ +

+ {{ 'LANDINGPAGE.providers.faqs.title' | translate }} +

+ +
+ @for (faq of faqs; track faq.id) { +
+ + +
+
+
+ +
+
+
+
+
+
+ } +
+ +
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.ts b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.ts new file mode 100644 index 00000000..b675860f --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-faqs/landing-providers-faqs.component.ts @@ -0,0 +1,66 @@ +import { Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faMinus, faPlus } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +type FaqItem = { + id: string; + questionKey: string; + answerKey: string; +}; + + +@Component({ + selector: "app-landing-page-providers-faqs", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-providers-faqs.component.html", + styleUrl: "./landing-providers-faqs.component.css" +}) +export class LandingPageProvidersFaqsComponent { + faPlus = faPlus; + faMinus = faMinus; + + openFaqId = ''; + + faqs: FaqItem[] = [ + { + id: '1', + questionKey: 'LANDINGPAGE.providers.faqs._items.1.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.1.answer' + }, + { + id: '2', + questionKey: 'LANDINGPAGE.providers.faqs._items.2.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.2.answer' + }, + { + id: '3', + questionKey: 'LANDINGPAGE.providers.faqs._items.3.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.3.answer' + }, + { + id: '4', + questionKey: 'LANDINGPAGE.providers.faqs._items.4.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.4.answer' + }, + { + id: '5', + questionKey: 'LANDINGPAGE.providers.faqs._items.5.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.5.answer' + }, + { + id: '6', + questionKey: 'LANDINGPAGE.providers.faqs._items.6.question', + answerKey: 'LANDINGPAGE.providers.faqs._items.6.answer' + } + ]; + + toggleFaq(id: string) { + this.openFaqId = this.openFaqId === id ? '' : id; + } + + isOpen(id: string): boolean { + return this.openFaqId === id; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.css b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.css new file mode 100644 index 00000000..06170da8 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.css @@ -0,0 +1,163 @@ +.good-fit-section { + min-height: 960px; +} + +.good-fit-layout { + display: grid; + grid-template-columns: 454px 580px; + justify-content: space-between; + align-items: center; + column-gap: 40px; +} + +.good-fit-copy { + max-width: 454px; +} + +.good-fit-title { + margin: 0; + color: #0b1528; + font-size: 48px; + font-weight: 700; + line-height: 58px; + letter-spacing: -0.02em; +} + +.good-fit-description { + margin: 24px 0 0; + color: #1f2937; + font-size: 20px; + line-height: 1.6; +} + +.good-fit-cards-col { + display: flex; + justify-content: flex-end; + min-width: 0; +} + +.good-fit-scroll { + width: 580px; + max-width: 100%; +} + +.good-fit-card { + width: 100%; + background: #ebf0f7; + border-radius: 20px; + padding: 28px 30px; + box-sizing: border-box; + transition: + background-color 0.2s ease, + transform 0.2s ease; +} + +.good-fit-card__icon { + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 76px; + border-radius: 18px; + background: #dfe7f5; + color: #2f58a7; + flex: 0 0 auto; +} + +.good-fit-card__title { + margin: 0; + color: #0b1528; + font-size: 24px; + font-weight: 700; + line-height: 1.2; +} + +.good-fit-card__desc { + margin: 0; + color: #4a5a70; + font-size: 20px; + line-height: 1.65; +} + +.good-fit-watermark { + position: absolute; + left: -120px; + bottom: -140px; + width: 560px; + height: 560px; + opacity: 0.5; + background-color: #edf2f8; + mask-image: url("/assets/logos/DOME_Icon_White.svg"); + -webkit-mask-image: url("/assets/logos/DOME_Icon_White.svg"); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-position: center; + -webkit-mask-position: center; + mask-size: contain; + -webkit-mask-size: contain; +} + +@media (max-width: 1279px) { + .good-fit-section { + min-height: auto; + } + + .good-fit-layout { + grid-template-columns: 1fr; + row-gap: 40px; + } + + .good-fit-copy { + max-width: 640px; + } + + .good-fit-cards-col { + justify-content: flex-start; + } + + .good-fit-scroll { + width: 100%; + max-width: 580px; + } +} + +@media (max-width: 767px) { + .good-fit-title { + font-size: 32px; + line-height: 40px; + } + + .good-fit-description { + margin-top: 16px; + font-size: 18px; + line-height: 1.6; + } + + .good-fit-card { + padding: 24px; + border-radius: 16px; + } + + .good-fit-card__icon { + width: 64px; + height: 64px; + border-radius: 16px; + } + + .good-fit-card__title { + font-size: 22px; + } + + .good-fit-card__desc { + font-size: 18px; + line-height: 1.6; + } + + .good-fit-watermark { + left: -90px; + bottom: -100px; + width: 320px; + height: 320px; + opacity: 0.35; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.html b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.html new file mode 100644 index 00000000..f652b354 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.html @@ -0,0 +1,45 @@ +
+ + +
+
+
+

+ {{ "LANDINGPAGE.providers.goodFit.titleStart" | translate }} + + {{ "LANDINGPAGE.providers.goodFit.titleAccent" | translate }} + + {{ "LANDINGPAGE.providers.goodFit.titleEnd" | translate }} +

+ +

+ {{ "LANDINGPAGE.providers.goodFit.description" | translate }} +

+
+ +
+ + @for (card of cards; track card.titleKey) { +
+
+
+ +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descKey | translate }} +

+
+
+
+ } +
+
+
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.ts b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.ts new file mode 100644 index 00000000..e3b4bed3 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-fit/landing-providers-fit.component.ts @@ -0,0 +1,49 @@ +import { Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faBuildingColumns, faCloud, faPuzzlePiece, faRocket } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; +import { VerticalScrollCardsModule } from '../../../../shared/vertical-scroll-cards/vertical-scroll-cards.module'; + +type ProviderGoodFitCard = { + titleKey: string; + descKey: string; + icon: any; +}; + +@Component({ + selector: "app-landing-page-providers-fit", + standalone: true, + imports: [TranslateModule, FontAwesomeModule, VerticalScrollCardsModule], + templateUrl: "./landing-providers-fit.component.html", + styleUrl: "./landing-providers-fit.component.css" +}) +export class LandingPageProvidersFitComponent { + get scrollHeight(): number { + if (window.innerWidth < 768) return 460 + if (window.innerWidth < 1280) return 540 + return 636 + } + + cards: ProviderGoodFitCard[] = [ + { + titleKey: "LANDINGPAGE.providers.goodFit.cards.cloud.title", + descKey: "LANDINGPAGE.providers.goodFit.cards.cloud.desc", + icon: faCloud + }, + { + titleKey: "LANDINGPAGE.providers.goodFit.cards.saas.title", + descKey: "LANDINGPAGE.providers.goodFit.cards.saas.desc", + icon: faPuzzlePiece + }, + { + titleKey: "LANDINGPAGE.providers.goodFit.cards.deepTech.title", + descKey: "LANDINGPAGE.providers.goodFit.cards.deepTech.desc", + icon: faRocket + }, + { + titleKey: "LANDINGPAGE.providers.goodFit.cards.publicSector.title", + descKey: "LANDINGPAGE.providers.goodFit.cards.publicSector.desc", + icon: faBuildingColumns + } + ]; +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.css b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.css new file mode 100644 index 00000000..70e04d75 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.css @@ -0,0 +1,78 @@ +:host { + display: block; +} + +.cta-provider-card { + min-height: 322px; + background: linear-gradient(134.88deg, #1A3360 -34.11%, #0B1528 41.11%, #1A3360 120.81%); +} + +.cta-provider-blur { + position: absolute; + width: 520px; + height: 520px; + left: -91px; + top: -158px; + border-radius: 999999px; + background: #234481; + opacity: 0.25; + filter: blur(120px); + z-index: 0; +} + +.cta-btn { + display: flex; + height: 48px; + min-width: 0; + flex: 1; + align-items: center; + justify-content: center; + padding-left: 20px; + padding-right: 20px; + border-radius: 6px; + font-size: 16px; + font-weight: 600; + line-height: 24px; + letter-spacing: 0.5px; + text-align: center; + text-decoration: none; + transition: + background-color 0.2s ease, + border-color 0.2s ease, + color 0.2s ease; +} + +.cta-btn--primary { + background: #2D58A7; + color: #ffffff; +} + +.cta-btn--primary:hover { + background: #18B5D9; + color: #ffffff; +} + +.cta-btn--secondary { + background: transparent; + color: #ffffff; + border: 2px solid #2D58A7; +} + +.cta-btn--secondary:hover { + background: #5B6F8E; + color: #ffffff; + border-color: #2D58A7; +} + +@media (max-width: 1023.98px) { + .cta-provider-card { + min-height: auto; + } + + .cta-provider-blur { + left: -180px; + top: -180px; + width: 420px; + height: 420px; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.html b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.html new file mode 100644 index 00000000..65e26ecf --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.html @@ -0,0 +1,31 @@ +
+
+
+ + + +
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.ts b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.ts new file mode 100644 index 00000000..bfb92ece --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-grow/landing-providers-grow.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: "app-landing-page-providers-grow", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-providers-grow.component.html", + styleUrl: "./landing-providers-grow.component.css" +}) +export class LandingPageProvidersGrowComponent { + url = input.required(); +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.css b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.css new file mode 100644 index 00000000..8af1b82f --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.css @@ -0,0 +1,55 @@ +.provider-btn { + display: flex; + height: 56px; + min-width: 0; + flex: 1; + align-items: center; + justify-content: center; + padding: 16px 24px; + border-radius: 8px; + font-size: 16px; + font-weight: 600; + line-height: 22px; + text-align: center; + text-decoration: none; + transition: + background-color 0.25s ease, + border-color 0.25s ease, + color 0.25s ease, + transform 0.15s ease; +} + +.provider-btn--primary { + background: #2D58A7; + color: #ffffff; + border: 2px solid transparent; +} + +.provider-btn--primary:hover { + background: #1BA6BD; + color: #ffffff; + transform: translateY(-1px); +} + +.provider-btn--secondary { + background: transparent; + color: #ffffff; + border: 3px solid #2D58A7; +} + +.provider-btn--secondary:hover { + background: #4E678A; + color: #ffffff; + border-color: #2D58A7; + transform: translateY(-1px); +} + +.provider-btn:active { + transform: translateY(0); +} + +@media (min-width: 640px) { + .provider-btn { + font-size: 18px; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.html b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.html new file mode 100644 index 00000000..35c673c1 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.html @@ -0,0 +1,46 @@ +
+ +
+
+ +
+
+ +
+
+ + + {{ 'LANDINGPAGE.providers.badge' | translate }} + + + +

+ {{ 'LANDINGPAGE.providers.titleLine1' | translate }}
+ {{ 'LANDINGPAGE.providers.titleHighlight' | translate }} + {{ 'LANDINGPAGE.providers.titleLine2' | translate }} +

+ +

+ {{ 'LANDINGPAGE.providers.description' | translate }} +

+ + +
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.ts b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.ts new file mode 100644 index 00000000..6ca23462 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-hero/landing-providers-hero.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: "app-landing-page-providers-hero", + standalone: true, + imports: [TranslateModule], + templateUrl: "./landing-providers-hero.component.html", + styleUrl: "./landing-providers-hero.component.css" +}) +export class LandingPageProvidersHeroComponent { + url = input.required(); +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.css b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.css new file mode 100644 index 00000000..4f9c7de6 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.css @@ -0,0 +1,41 @@ +:host { + display: block; +} + +.providers-included-section { + background: linear-gradient(180deg, #0e1e3c 0%, #14274a 50%, #0e1e3c 100%); +} + +.providers-included-glow { + position: absolute; + border-radius: 999999px; + background: #234481; + opacity: 0.25; + filter: blur(120px); + pointer-events: none; +} + +.providers-included-glow--left { + width: 520px; + height: 520px; + left: 0; + top: -40px; +} + +.providers-included-glow--right { + width: 440px; + height: 440px; + right: -18px; + top: 35px; +} + +.provider-card__top-line { + position: absolute; + top: 0; + left: 50%; + width: calc(100% - 18px); + height: 2px; + transform: translateX(-50%); + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, #00add3 50%, rgba(0, 0, 0, 0) 100%); + opacity: 0.75; +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.html b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.html new file mode 100644 index 00000000..7c0bde6c --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.html @@ -0,0 +1,44 @@ +
+ + + + +
+

+ {{ 'LANDINGPAGE.providers.included.title' | translate }} +

+
+ +
+ + + @for (card of cards; track card.titleKey) { +
+
+ + + +
+ + +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descriptionKey | translate }} +

+
+
+
+ } + +
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.ts b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.ts new file mode 100644 index 00000000..42cdc6ce --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-included/landing-providers-included.component.ts @@ -0,0 +1,106 @@ +import { Component, HostListener } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { + faBadgeCheck, + faBullhorn, + faChartColumn, + faCircleQuestion, + faCreditCard, + faGear, + faGlobe, + faRocket, + faShieldHalved +} from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; +import { CarouselComponent } from '../../../../shared/carousel/carousel.component'; + +type ProviderIncludedCard = { + titleKey: string; + descriptionKey: string; + icon: any; +}; + +@Component({ + selector: 'app-landing-page-providers-included', + standalone: true, + templateUrl: './landing-providers-included.component.html', + styleUrl: './landing-providers-included.component.css', + imports: [TranslateModule, FontAwesomeModule, CarouselComponent] +}) +export class LandingPageProvidersIncludedComponent { + visibleItems = 3; + + cards: ProviderIncludedCard[] = [ + { + titleKey: 'LANDINGPAGE.providers.included.cards.onboarding.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.onboarding.description', + icon: faBadgeCheck + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.procurement.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.procurement.description', + icon: faRocket + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.trust.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.trust.description', + icon: faShieldHalved + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.performance.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.performance.description', + icon: faChartColumn + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.advanced.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.advanced.description', + icon: faGear + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.commercial.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.commercial.description', + icon: faCreditCard + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.operational.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.operational.description', + icon: faCircleQuestion + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.marketing.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.marketing.description', + icon: faBullhorn + }, + { + titleKey: 'LANDINGPAGE.providers.included.cards.federated.title', + descriptionKey: 'LANDINGPAGE.providers.included.cards.federated.description', + icon: faGlobe + } + ]; + + constructor() { + this.updateVisibleItems(); + } + + @HostListener('window:resize') + onResize(): void { + this.updateVisibleItems(); + } + + private updateVisibleItems(): void { + + const width = window.innerWidth; + + if (width < 768) { + this.visibleItems = 1; + return; + } + + if (width < 1280) { + this.visibleItems = 2; + return; + } + + this.visibleItems = 3; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.css b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.css new file mode 100644 index 00000000..e65bbcf7 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.css @@ -0,0 +1,158 @@ +:host { + display: block; +} + +.providers-steps-layout { + display: flex; + flex-direction: column; + gap: 32px; +} + +.providers-steps-copy { + max-width: 1120px; +} + +.providers-steps-cards { + display: flex; + flex-direction: column; + gap: 24px; + align-items: stretch; +} + +.providers-step-wrapper { + width: 100%; +} + +.providers-step-card { + position: relative; + width: 100%; + min-height: 190px; + background: #f7f9fd; + border: 1px solid rgba(216, 218, 222, 0.6); + border-radius: 16px; + padding: 20px; + box-sizing: border-box; + overflow: hidden; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 24px; +} + +.providers-step-icon { + position: absolute; + right: -8px; + bottom: -8px; + font-size: 72px; + color: #2d58a7; + opacity: 0.07; +} + +.providers-step-number { + display: inline-block; + font-size: 52px; + font-weight: 800; + line-height: 1; + letter-spacing: 0.02em; +} + +.providers-step-text { + max-width: 180px; + font-size: 16px; + font-weight: 600; + line-height: 1.2; + color: #0b1528; +} + +.providers-step-separator { + display: none; +} + +.gradient-number { + background: linear-gradient(180deg, #1a3360 0%, #00add3 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + line-height: 1; +} + +@media (min-width: 640px) { + .providers-step-card { + min-height: 220px; + padding: 24px; + gap: 24px; + } + + .providers-step-icon { + right: -16px; + bottom: -16px; + font-size: 96px; + } + + .providers-step-number { + font-size: 72px; + } + + .providers-step-text { + font-size: 18px; + } +} + +@media (min-width: 768px) and (max-width: 1279px) { + .providers-steps-cards { + flex-direction: row; + flex-wrap: wrap; + gap: 24px; + } + + .providers-step-wrapper { + width: calc(50% - 12px); + } +} + +@media (min-width: 1280px) { + .providers-steps-layout { + gap: 40px; + } + + .providers-steps-cards { + flex-direction: row; + flex-wrap: nowrap; + align-items: stretch; + gap: 8px; + } + + .providers-step-wrapper { + width: auto; + flex: 0 0 auto; + } + + .providers-step-card { + width: 226px; + min-height: 240px; + padding: 24px; + } + + .providers-step-icon { + right: -22px; + bottom: -20px; + font-size: 120px; + } + + .providers-step-number { + font-size: 96px; + } + + .providers-step-text { + font-size: 20px; + } + + .providers-step-separator { + display: block; + width: 56px; + height: 2px; + align-self: center; + flex: 0 0 auto; + background: linear-gradient(90deg, #ebf0f7 0%, #00add3 50%, #ebf0f7 100%); + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.html b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.html new file mode 100644 index 00000000..d1334fa4 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.html @@ -0,0 +1,38 @@ +
+
+
+
+

+

+ +

+ {{ 'LANDINGPAGE.providers.procureSteps.subtitle' | translate }} +

+
+ +
+ @for (step of steps; track step.number) { +
+
+ + +
+ {{ step.number }} +
+ +
+ {{ step.textKey | translate }} +
+
+
+ + @if (step.number < steps.length) {
+
+ } + } +
+
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.ts b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.ts new file mode 100644 index 00000000..44388042 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-procure/landing-providers-procure.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faBagShopping, faHandshake, faMagnifyingGlass, faUser } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +type ProcureStep = { + number: number; + textKey: string; + icon: any; +}; + +@Component({ + selector: "app-landing-page-providers-procure", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-providers-procure.component.html", + styleUrl: "./landing-providers-procure.component.css" +}) +export class LandingPageProvidersProcureComponent { + steps: ProcureStep[] = [ + { + number: 1, + textKey: 'LANDINGPAGE.providers.procureSteps.steps.step1', + icon: faUser + }, + { + number: 2, + textKey: 'LANDINGPAGE.providers.procureSteps.steps.step2', + icon: faMagnifyingGlass + }, + { + number: 3, + textKey: 'LANDINGPAGE.providers.procureSteps.steps.step3', + icon: faBagShopping + }, + { + number: 4, + textKey: 'LANDINGPAGE.providers.procureSteps.steps.step4', + icon: faHandshake + } + ]; +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.css b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.css new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.css @@ -0,0 +1 @@ + diff --git a/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.html b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.html new file mode 100644 index 00000000..fdeba4e1 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.html @@ -0,0 +1,71 @@ +
+
+ +
+
+

+ {{ 'LANDINGPAGE.providers.trust.titleStart' | translate }} + + {{ 'LANDINGPAGE.providers.trust.titleHighlight' | translate }} + +
+ {{ 'LANDINGPAGE.providers.trust.titleLine2' | translate }} +
+ {{ 'LANDINGPAGE.providers.trust.titleLine3' | translate }} +

+ +

+ {{ 'LANDINGPAGE.providers.trust.description' | translate }} +

+
+
+ +
+
+ @for (card of leftCards; track card.titleKey) { +
+
+ +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descriptionKey | translate }} +

+
+
+ } +
+ +
+ @for (card of rightCards; track card.titleKey) { +
+
+ +
+ +
+

+ {{ card.titleKey | translate }} +

+ +

+ {{ card.descriptionKey | translate }} +

+
+
+ } +
+
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.ts b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.ts new file mode 100644 index 00000000..71dcd201 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-trust/landing-providers-trust.component.ts @@ -0,0 +1,47 @@ +import { Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faDatabase, faFileArrowDown, faFlag, faShieldCheck } from '@fortawesome/pro-solid-svg-icons'; +import { TranslateModule } from '@ngx-translate/core'; + +interface TrustCard { + titleKey: string; + descriptionKey: string; + icon: any; + alignEnd?: boolean; +} + +@Component({ + selector: "app-landing-page-providers-trust", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-providers-trust.component.html", + styleUrl: "./landing-providers-trust.component.css" +}) +export class LandingPageProvidersTrustComponent { + leftCards: TrustCard[] = [ + { + titleKey: 'LANDINGPAGE.providers.trust.cards.euBasedProviders.title', + descriptionKey: 'LANDINGPAGE.providers.trust.cards.euBasedProviders.description', + icon: faFlag, + alignEnd: true + }, + { + titleKey: 'LANDINGPAGE.providers.trust.cards.transparency.title', + descriptionKey: 'LANDINGPAGE.providers.trust.cards.transparency.description', + icon: faShieldCheck + } + ]; + + rightCards: TrustCard[] = [ + { + titleKey: 'LANDINGPAGE.providers.trust.cards.trustedSourcing.title', + descriptionKey: 'LANDINGPAGE.providers.trust.cards.trustedSourcing.description', + icon: faFileArrowDown + }, + { + titleKey: 'LANDINGPAGE.providers.trust.cards.dataSovereignty.title', + descriptionKey: 'LANDINGPAGE.providers.trust.cards.dataSovereignty.description', + icon: faDatabase + } + ]; +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.css b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.css new file mode 100644 index 00000000..ddd8a751 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.css @@ -0,0 +1,203 @@ +:host { + display: block; +} + +.why-join-section { + background: linear-gradient(180deg, #0e1e3c 0%, #14274a 50%, #0e1e3c 100%); +} + +.why-join-glow { + position: absolute; + z-index: 0; + border-radius: 999999px; + background: #234481; + opacity: 0.25; + filter: blur(120px); + pointer-events: none; +} + +.why-join-glow--left { + width: 520px; + height: 520px; + left: 0; + top: -40px; +} + +.why-join-glow--right { + width: 440px; + height: 440px; + right: -18px; + top: 35px; +} + +.why-join-header { + min-height: 106px; +} + +.why-join-title { + margin: 0; + color: #ffffff; + font-weight: 700; + font-size: 36px; + line-height: 44px; + letter-spacing: 0; +} + +.why-join-subtitle { + margin: 0; + color: #ffffff; + font-weight: 400; + font-size: 18px; + line-height: 30px; + max-width: 729px; +} + +.why-card { + box-sizing: border-box; + border: 0.5px solid #234481; + background: linear-gradient(180deg, #14274a 0%, #0b1528 100%); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.02), + 0 10px 40px rgba(3, 10, 24, 0.18); +} + +.why-card:nth-child(2) { + background: linear-gradient(175.9deg, #14274a 3.34%, #0b1528 97.37%); +} + +.why-card:nth-child(3) { + background: linear-gradient(161.4deg, #14274a 11.24%, #0b1528 98.7%); +} + +.why-card:nth-child(4) { + background: linear-gradient(180deg, #14274a 0%, #0b1528 100%); +} + +.why-card-line { + position: absolute; + left: 8px; + top: 0; + width: calc(100% - 16px); + height: 2px; + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, #00add3 50%, rgba(0, 0, 0, 0) 100%); + opacity: 0.75; + z-index: 3; +} + +.why-card-blur { + position: absolute; + left: 50%; + top: 28%; + width: 317px; + height: 317px; + transform: translate(-42%, -50%); + background: #2d58a7; + opacity: 0.3; + filter: blur(100px); + border-radius: 999999px; + z-index: 1; + pointer-events: none; +} + +.why-card-title, +.why-card-highlight { + display: block; + font-weight: 700; + font-size: 40px; + line-height: 48px; +} + +.why-card-title { + color: #ffffff; +} + +.why-card-highlight { + color: #00add3; +} + +.why-card-description { + margin: 0; + max-width: 214px; + color: #ffffff; + font-weight: 400; + font-size: 24px; + line-height: 32px; +} + +@media (min-width: 1024px) { + .why-join-title { + font-size: 48px; + line-height: 58px; + } + + .why-join-subtitle { + font-size: 20px; + line-height: 32px; + } +} + +@media (max-width: 1279px) { + .why-card { + height: 320px; + } + + .why-card-title, + .why-card-highlight { + font-size: 34px; + line-height: 40px; + } + + .why-card-description { + max-width: 100%; + font-size: 21px; + line-height: 30px; + } + + .why-card-blur { + width: 260px; + height: 260px; + } +} + +@media (max-width: 767px) { + .why-join-glow--left { + width: 280px; + height: 280px; + top: -30px; + left: -40px; + } + + .why-join-glow--right { + width: 240px; + height: 240px; + top: 40px; + right: -60px; + } + + .why-join-title { + font-size: 32px; + line-height: 40px; + } + + .why-join-subtitle { + font-size: 16px; + line-height: 26px; + } + + .why-card { + height: auto; + min-height: 280px; + } + + .why-card-title, + .why-card-highlight { + font-size: 30px; + line-height: 36px; + } + + .why-card-description { + font-size: 20px; + line-height: 30px; + max-width: 100%; + } +} diff --git a/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.html b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.html new file mode 100644 index 00000000..477a0e55 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.html @@ -0,0 +1,40 @@ +
+ + + +
+
+

+ {{ 'LANDINGPAGE.providers.whyJoinDome.title' | translate }} +

+ +

+ {{ 'LANDINGPAGE.providers.whyJoinDome.subtitle' | translate }} +

+
+ +
+ @for (card of cards; track card.titleKey) { +
+ + + +
+ + {{ card.titleKey | translate }} + + + + {{ card.highlightKey | translate }} + +
+ +

+ {{ card.descriptionKey | translate }} +

+
+ } +
+
+
diff --git a/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.ts b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.ts new file mode 100644 index 00000000..6816bd59 --- /dev/null +++ b/src/app/pages/landing-pages/providers/landing-providers-why/landing-providers-why.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { TranslateModule } from '@ngx-translate/core'; + +interface WhyJoinCard { + titleKey: string; + highlightKey: string; + descriptionKey: string; +} + +@Component({ + selector: "app-landing-page-providers-why", + standalone: true, + imports: [TranslateModule, FontAwesomeModule], + templateUrl: "./landing-providers-why.component.html", + styleUrl: "./landing-providers-why.component.css" +}) +export class LandingPageProvidersWhyComponent { + readonly cards: WhyJoinCard[] = [ + { + titleKey: 'LANDINGPAGE.providers.whyJoinDome.cards.data.title', + highlightKey: 'LANDINGPAGE.providers.whyJoinDome.cards.data.highlight', + descriptionKey: 'LANDINGPAGE.providers.whyJoinDome.cards.data.description' + }, + { + titleKey: 'LANDINGPAGE.providers.whyJoinDome.cards.trust.title', + highlightKey: 'LANDINGPAGE.providers.whyJoinDome.cards.trust.highlight', + descriptionKey: 'LANDINGPAGE.providers.whyJoinDome.cards.trust.description' + }, + { + titleKey: 'LANDINGPAGE.providers.whyJoinDome.cards.easier.title', + highlightKey: 'LANDINGPAGE.providers.whyJoinDome.cards.easier.highlight', + descriptionKey: 'LANDINGPAGE.providers.whyJoinDome.cards.easier.description' + }, + { + titleKey: 'LANDINGPAGE.providers.whyJoinDome.cards.market.title', + highlightKey: 'LANDINGPAGE.providers.whyJoinDome.cards.market.highlight', + descriptionKey: 'LANDINGPAGE.providers.whyJoinDome.cards.market.description' + } + ]; +} diff --git a/src/app/shared/carousel/carousel.component.html b/src/app/shared/carousel/carousel.component.html index dbfdbbbe..434a7a42 100644 --- a/src/app/shared/carousel/carousel.component.html +++ b/src/app/shared/carousel/carousel.component.html @@ -1,26 +1,51 @@ -
+
+ + +
-
+ + + +
+ + + +
+
-
-
+ + +@if (pages > 1) { + +
+ @for (i of [].constructor(pages); track $index) { - + + + } +
+ +} diff --git a/src/app/shared/carousel/carousel.component.ts b/src/app/shared/carousel/carousel.component.ts index 26f55109..e25d8860 100644 --- a/src/app/shared/carousel/carousel.component.ts +++ b/src/app/shared/carousel/carousel.component.ts @@ -1,40 +1,60 @@ -import { Component, Input } from '@angular/core'; +import { + Component, + HostListener, + Input, + OnChanges, + SimpleChanges +} from '@angular/core'; + import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { faChevronLeft, faChevronRight } from '@fortawesome/pro-solid-svg-icons'; +import { + faChevronLeft, + faChevronRight +} from '@fortawesome/pro-solid-svg-icons'; /** - * Generic carousel component. + * Generic reusable horizontal carousel. + * + * Core responsibilities: + * + * - Handles horizontal scrolling logic. + * - Calculates navigation limits. + * - Applies translateX transform to the track. + * - Renders navigation arrows. + * - Renders pagination dots. + * + * This component DOES NOT render slide content directly. + * Instead, it uses Angular content projection (`ng-content`). + * + * This allows the parent component to fully control: * - * This component provides the structural and behavioral logic for a horizontal carousel. - * It does NOT define the content of the slides. Instead, the slide content is provided - * by the parent component using Angular content projection (`ng-content`). + * - Slide layout + * - Slide styling + * - Slide structure * - * The carousel works by: - * 1. Rendering a horizontal flex container (the "track"). - * 2. Moving the track using `translateX` when the index changes. - * 3. Showing a fixed number of visible items (`visible`). - * 4. Allowing navigation through arrows or dots. + * while the carousel manages: * - * The parent component is responsible for: - * - Passing the `items` array (used only to calculate the carousel bounds). - * - Rendering each slide via `@for` inside the `` tag. - * - Setting the width of each slide (usually `100 / visible`). + * - scrolling + * - navigation + * - pagination * - * Example usage: + * Typical usage: * - * + * + * + * @for (card of cards) { + *
+ * + * * - * @for (product of products; track product.id) { - *
- * *
* } * * - * - * Important: - * The carousel itself does not know anything about the structure of the items. - * It only controls scrolling and pagination. */ @Component({ @@ -43,93 +63,252 @@ import { faChevronLeft, faChevronRight } from '@fortawesome/pro-solid-svg-icons' templateUrl: './carousel.component.html', imports: [FontAwesomeModule] }) -export class CarouselComponent { +export class CarouselComponent implements OnChanges { + /** - * Array of items rendered inside the carousel. + * Items array. + * + * IMPORTANT: + * The carousel does NOT render these items. * - * The carousel does not directly render these items. - * The array is used only to calculate: - * - how many slides exist - * - the maximum scroll index - * - the number of pagination dots + * The array is used only to: + * + * - calculate total number of slides + * - determine navigation bounds + * - compute pagination dots */ - @Input({ required: true }) items!: T[]; + @Input({ required: true }) + items!: T[]; /** - * Number of elements visible at the same time. + * Number of visible slides at once. * * Example: - * visible = 3 → three cards visible in the viewport + * + * visible = 3 + * + * viewport shows: + * + * [0] [1] [2] + * + * Then scroll moves: + * + * [1] [2] [3] + */ + @Input({ required: true }) + visible = 3; + + /** + * Arrow visual theme. + * + * light: + * - white background + * - dark icon + * + * dark: + * - transparent background + * - white border + icon + */ + @Input() + arrowTheme: 'light' | 'dark' = 'light'; + + /** + * Pagination dots theme. + * + * light: + * default dashboard style + * + * accent: + * landing accent color (#00ADD3) + */ + @Input() + dotsTheme: 'light' | 'accent' = 'light'; + + /** + * Enables horizontal padding around the carousel. + * + * Useful when arrows should sit + * outside content boundaries. */ - @Input({ required: true }) visible: number; + @Input() + sidePadding = true; /** - * Current scroll index. + * Current visible index. + * + * Represents the FIRST visible item. * - * This represents the first visible element in the viewport. * Example: - * index = 0 → show items 0,1,2 - * index = 1 → show items 1,2,3 + * + * index = 0 + * visible = 3 + * + * visible items: + * 0,1,2 */ index = 0; + /** + * Navigation icons. + */ faChevronRight = faChevronRight; - faChevronLeft = faChevronLeft + faChevronLeft = faChevronLeft; /** - * Maximum scroll position. + * Maximum allowed scroll index. + * + * Prevents overflow scrolling. * * Example: - * items = 10 - * visible = 3 * - * maxIndex = 7 + * items = 5 + * visible = 3 * - * This prevents the carousel from scrolling past the last element. + * maxIndex = 2 */ get maxIndex(): number { return Math.max(0, this.items.length - this.visible); } /** - * Number of pagination dots. + * Total number of pagination pages. * - * Each dot represents a possible starting position. + * Each page corresponds to a possible index. */ get pages(): number { return this.maxIndex + 1; } /** - * CSS transform applied to the carousel track. + * CSS transform applied to the track. * - * The track is moved horizontally using translateX. - * The movement step corresponds to the width of a single item. + * Moves content horizontally. + * + * Movement step: + * + * 100 / visible + * + * Example: + * + * visible = 3 + * index = 1 + * + * translateX(-33.33%) */ get trackTransform(): string { return `translateX(-${this.index * (100 / this.visible)}%)`; } /** - * Move carousel forward by one element. + * Wrapper dynamic class. + * + * Controls outer horizontal padding. + */ + get wrapperClass(): string { + return this.sidePadding + ? 'relative px-0 sm:px-4 md:px-12 lg:px-16 xl:px-20' + : 'relative'; + } + + /** + * Left arrow style selector. + * + * Changes based on theme. + */ + get leftButtonClass(): string { + return this.arrowTheme === 'dark' + ? 'absolute left-2 top-1/2 z-10 -translate-y-1/2 flex h-10 w-10 items-center justify-center rounded-full border border-white/90 bg-transparent text-white transition hover:bg-white/10 disabled:opacity-40' + : 'absolute left-2 top-1/2 z-10 -translate-y-1/2 flex h-10 w-10 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-900 shadow-md transition disabled:opacity-40'; + } + + /** + * Right arrow style selector. + */ + get rightButtonClass(): string { + return this.arrowTheme === 'dark' + ? 'absolute right-2 top-1/2 z-10 -translate-y-1/2 flex h-10 w-10 items-center justify-center rounded-full border border-white/90 bg-transparent text-white transition hover:bg-white/10 disabled:opacity-40' + : 'absolute right-2 top-1/2 z-10 -translate-y-1/2 flex h-10 w-10 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-900 shadow-md transition disabled:opacity-40'; + } + + /** + * Returns correct dot color class. + * + * Depends on: + * + * - active state + * - theme + */ + dotClass(active: boolean): string { + + if (this.dotsTheme === 'accent') { + return active + ? 'bg-[#00ADD3]' + : 'bg-[#D1F7FF]'; + } + + return active + ? 'bg-blue-700' + : 'bg-slate-300'; + } + + /** + * Move forward by one step. */ - next() { - this.index = Math.min(this.index + 1, this.maxIndex); + next(): void { + this.index = Math.min( + this.index + 1, + this.maxIndex + ); } /** - * Move carousel backward by one element. + * Move backward by one step. */ - prev() { - this.index = Math.max(this.index - 1, 0); + prev(): void { + this.index = Math.max( + this.index - 1, + 0 + ); } /** - * Jump directly to a specific index. + * Jump to specific index. + * * Used by pagination dots. */ - goTo(i: number) { - this.index = Math.max(0, Math.min(i, this.maxIndex)); + goTo(i: number): void { + this.index = Math.max( + 0, + Math.min(i, this.maxIndex) + ); } + /** + * Ensures index never exceeds bounds + * when inputs change. + */ + ngOnChanges( + changes: SimpleChanges + ): void { + + this.index = Math.min( + this.index, + this.maxIndex + ); + } + + /** + * Re-validates index on window resize. + * + * Necessary when `visible` + * changes responsively. + */ + @HostListener('window:resize') + onResize(): void { + + this.index = Math.min( + this.index, + this.maxIndex + ); + } } diff --git a/src/app/shared/footer/footer.component.html b/src/app/shared/footer/footer.component.html index bbbe5ce6..75f9254b 100644 --- a/src/app/shared/footer/footer.component.html +++ b/src/app/shared/footer/footer.component.html @@ -1,5 +1,5 @@ @if (isDomeTheme) { -
diff --git a/src/app/shared/header/header.component.css b/src/app/shared/header/header.component.css index d73020ce..b31a3d8d 100644 --- a/src/app/shared/header/header.component.css +++ b/src/app/shared/header/header.component.css @@ -13,13 +13,10 @@ display: flex; align-items: center; gap: 0.5rem; - padding: 10px 12px; border-radius: 10px; - font-size: 14px; font-weight: 600; - color: #0f172a; text-decoration: none; background: transparent; @@ -32,7 +29,9 @@ } .mobile-nav-item { - display: block; + width: 100%; + display: flex; + align-items: center; padding: 12px 12px; border-radius: 12px; font-size: 15px; @@ -40,6 +39,9 @@ color: rgba(255, 255, 255, 0.92); cursor: pointer; text-decoration: none; + background: transparent; + border: 0; + text-align: left; } .mobile-nav-item:hover { @@ -49,17 +51,13 @@ .header-glass { background: var(--theme-header-v2-glass-bg, rgba(7, 18, 40, 0.55)); - backdrop-filter: blur(14px) saturate(140%); -webkit-backdrop-filter: blur(14px) saturate(140%); - background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02)); - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25); } @@ -86,3 +84,76 @@ .header-solid-btn:hover { background-color: var(--theme-header-v2-solid-hover-bg, rgba(47, 111, 214, 0.9)); } + +.mobile-action-btn { + display: flex; + align-items: center; + justify-content: center; + min-height: 44px; + width: 100%; + padding: 0 16px; + border-radius: 10px; + font-size: 15px; + font-weight: 600; + transition: all 0.2s ease; +} + +.mobile-action-btn--solid { + background-color: var(--theme-header-v2-solid-bg, #2D58A7); + color: #fff; + border: 0; +} + +.mobile-action-btn--solid:hover { + background-color: var(--theme-header-v2-solid-hover-bg, rgba(47, 111, 214, 0.9)); +} + +.mobile-action-btn--outline { + background: transparent; + color: #fff; + border: 2px solid var(--theme-header-v2-outline-border, #2D58A7); +} + +.mobile-action-btn--outline:hover { + background-color: var(--theme-header-v2-outline-hover-bg, rgba(47, 111, 214, 0.9)); + color: var(--theme-header-v2-outline-hover-text, #ffffff); +} + +.mobile-user-box { + display: flex; + align-items: center; + gap: 12px; + padding: 12px; + margin-bottom: 4px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.08); +} + +.mobile-user-box__avatar { + display: inline-flex; + align-items: center; + justify-content: center; + width: 42px; + height: 42px; + border-radius: 9999px; + background: rgba(255, 255, 255, 0.15); + color: #fff; + font-size: 14px; + font-weight: 700; + flex: 0 0 auto; +} + +.mobile-user-box__name { + font-size: 14px; + font-weight: 700; + color: #fff; + line-height: 1.2; +} + +.mobile-user-box__email { + margin-top: 2px; + font-size: 12px; + color: rgba(255, 255, 255, 0.72); + line-height: 1.2; + word-break: break-all; +} diff --git a/src/app/shared/header/header.component.html b/src/app/shared/header/header.component.html index 4ded35c2..ff477fc0 100644 --- a/src/app/shared/header/header.component.html +++ b/src/app/shared/header/header.component.html @@ -1,5 +1,5 @@ -