diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..5321e775
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,78 @@
+{
+ "editor.defaultFormatter": "vscode.typescript-language-features",
+ "editor.formatOnSave": true,
+ "editor.formatOnPaste": false,
+ "editor.formatOnType": false,
+ "[typescript]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features",
+ "editor.formatOnSave": true
+ },
+ "[typescriptreact]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features"
+ },
+ "[javascript]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features"
+ },
+ "[javascriptreact]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features"
+ },
+ "[json]": {
+ "editor.defaultFormatter": "vscode.json-language-features",
+ "editor.formatOnSave": true
+ },
+ "[jsonc]": {
+ "editor.defaultFormatter": "vscode.json-language-features",
+ "editor.formatOnSave": true
+ },
+ "[html]": {
+ "editor.defaultFormatter": "vscode.html-language-features",
+ "editor.formatOnSave": true
+ },
+ "[css]": {
+ "editor.defaultFormatter": "vscode.css-language-features",
+ "editor.formatOnSave": true
+ },
+ "[scss]": {
+ "editor.defaultFormatter": "vscode.css-language-features",
+ "editor.formatOnSave": true
+ },
+ "editor.codeActionsOnSave": {
+ "source.organizeImports": "explicit"
+ },
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.validate.enable": true,
+ "typescript.updateImportsOnFileMove.enabled": "always",
+ "typescript.preferences.importModuleSpecifier": "relative",
+ "typescript.preferences.importModuleSpecifierEnding": "auto",
+ "typescript.preferences.quoteStyle": "single",
+ "typescript.suggest.autoImports": true,
+ "typescript.suggest.completeFunctionCalls": true,
+ "editor.inlineSuggest.enabled": true,
+ "editor.parameterHints.enabled": true,
+ "editor.suggestSelection": "first",
+ "editor.tabCompletion": "on",
+ "angular.enable-strict-mode-prompt": false,
+ "angular.trace.server": "off",
+ "editor.tabSize": 2,
+ "editor.insertSpaces": true,
+ "editor.detectIndentation": false,
+ "files.eol": "\n",
+ "files.trimTrailingWhitespace": true,
+ "files.insertFinalNewline": true,
+ "editor.wordWrap": "on",
+ "editor.minimap.enabled": false,
+ "editor.renderWhitespace": "selection",
+ "editor.bracketPairColorization.enabled": true,
+ "editor.guides.bracketPairs": true,
+ "files.exclude": {
+ "**/.angular/**": true,
+ "**/.cache/**": true,
+ "**/dist/**": true,
+ "**/coverage/**": true,
+ "**/.DS_Store": true
+ },
+ "git.autofetch": true,
+ "git.confirmSync": false,
+ "explorer.compactFolders": false,
+ "workbench.startupEditor": "none"
+}
diff --git a/cypress/e2e/dashboard.cy.ts b/cypress/e2e/dashboard.cy.ts
index 933e66be..192d61b3 100644
--- a/cypress/e2e/dashboard.cy.ts
+++ b/cypress/e2e/dashboard.cy.ts
@@ -13,18 +13,21 @@ describe('/dashboard',{
it('should have all required elements in dashboard', ()=>{
checkHeaderPreLogin()
- cy.getBySel('browseServices').should('not.be.disabled')
+ cy.getBySel('browseServicesDashboard').should('not.be.disabled')
cy.getBySel('mainText').should('exist')
cy.getBySel('publishOff').should('exist')
cy.getBySel('publishOff').should('have.attr', 'href', init_config.domeRegister)
cy.getBySel('vServices').should('exist')
- cy.getBySel('vServices').should('have.text', '1 verified services')
+ cy.getBySel('vServices').invoke('text').then((text) => {
+ expect(text.trim()).to.eq('1 verified services')
+ })
cy.getBySel('rPublishers').should('exist')
- cy.getBySel('rPublishers').should('have.text', '1 registered providers')
+ cy.getBySel('rPublishers').invoke('text').then((text) => {
+ expect(text.trim()).to.eq('1 registered providers')
+ })
cy.getBySel('nameServices').should('have.length', init_stat.services.length)
cy.getBySel('nameOrgs').should('have.length', init_stat.organizations.length)
})
})
-
diff --git a/cypress/support/constants.ts b/cypress/support/constants.ts
index 275e0895..80030f2e 100644
--- a/cypress/support/constants.ts
+++ b/cypress/support/constants.ts
@@ -237,18 +237,20 @@ export const checkHeaderPreLogin = () => {
if ($body.find('[data-cy=publishOffering]').length > 0) cy.getBySel('publishOffering').should('exist')
if ($body.find('[data-cy=browse]').length > 0) cy.getBySel('browse').should('exist')
if ($body.find('[data-cy=about]').length > 0) cy.getBySel('about').should('exist')
+ if ($body.find('[data-cy=knowledge]').length > 0) {
+ cy.getBySel('knowledge').should('exist')
+ cy.getBySel('knowledge').should('have.attr', 'href', init_config.knowledgeBaseUrl)
+ }
+ if ($body.find('[data-cy=darkMode]').length > 0) {
+ cy.getBySel('darkMode').should('exist')
+ cy.getBySel('darkMode').click()
+ cy.getBySel('moonSVG').should('be.hidden')
+ cy.getBySel('sunSVG').should('not.be.hidden')
+ cy.getBySel('darkMode').click()
+ cy.getBySel('sunSVG').should('be.hidden')
+ cy.getBySel('moonSVG').should('not.be.hidden')
+ }
})
- cy.getBySel('knowledge').should('exist')
- cy.getBySel('darkMode').should('exist')
-
- cy.getBySel('darkMode').click()
- cy.getBySel('moonSVG').should('be.hidden')
- cy.getBySel('sunSVG').should('not.be.hidden')
- cy.getBySel('darkMode').click()
- cy.getBySel('sunSVG').should('be.hidden')
- cy.getBySel('moonSVG').should('not.be.hidden')
-
- cy.getBySel('knowledge').should('have.attr', 'href', init_config.knowledgeBaseUrl)
};
export const checkHeaderPostLogin = () => {
@@ -259,18 +261,20 @@ export const checkHeaderPostLogin = () => {
if ($body.find('[data-cy=publishOffering]').length > 0) cy.getBySel('publishOffering').should('exist')
if ($body.find('[data-cy=browse]').length > 0) cy.getBySel('browse').should('exist')
if ($body.find('[data-cy=about]').length > 0) cy.getBySel('about').should('exist')
+ if ($body.find('[data-cy=knowledge]').length > 0) {
+ cy.getBySel('knowledge').should('exist')
+ cy.getBySel('knowledge').should('have.attr', 'href', init_config.knowledgeBaseUrl)
+ }
+ if ($body.find('[data-cy=darkMode]').length > 0) {
+ cy.getBySel('darkMode').should('exist')
+ cy.getBySel('darkMode').click()
+ cy.getBySel('moonSVG').should('be.hidden')
+ cy.getBySel('sunSVG').should('not.be.hidden')
+ cy.getBySel('darkMode').click()
+ cy.getBySel('sunSVG').should('be.hidden')
+ cy.getBySel('moonSVG').should('not.be.hidden')
+ }
})
- cy.getBySel('knowledge').should('exist')
- cy.getBySel('darkMode').should('exist')
-
- cy.getBySel('darkMode').click()
- cy.getBySel('moonSVG').should('be.hidden')
- cy.getBySel('sunSVG').should('not.be.hidden')
- cy.getBySel('darkMode').click()
- cy.getBySel('sunSVG').should('be.hidden')
- cy.getBySel('moonSVG').should('not.be.hidden')
-
- cy.getBySel('knowledge').should('have.attr', 'href', init_config.knowledgeBaseUrl)
};
diff --git a/src/app/app.component.css b/src/app/app.component.css
index e69de29b..75243035 100644
--- a/src/app/app.component.css
+++ b/src/app/app.component.css
@@ -0,0 +1,10 @@
+.app-content {
+ min-height: calc(100vh - 88px);
+ min-height: calc(100dvh - 88px);
+ display: flex;
+ flex-direction: column;
+}
+
+.app-content > main {
+ flex: 1 0 auto;
+}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 16a1a252..0ad9b233 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,17 +1,22 @@
-
+
-
-
-
-@if (providerThemeName == "DOME") {
-
-}
+
+
+
+
+
+
+
-
+@if (providerThemeName === "DOME") {
+
+}
@if(isProduction){
-
-}
\ No newline at end of file
+
+
+
+}
diff --git a/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.css b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.css
new file mode 100644
index 00000000..e82a9da3
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.css
@@ -0,0 +1,215 @@
+.dc-wrap {
+ position: relative;
+ width: 100%;
+ isolation: isolate;
+}
+
+.dc-bg {
+ position: absolute;
+ inset: 0;
+ z-index: 0;
+ overflow: hidden;
+ pointer-events: none;
+ background: #f3f6ff;
+}
+
+.dc-content {
+ position: relative;
+ z-index: 1;
+}
+
+.dc-ellipse {
+ position: absolute;
+ width: 720px;
+ height: 720px;
+ border-radius: 9999px;
+ transform: rotate(180deg);
+ opacity: 1;
+ background: radial-gradient(circle at 35% 35%,
+ rgba(182, 202, 236, 0.95) 0%,
+ rgba(182, 202, 236, 0.65) 38%,
+ rgba(182, 202, 236, 0) 72%);
+ filter: blur(10px);
+}
+
+.dc-e1 {
+ left: -220px;
+ top: -190px;
+}
+
+.dc-e2 {
+ right: -260px;
+ top: 60px;
+}
+
+.dc-e3 {
+ left: 50%;
+ top: -240px;
+ transform: translateX(-50%) rotate(180deg);
+}
+
+.dc-e4 {
+ left: 140px;
+ bottom: -360px;
+}
+
+.dc-blur {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(226.59deg,
+ rgba(255, 242, 242, 0.18) 25.7%,
+ rgba(255, 250, 250, 0.28) 94.73%);
+ backdrop-filter: blur(90px);
+ -webkit-backdrop-filter: blur(90px);
+ transform: rotate(180deg);
+}
+
+.dc-feature-card {
+ position: relative;
+ min-height: 180px;
+ border-radius: 12px;
+ overflow: hidden;
+ background: rgba(255, 255, 255, 0.95);
+ box-shadow: 0 10px 30px rgba(13, 33, 74, 0.1);
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ transition: transform 220ms ease, box-shadow 220ms ease;
+}
+
+.dc-feature-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 16px 38px rgba(13, 33, 74, 0.14);
+}
+
+.dc-feature-card__base {
+ position: relative;
+ z-index: 1;
+ height: 100%;
+ min-height: 180px;
+ transition: opacity 180ms ease, transform 220ms ease;
+}
+
+.dc-feature-card__content {
+ height: 100%;
+ display: flex;
+ align-items: flex-end;
+ padding: 1.5rem;
+}
+
+.dc-feature-card__icon {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ font-size: 72px;
+ color: #1f4fbf;
+ opacity: 0.1;
+ transition: opacity 220ms ease, transform 220ms ease;
+}
+
+.dc-feature-card__hover {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ padding: 2rem 1.9rem 1.8rem;
+ background: rgba(226, 233, 245, 0.9);
+ opacity: 0;
+ transform: translateY(8px);
+ transition: opacity 220ms ease, transform 220ms ease;
+ pointer-events: none;
+}
+
+.dc-feature-card__hover-text {
+ position: relative;
+ z-index: 2;
+ max-width: 250px;
+ font-size: 16px;
+ line-height: 1.55;
+ font-weight: 500;
+ color: #1f2937;
+}
+
+.dc-feature-card__hover-icon {
+ position: absolute;
+ right: -6px;
+ bottom: -10px;
+ font-size: 122px;
+ color: #1f4fbf;
+ opacity: 0.1;
+ z-index: 1;
+ transition: transform 220ms ease, opacity 220ms ease;
+}
+
+.dc-feature-card:hover .dc-feature-card__base {
+ opacity: 0;
+ transform: scale(0.98);
+}
+
+.dc-feature-card:hover .dc-feature-card__icon {
+ opacity: 0;
+ transform: scale(0.9);
+}
+
+.dc-feature-card:hover .dc-feature-card__hover {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.dc-feature-card:hover .dc-feature-card__hover-icon {
+ opacity: 0.12;
+ transform: scale(1.03);
+}
+
+@media (max-width: 1024px) {
+ .dc-ellipse {
+ width: 620px;
+ height: 620px;
+ filter: blur(9px);
+ }
+
+ .dc-e2 {
+ right: -300px;
+ }
+}
+
+@media (max-width: 640px) {
+ .dc-ellipse {
+ width: 520px;
+ height: 520px;
+ filter: blur(8px);
+ }
+
+ .dc-e1 {
+ left: -280px;
+ top: -230px;
+ }
+
+ .dc-e2 {
+ right: -320px;
+ top: 10px;
+ }
+
+ .dc-e4 {
+ left: 40px;
+ bottom: -380px;
+ }
+
+ .dc-feature-card {
+ min-height: 160px;
+ }
+
+ .dc-feature-card__base {
+ min-height: 160px;
+ }
+
+ .dc-feature-card__hover {
+ padding: 1.5rem;
+ }
+
+ .dc-feature-card__hover-text {
+ font-size: 16px;
+ line-height: 1.65;
+ }
+
+ .dc-feature-card__hover-icon {
+ font-size: 104px;
+ }
+}
diff --git a/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.html b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.html
new file mode 100644
index 00000000..c0b172a7
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if (featureCards.length) {
+
+ @for (card of featureCards; track $index) {
+
+
+
+
+
+ {{ card.hoverText | translate }}
+
+
+
+
+
+ }
+
+ }
+
+
+
+
+
+
+ @if (steps.length) {
+
+ @for (step of steps; track $index) {
+
+
+
+
+
+
+ {{ step.desc | translate }}
+
+
+
+ }
+
+ }
+
+
+
+
+
+
+
diff --git a/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.ts b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.ts
new file mode 100644
index 00000000..274057d2
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-customers/dashboard-customers.component.ts
@@ -0,0 +1,61 @@
+import { Component, input } from "@angular/core";
+import { RouterLink } from '@angular/router';
+import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
+import { faCircleCheck, faEye } from "@fortawesome/free-regular-svg-icons";
+import { faBoltLightning, faDiagramProject } from "@fortawesome/free-solid-svg-icons";
+import { TranslateModule } from '@ngx-translate/core';
+
+type FeatureCard = { html: string; hoverText: string; icon: any };
+type Step = { num: string; title: string; desc: string };
+
+@Component({
+ selector: "app-dashboard-customers",
+ standalone: true,
+ imports: [FontAwesomeModule, TranslateModule, RouterLink],
+ templateUrl: "./dashboard-customers.component.html",
+ styleUrl: "./dashboard-customers.component.css"
+})
+export class DashboardCustomersComponent {
+ customerLink = input.required();
+
+ featureCards: FeatureCard[] = [
+ {
+ html: 'DASHBOARD.customers._cards.access.title',
+ hoverText: 'DASHBOARD.customers._cards.access.desc',
+ icon: faCircleCheck
+ },
+ {
+ html: 'DASHBOARD.customers._cards.discovery.title',
+ hoverText: 'DASHBOARD.customers._cards.discovery.desc',
+ icon: faEye
+ },
+ {
+ html: 'DASHBOARD.customers._cards.procurement.title',
+ hoverText: 'DASHBOARD.customers._cards.procurement.desc',
+ icon: faBoltLightning
+ },
+ {
+ html: 'DASHBOARD.customers._cards.ecosystem.title',
+ hoverText: 'DASHBOARD.customers._cards.ecosystem.desc',
+ icon: faDiagramProject
+ }
+ ];
+
+ steps: Step[] = [
+ {
+ num: '01',
+ title: 'DASHBOARD.customers._steps.register.title',
+ desc: 'DASHBOARD.customers._steps.register.desc'
+ },
+ {
+ num: '02',
+ title: 'DASHBOARD.customers._steps.search.title',
+ desc: 'DASHBOARD.customers._steps.search.desc'
+ },
+ {
+ num: '03',
+ title: 'DASHBOARD.customers._steps.connect.title',
+ desc: 'DASHBOARD.customers._steps.connect.desc'
+ }
+ ];
+}
diff --git a/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.css b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.css
new file mode 100644
index 00000000..1eb4facf
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.css
@@ -0,0 +1,101 @@
+.hero-shell {
+ background: #070f24;
+ font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans";
+}
+
+.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%);
+}
+
+.hero-title {
+ font-weight: 800;
+ letter-spacing: -0.02em;
+ line-height: 1.05;
+ font-size: clamp(40px, 4.2vw, 64px);
+}
+
+.hero-accent {
+ color: #23b9d8;
+}
+
+.hero-sub {
+ color: rgba(255, 255, 255, 0.55);
+ font-size: 16px;
+ line-height: 1.7;
+}
+
+.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;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 260px;
+}
+
+.hero-btn:active {
+ transform: translateY(1px);
+}
+
+.hero-btn--primary {
+ background: #2D58A7;
+ color: #fff;
+ box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
+}
+
+.hero-btn--primary:hover {
+ background: #00ADD3;
+ box-shadow: 0 22px 55px rgba(0, 0, 0, 0.32);
+}
+
+.hero-btn--ghost {
+ 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);
+}
+
+.hero-btn--ghost:hover {
+ border-color: #2D58A7;
+ color: #2D58A7;
+ background: white;
+}
+
+.logo-ph {
+ height: 32px;
+ 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;
+}
+
+.earth-wrapper {
+ position: absolute;
+ bottom: -2%;
+ left: 50%;
+ transform: translateX(-50%);
+ width: min(1600px, 140vw);
+ pointer-events: none;
+ opacity: 0.95;
+}
+
+.earth-wrapper img {
+ width: 100%;
+ height: auto;
+ display: block;
+ filter: drop-shadow(0 0 40px rgba(120, 220, 255, 0.35));
+}
diff --git a/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.html b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.html
new file mode 100644
index 00000000..547df90a
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.html
@@ -0,0 +1,94 @@
+
+
+
+
+
+ {{ 'DASHBOARD.ecosystem._subtitle' | translate }}
+
+
+
+
+
+ {{ 'DASHBOARD.ecosystem._nowLabel' | translate }}
+
+
+ {{ 'DASHBOARD.ecosystem._nextLabel' | translate }}
+
+
+ {{ 'DASHBOARD.ecosystem._beyondLabel' | translate }}
+
+
+
+
+
+ @if (milestones.length) {
+
+ @for (milestone of milestones; track $index) {
+
+
+
+
+ {{ milestone.desc | translate }}
+
+
+ }
+
+ }
+
+
+
+
+
diff --git a/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.ts b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.ts
new file mode 100644
index 00000000..694ab41a
--- /dev/null
+++ b/src/app/pages/dashboard/dashboard-ecosystem/dashboard-ecosystem.component.ts
@@ -0,0 +1,38 @@
+import { Component, input } from "@angular/core";
+import { TranslateModule } from '@ngx-translate/core';
+
+type Milestone = {
+ title: string;
+ desc: string;
+ active: boolean;
+};
+
+@Component({
+ selector: "app-dashboard-ecosystem",
+ standalone: true,
+ templateUrl: "./dashboard-ecosystem.component.html",
+ imports: [TranslateModule]
+})
+export class DashboardEcosystemComponent {
+
+ providersLink = input.required();
+ customersLink = input.required();
+
+ milestones: Milestone[] = [
+ {
+ title: "DASHBOARD.ecosystem._milestones._live._title",
+ desc: "DASHBOARD.ecosystem._milestones._live._desc",
+ active: true,
+ },
+ {
+ title: "DASHBOARD.ecosystem._milestones._tools._title",
+ desc: "DASHBOARD.ecosystem._milestones._tools._desc",
+ active: false,
+ },
+ {
+ title: "DASHBOARD.ecosystem._milestones._federation._title",
+ desc: "DASHBOARD.ecosystem._milestones._federation._desc",
+ active: false,
+ },
+ ];
+}
diff --git a/src/app/pages/dashboard/dashboard-footer/dashboard-footer.component.html b/src/app/pages/dashboard/dashboard-footer/dashboard-footer.component.html
index 3bc12bfa..c4d0afa3 100644
--- a/src/app/pages/dashboard/dashboard-footer/dashboard-footer.component.html
+++ b/src/app/pages/dashboard/dashboard-footer/dashboard-footer.component.html
@@ -1,59 +1,52 @@
-