diff --git a/apps/model-ad/app/project.json b/apps/model-ad/app/project.json
index cc621d386e..27c8a2e038 100644
--- a/apps/model-ad/app/project.json
+++ b/apps/model-ad/app/project.json
@@ -7,44 +7,60 @@
"tags": [],
"targets": {
"build": {
- "executor": "@angular-devkit/build-angular:application",
- "outputs": ["{options.outputPath}"],
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": [
+ "{options.outputPath}"
+ ],
"options": {
- "outputPath": "dist/apps/model-ad/app",
+ "outputPath": "dist/apps/model-ad/app/browser/browser",
"index": "apps/model-ad/app/src/index.html",
- "browser": "apps/model-ad/app/src/main.ts",
- "polyfills": ["zone.js"],
+ "main": "apps/model-ad/app/src/main.ts",
+ "polyfills": [
+ "zone.js"
+ ],
"tsConfig": "apps/model-ad/app/tsconfig.app.json",
"inlineStyleLanguage": "scss",
- "assets": ["apps/model-ad/app/src/favicon.ico", "apps/model-ad/app/src/assets"],
- "styles": ["apps/model-ad/app/src/styles.scss"],
- "scripts": [],
- "server": "apps/model-ad/app/src/main.server.ts",
- "prerender": true,
- "ssr": {
- "entry": "apps/model-ad/app/server.ts"
- }
+ "assets": [
+ "apps/model-ad/app/src/assets",
+ "apps/model-ad/app/src/humans.txt",
+ "apps/model-ad/app/src/robots.txt",
+ {
+ "input": "libs/shared/typescript/assets/src/assets",
+ "glob": "**/*",
+ "output": "assets"
+ }
+ ],
+ "styles": [
+ "apps/model-ad/app/src/styles.scss",
+ "node_modules/primeicons/primeicons.css",
+ "node_modules/primeng/resources/themes/lara-light-blue/theme.css",
+ "node_modules/primeng/resources/primeng.min.css"
+ ],
+ "scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
- "maximumWarning": "500kb",
- "maximumError": "1mb"
+ "maximumWarning": "1mb",
+ "maximumError": "2mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
- "maximumError": "4kb"
+ "maximumError": "10kb"
}
],
"outputHashing": "all"
},
"development": {
+ "buildOptimizer": false,
"optimization": false,
+ "vendorChunk": true,
"extractLicenses": false,
- "sourceMap": true
+ "sourceMap": true,
+ "namedChunks": true
}
},
"defaultConfiguration": "production"
@@ -72,7 +88,9 @@
},
"test": {
"executor": "@nx/jest:jest",
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+ "outputs": [
+ "{workspaceRoot}/coverage/{projectRoot}"
+ ],
"options": {
"jestConfig": "apps/model-ad/app/jest.config.ts"
}
@@ -84,5 +102,10 @@
"staticFilePath": "dist/apps/model-ad/app/browser"
}
}
- }
-}
+ },
+ "implicitDependencies": [
+ "model-ad-styles",
+ "model-ad-themes",
+ "shared-typescript-assets"
+ ]
+}
\ No newline at end of file
diff --git a/apps/model-ad/app/src/_app-theme.scss b/apps/model-ad/app/src/_app-theme.scss
new file mode 100644
index 0000000000..5b717506d8
--- /dev/null
+++ b/apps/model-ad/app/src/_app-theme.scss
@@ -0,0 +1,48 @@
+@use 'sass:map';
+@use '@angular/material' as mat;
+@use 'libs/model-ad/themes/src/fonts' as fonts;
+@use 'libs/model-ad/themes/src/palettes' as palettes;
+@use 'libs/model-ad/themes/src/index' as model-ad;
+
+@include mat.typography-hierarchy(fonts.$lato);
+@include mat.core();
+
+$primary: mat.define-palette(palettes.$dark-blue-palette, 600);
+$accent: mat.define-palette(palettes.$accent-purple-palette, 400);
+
+$theme: mat.define-light-theme(
+ (
+ color: (
+ primary: $primary,
+ accent: $accent,
+ ),
+ typography: fonts.$lato,
+ density: 0,
+ is-dark: false,
+ )
+);
+
+// Add custom palettes used in figma to the theme
+$theme: map.deep-merge(
+ $theme,
+ (
+ color: (
+ figma: palettes.$figma-collection,
+ ),
+ )
+);
+
+// Emit theme-dependent styles for common features used across multiple components.
+@include mat.core-theme($theme);
+
+// Emit styles for MatButton based on `$theme`.
+@include mat.button-theme($theme);
+
+// Include the theme mixins for other components you use here.
+@include model-ad.theme($theme);
+
+:root {
+ --color-btn-primary: #39bde7;
+ --color-btn-disabled: #ebebe4;
+ --color-btn-shadow: rgba(196, 196, 196, 1);
+}
diff --git a/apps/model-ad/app/src/app/app.component.html b/apps/model-ad/app/src/app/app.component.html
index 0f4018b6d7..db2579811d 100644
--- a/apps/model-ad/app/src/app/app.component.html
+++ b/apps/model-ad/app/src/app/app.component.html
@@ -1 +1,8 @@
+
diff --git a/apps/model-ad/app/src/app/app.component.ts b/apps/model-ad/app/src/app/app.component.ts
index e5bfabd849..342ee3f7ce 100644
--- a/apps/model-ad/app/src/app/app.component.ts
+++ b/apps/model-ad/app/src/app/app.component.ts
@@ -1,10 +1,11 @@
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { NxWelcomeComponent } from './nx-welcome.component';
+import { FooterComponent } from '@sagebionetworks/model-ad/ui';
@Component({
standalone: true,
- imports: [NxWelcomeComponent, RouterModule],
+ imports: [NxWelcomeComponent, RouterModule, FooterComponent],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
diff --git a/apps/model-ad/app/src/humans.txt b/apps/model-ad/app/src/humans.txt
new file mode 100644
index 0000000000..9093f0f578
--- /dev/null
+++ b/apps/model-ad/app/src/humans.txt
@@ -0,0 +1,6 @@
+/* TEAM */
+
+/* THANKS */
+
+/* SITE */
+Last update: 2024/05/29
diff --git a/apps/model-ad/app/src/robots.txt b/apps/model-ad/app/src/robots.txt
new file mode 100644
index 0000000000..4f9540ba35
--- /dev/null
+++ b/apps/model-ad/app/src/robots.txt
@@ -0,0 +1 @@
+User-agent: *
\ No newline at end of file
diff --git a/apps/model-ad/app/src/styles.scss b/apps/model-ad/app/src/styles.scss
index 90d4ee0072..8ddd28cc9e 100644
--- a/apps/model-ad/app/src/styles.scss
+++ b/apps/model-ad/app/src/styles.scss
@@ -1 +1,4 @@
/* You can add global styles to this file, and also import other style files */
+@use 'libs/model-ad/styles/src/index';
+
+@use 'app-theme';
diff --git a/libs/model-ad/.gitkeep b/libs/model-ad/.gitkeep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/libs/model-ad/styles/README.md b/libs/model-ad/styles/README.md
new file mode 100644
index 0000000000..3428bf1e5f
--- /dev/null
+++ b/libs/model-ad/styles/README.md
@@ -0,0 +1 @@
+# model-ad-styles
diff --git a/libs/model-ad/styles/project.json b/libs/model-ad/styles/project.json
new file mode 100644
index 0000000000..a6d0e044d3
--- /dev/null
+++ b/libs/model-ad/styles/project.json
@@ -0,0 +1,13 @@
+{
+ "name": "model-ad-styles",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/model-ad/styles/src",
+ "projectType": "library",
+ "generators": {},
+ "targets": {},
+ "tags": [
+ "type:styles",
+ "scope:model-ad",
+ "language:typescript"
+ ]
+}
\ No newline at end of file
diff --git a/libs/model-ad/styles/src/_index.scss b/libs/model-ad/styles/src/_index.scss
new file mode 100644
index 0000000000..144ee1f14c
--- /dev/null
+++ b/libs/model-ad/styles/src/_index.scss
@@ -0,0 +1,4 @@
+@use 'libs/shared/typescript/styles/src/index';
+
+@use './lib/constants';
+@use './lib/general';
diff --git a/libs/model-ad/styles/src/lib/_constants.scss b/libs/model-ad/styles/src/lib/_constants.scss
new file mode 100644
index 0000000000..ceb3628f29
--- /dev/null
+++ b/libs/model-ad/styles/src/lib/_constants.scss
@@ -0,0 +1,39 @@
+// See https://github.com/angular/components/blob/master/src/material/core/style/_variables.scss
+
+// Global constants
+$pi: 3.14159264;
+$padding-test: 20px;
+
+// Figma variables
+$dl-size-size-large: 144px;
+$dl-size-size-small: 48px;
+$dl-size-size-medium: 96px;
+$dl-size-size-xlarge: 192px;
+$dl-size-size-xsmall: 16px;
+$dl-space-space-unit: 16px;
+$dl-size-size-xxlarge: 288px;
+$dl-size-size-maxwidth: 1400px;
+$dl-radius-radius-round: 50%;
+$dl-space-space-halfunit: 8px;
+$dl-space-space-sixunits: 96px;
+$dl-space-space-twounits: 32px;
+$dl-radius-radius-radius2: 2px;
+$dl-radius-radius-radius4: 4px;
+$dl-radius-radius-radius8: 8px;
+$dl-space-space-fiveunits: 80px;
+$dl-space-space-fourunits: 64px;
+$dl-radius-radius-radius16: 16px;
+$dl-space-space-threeunits: 48px;
+$dl-space-space-oneandhalfunits: 24px;
+
+// Breakpoints from https://getbootstrap.com/docs/5.0/layout/breakpoints/
+$sm-breakpoint: 576px;
+$md-breakpoint: 768px;
+$lg-breakpoint: 992px;
+$xl-breakpoint: 1200px;
+$xxl-breakpoint: 1400px;
+
+// Dimensions of component
+$navbar-height: 68px;
+$navbar-height-tall: 240px;
+$footer-height: 259px;
diff --git a/libs/model-ad/styles/src/lib/_general.scss b/libs/model-ad/styles/src/lib/_general.scss
new file mode 100644
index 0000000000..e774e40dbb
--- /dev/null
+++ b/libs/model-ad/styles/src/lib/_general.scss
@@ -0,0 +1,432 @@
+@use 'libs/model-ad/styles/src/lib/constants';
+
+html {
+ margin-top: constants.$navbar-height;
+}
+body {
+ max-height: 100vh;
+ margin: 0;
+}
+em {
+ color: #00b1e5;
+ font-style: normal;
+ font-weight: 700;
+}
+
+// GRID
+.base {
+ width: 100%;
+ min-height: calc(100vh - constants.$navbar-height - constants.$footer-height);
+}
+.row {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+}
+.col {
+ display: flex;
+ flex-direction: column;
+ flex-basis: 100%;
+}
+.fill-empty {
+ max-width: 920px;
+}
+.content {
+ @extend .row;
+ max-width: 2000px;
+ margin: auto;
+ padding: 48px 32px;
+ gap: 36px;
+}
+
+// TEXT
+.text-left {
+ text-align: left;
+}
+.text-center {
+ text-align: center;
+}
+.text-right {
+ text-align: right;
+}
+.text-grey,
+span.text-grey a {
+ color: rgba(black, 0.38);
+}
+.text-right {
+ font-weight: 600;
+}
+
+// LOGO & DESIGN
+.logo-icon {
+ width: 140px;
+ height: 140px;
+}
+.top-design {
+ background: url('/model-ad-assets/images/banner-sm.svg');
+ background-size: cover;
+ background-position: bottom;
+ padding-top: 108px;
+ text-align: center;
+
+ .section-inner {
+ margin-bottom: 40px;
+
+ h2 {
+ margin: 8px 0;
+ }
+ }
+}
+
+// BUTTONS
+.btn {
+ padding: 6px 32px !important;
+ text-transform: uppercase;
+ text-decoration: none;
+ transition: background 0.15s ease !important;
+}
+.btn-block {
+ width: 100%;
+ padding: 16px 32px !important;
+ text-transform: uppercase;
+ text-decoration: none;
+}
+.btn-group {
+ display: flex;
+ flex-flow: column wrap;
+ align-content: center;
+
+ a {
+ text-decoration: none;
+ }
+}
+.btn-group > *:first-child {
+ align-self: stretch;
+}
+.btn-group button,
+.btn-group a {
+ margin: 5px;
+ padding: 21px 32px !important;
+}
+
+// SEARCH PAGES
+#search-top {
+ padding: 0 32px 80px;
+}
+.search-sort-container {
+ gap: 24px;
+ justify-content: space-between;
+}
+.search-field {
+ position: relative;
+ flex-grow: 1;
+ margin: auto;
+}
+.sort-field {
+ display: flex;
+ gap: 16px;
+ align-items: center;
+}
+.sort-title {
+ white-space: nowrap;
+}
+.facets {
+ padding: 24px 16px;
+ height: 100%;
+ min-width: 280px;
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 8px;
+
+ & > * {
+ width: 100%;
+ }
+}
+
+// PROFILE PAGES
+#profile-top,
+#profile-bottom {
+ min-height: 320px;
+ justify-content: center;
+}
+#profile-top {
+ padding-top: 60px;
+}
+#profile-bottom {
+ padding-top: 32px;
+}
+#profile-top > div {
+ align-self: center;
+ flex: 1 0 auto;
+ padding: 22px;
+}
+.profile-pic,
+.organization-card-banner {
+ // width: 40px;
+ // object-fit: cover;
+ margin: 8px;
+ align-self: center;
+ flex: 0 0 auto;
+ box-sizing: border-box;
+ border-radius: constants.$dl-radius-radius-round;
+ box-shadow: 1px 5px 18px 0px #d4d4d4;
+
+ div.avatar-content {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+#profile-details {
+ max-width: 100%;
+ text-align: center;
+}
+.profile-activity-card {
+ text-align: right;
+}
+.profile-nav-group {
+ margin: 18px;
+ padding: 48px 18px;
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 8px;
+}
+.profile-nav-item {
+ width: 100%;
+ height: 54px;
+ margin: 0 0 18px 0;
+ padding: 13px 18px;
+ box-sizing: border-box;
+ transition: 0.3s;
+ align-items: flex-start;
+ flex-shrink: 1;
+ text-align: left;
+ text-decoration: none;
+}
+.profile-type {
+ width: 100%;
+ max-width: 148px;
+ margin: 8px 0;
+ padding: 5px;
+ border-radius: 32px;
+ text-align: center;
+ align-self: center;
+}
+.stats-group {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+ justify-content: center;
+}
+.stat-item {
+ flex-direction: column;
+ flex: 1;
+ max-width: 120px;
+ padding: 18px 5px 8px;
+ border-style: solid;
+ border-width: 1px;
+ text-align: center;
+ border-color: var(--color-btn-shadow);
+ background-color: white;
+ border-right-width: 0;
+
+ h3 {
+ margin-bottom: 2px !important;
+ }
+}
+.action-btn,
+.disabled-btn {
+ height: 100%;
+ min-width: 260px;
+ max-width: 280px;
+ padding: 13px 5px;
+ display: inline-flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+.action-btn {
+ background-color: var(--color-btn-primary);
+ color: white;
+ border-color: transparent;
+ cursor: pointer;
+}
+.disabled-btn {
+ background-color: var(--color-btn-disabled);
+ border-right-width: 1px;
+}
+.stats-card-icon {
+ margin-right: 4px;
+}
+table {
+ border-spacing: 11px;
+}
+#bio div a mat-icon {
+ font-size: 15px;
+ vertical-align: middle;
+}
+.created-updated-dates,
+.created-updated-dates a,
+.read-more {
+ color: #1f3b8f;
+}
+.created-updated-dates {
+ font-style: italic !important;
+}
+.read-more {
+ text-underline-offset: 3px;
+}
+
+// CARDS
+@mixin line-clamp($max-lines) {
+ display: -webkit-box;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: $max-lines;
+}
+.card-group {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+ gap: 24px;
+ padding: 16px 0;
+}
+.card-banner {
+ width: 100%;
+ height: 130px;
+ display: flex;
+ align-items: flex-start;
+}
+.card-icon {
+ margin: 0 3px;
+ padding-right: 24px;
+}
+.card-title {
+ margin: 15px 0 !important;
+ font-weight: 700 !important;
+ line-height: 24px !important;
+ min-height: 48px;
+ @include line-clamp(2);
+}
+.mat-caption {
+ @include line-clamp(2);
+}
+.card-body {
+ width: 100%;
+ margin: 8px;
+ display: flex;
+ flex: 1;
+ align-items: center;
+ flex-direction: column;
+ justify-content: flex-start;
+
+ & > p {
+ text-align: center;
+ }
+}
+.card-footer {
+ display: flex;
+ flex-direction: row;
+ height: 50px;
+ width: 100%;
+ border-top: 1px solid #c4c4c4;
+ justify-content: center;
+ align-items: center;
+ gap: 6px;
+}
+.star-btn {
+ position: absolute;
+ top: 18px;
+ right: 18px;
+ // height: 32px;
+ padding: 0 8px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: constants.$dl-radius-radius-radius16;
+ cursor: pointer;
+}
+
+// MEDIA QUERIES
+@media screen and (max-width: constants.$sm-breakpoint) {
+ .profile-activity-card {
+ text-align: center;
+ }
+}
+@media screen and (max-width: constants.$md-breakpoint) {
+ .content {
+ flex-direction: column;
+ }
+}
+@media screen and (min-width: constants.$md-breakpoint) {
+ .col,
+ .col-1 {
+ flex: 1;
+ }
+ .col-2 {
+ flex: 2;
+ }
+ .col-3 {
+ flex: 3;
+ }
+ .col-4 {
+ flex: 4;
+ }
+ .col-5 {
+ flex: 5;
+ }
+ .col-6 {
+ flex: 6;
+ }
+ .col-7 {
+ flex: 7;
+ }
+ .col-8 {
+ flex: 8;
+ }
+ .col-9 {
+ flex: 9;
+ }
+ .col-10 {
+ flex: 10;
+ }
+ .col-11 {
+ flex: 11;
+ }
+ .col-12 {
+ flex: 12;
+ }
+ #search-top {
+ padding: 0 132px 80px;
+ }
+ #profile-details {
+ // max-width: 760px;
+ max-width: 1060px;
+ text-align: left;
+ }
+ .profile-type {
+ align-self: auto;
+ }
+ .profile-sidenav {
+ max-width: 320px;
+ }
+}
+@media only screen and (max-width: constants.$lg-breakpoint) {
+ html {
+ margin-top: constants.$navbar-height-tall;
+ }
+
+ .card-group {
+ grid-template-columns: 60%;
+ justify-content: center;
+ }
+}
diff --git a/libs/model-ad/themes/README.md b/libs/model-ad/themes/README.md
new file mode 100644
index 0000000000..22855b7383
--- /dev/null
+++ b/libs/model-ad/themes/README.md
@@ -0,0 +1 @@
+# model-ad-themes
\ No newline at end of file
diff --git a/libs/model-ad/themes/project.json b/libs/model-ad/themes/project.json
new file mode 100644
index 0000000000..2b9272fd60
--- /dev/null
+++ b/libs/model-ad/themes/project.json
@@ -0,0 +1,14 @@
+{
+ "name": "model-ad-themes",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/model-ad/themes/src",
+ "projectType": "library",
+ "generators": {},
+ "targets": {},
+ "tags": [
+ "type:themes",
+ "scope:model-ad",
+ "language:typescript"
+ ],
+ "implicitDependencies": []
+}
\ No newline at end of file
diff --git a/libs/model-ad/themes/src/_fonts.scss b/libs/model-ad/themes/src/_fonts.scss
new file mode 100644
index 0000000000..f4f0388601
--- /dev/null
+++ b/libs/model-ad/themes/src/_fonts.scss
@@ -0,0 +1,16 @@
+@use '@angular/material' as mat;
+
+@import url('https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap');
+
+
+$lato: mat.define-typography-config(
+ $font-family: "'Lato', sans-serif",
+ $headline-5: mat.define-typography-level(46px, 56px, 700),
+ $headline-6: mat.define-typography-level(40px, 50px, 700),
+ $subtitle-1: mat.define-typography-level(28px, 38px, 700, $letter-spacing: -0.1px),
+ $subtitle-2: mat.define-typography-level(20px, 32px, 400, $letter-spacing: -0.1px),
+ $body-1: mat.define-typography-level(21px, 36px, 400, $letter-spacing: -0.1px),
+ $body-2: mat.define-typography-level(16px, 26px, 400),
+ $caption: mat.define-typography-level(14px, 21px, 400),
+ $button: mat.define-typography-level(16px, 18px, 700),
+);
diff --git a/libs/model-ad/themes/src/_index.scss b/libs/model-ad/themes/src/_index.scss
new file mode 100644
index 0000000000..de22118d94
--- /dev/null
+++ b/libs/model-ad/themes/src/_index.scss
@@ -0,0 +1,5 @@
+@use 'libs/model-ad/ui/src/lib-theme' as model-ad-ui;
+
+@mixin theme($theme) {
+ @include model-ad-ui.theme($theme);
+}
diff --git a/libs/model-ad/themes/src/_palettes.scss b/libs/model-ad/themes/src/_palettes.scss
new file mode 100644
index 0000000000..815a96839d
--- /dev/null
+++ b/libs/model-ad/themes/src/_palettes.scss
@@ -0,0 +1,135 @@
+@use 'sass:map';
+
+// Color variables
+$dark-primary-text: rgba(black, 0.87);
+$dark-secondary-text: rgba(black, 0.54);
+$dark-disabled-text: rgba(black, 0.38);
+$dark-dividers: rgba(black, 0.12);
+$dark-focused: rgba(black, 0.12);
+$light-primary-text: white;
+$light-secondary-text: rgba(white, 0.7);
+$light-disabled-text: rgba(white, 0.5);
+$light-dividers: rgba(white, 0.12);
+$light-focused: rgba(white, 0.12);
+
+$dark-blue-palette: (
+ 50: #e8ebf5,
+ 100: #c4cce7,
+ 200: #9dabd7,
+ 300: #768ac7,
+ 400: #586fbc,
+ 500: #3756b1,
+ 600: #314fa7,
+ 700: #27459b,
+ 800: #1f3b8f,
+ 900: #102979,
+ contrast: (
+ 50: $dark-primary-text,
+ 100: $dark-primary-text,
+ 200: $dark-primary-text,
+ 300: $dark-primary-text,
+ 400: $light-primary-text,
+ 500: $light-primary-text,
+ 600: $light-primary-text,
+ 700: $light-primary-text,
+ 800: $light-primary-text,
+ 900: $light-primary-text,
+ ),
+);
+
+$light-blue-palette: (
+ 50: #dff4fb,
+ 100: #ade3f4,
+ 200: #76d1ed,
+ 300: #39bde7,
+ 400: #00b1e5,
+ 500: #00a4e3,
+ 600: #0096d5,
+ 700: #0084c3,
+ 800: #0073b0,
+ 900: #005390,
+ contrast: (
+ 50: $dark-primary-text,
+ 100: $dark-primary-text,
+ 200: $dark-primary-text,
+ 300: $dark-primary-text,
+ 400: $dark-primary-text,
+ 500: $dark-primary-text,
+ 600: $dark-primary-text,
+ 700: $dark-primary-text,
+ 800: $light-primary-text,
+ 900: $light-primary-text,
+ ),
+);
+
+$light-green-palette: (
+ 50: #e8fefb,
+ 100: #c6fdf3,
+ 200: #a5fdec,
+ 300: #88f9e3,
+ 400: #76f2d9,
+ 500: #71ecd0,
+ 600: #6adbbf,
+ 700: #61c8ad,
+ 800: #5bb79d,
+ 900: #50977e,
+ contrast: (
+ 50: $dark-primary-text,
+ 100: $dark-primary-text,
+ 200: $dark-primary-text,
+ 300: $dark-primary-text,
+ 400: $dark-primary-text,
+ 500: $dark-primary-text,
+ 600: $dark-primary-text,
+ 700: $dark-primary-text,
+ 800: $dark-primary-text,
+ 900: $dark-primary-text,
+ ),
+);
+
+$light-purple-palette: (
+ 50: #ede8ff,
+ 100: #d0c6fd,
+ 200: #afa0fe,
+ 300: #8a78ff,
+ 400: #6859ff,
+ 500: #594AFC,
+ 600: #2e3aee,
+ 700: #0032e5,
+ 800: #002ddc,
+ 900: #0023ce,
+ contrast: (
+ 50: $dark-primary-text,
+ 100: $dark-primary-text,
+ 200: $dark-primary-text,
+ 300: $dark-primary-text,
+ 400: $light-primary-text,
+ 500: $light-primary-text,
+ 600: $light-primary-text,
+ 700: $light-primary-text,
+ 800: $light-primary-text,
+ 900: $light-primary-text,
+ ),
+);
+
+// Alias for "accent" usage
+$accent-green-palette: $light-green-palette;
+$accent-purple-palette: $light-purple-palette;
+
+// Figma palettes variables
+$figma-collection: (
+ dl-color-default-navbar: map.get($dark-blue-palette, 600),
+ dl-color-default-accent1: map.get($accent-green-palette, 100),
+ dl-color-default-accent2: map.get($accent-purple-palette, 50),
+ dl-color-default-primary1: map.get($dark-blue-palette, 400),
+ dl-color-default-primary2: $dark-focused,
+ dl-color-default-navbardark: map.get($dark-blue-palette, 800),
+ dl-color-default-secondary1: map.get($light-blue-palette, 300),
+ dl-color-default-secondary2: map.get($accent-purple-palette, 300),
+ dl-color-default-darkaccent1: map.get($accent-green-palette, 700),
+ dl-color-default-darkaccent2: map.get($accent-purple-palette, 200),
+ dl-color-gray-black: #000000,
+ dl-color-gray-white: #ffffff,
+ dl-color-default-hover1: rgba(249, 249, 249, 1),
+ dl-color-default-hover2: rgba(229, 229, 229, 1),
+);
diff --git a/libs/model-ad/ui/.eslintrc.json b/libs/model-ad/ui/.eslintrc.json
new file mode 100644
index 0000000000..921d4e5307
--- /dev/null
+++ b/libs/model-ad/ui/.eslintrc.json
@@ -0,0 +1,50 @@
+{
+ "extends": [
+ "../../../.eslintrc.json"
+ ],
+ "ignorePatterns": [
+ "!**/*"
+ ],
+ "env": {
+ "jest": true
+ },
+ "overrides": [
+ {
+ "files": [
+ "*.ts"
+ ],
+ "extends": [
+ "plugin:@nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates",
+ "plugin:jest/recommended"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "model-ad",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "model-ad",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": [
+ "*.html"
+ ],
+ "extends": [
+ "plugin:@nx/angular-template"
+ ],
+ "rules": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libs/model-ad/ui/README.md b/libs/model-ad/ui/README.md
new file mode 100644
index 0000000000..53bd98408c
--- /dev/null
+++ b/libs/model-ad/ui/README.md
@@ -0,0 +1,7 @@
+# model-ad-ui
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test model-ad-ui` to execute the unit tests.
diff --git a/libs/model-ad/ui/jest.config.ts b/libs/model-ad/ui/jest.config.ts
new file mode 100644
index 0000000000..0c34499915
--- /dev/null
+++ b/libs/model-ad/ui/jest.config.ts
@@ -0,0 +1,23 @@
+/* eslint-disable */
+export default {
+ displayName: 'model-ad-ui',
+ preset: '../../../jest.preset.js',
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
+ globals: {},
+ coverageDirectory: '../../../coverage/libs/model-ad/ui',
+ transform: {
+ '^.+\\.(ts|mjs|js|html)$': [
+ 'jest-preset-angular',
+ {
+ tsconfig: '/tsconfig.spec.json',
+ stringifyContentPathRegex: '\\.(html|svg)$',
+ },
+ ],
+ },
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+ snapshotSerializers: [
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
+ 'jest-preset-angular/build/serializers/ng-snapshot',
+ 'jest-preset-angular/build/serializers/html-comment',
+ ],
+};
diff --git a/libs/model-ad/ui/project.json b/libs/model-ad/ui/project.json
new file mode 100644
index 0000000000..b4b9e13f1d
--- /dev/null
+++ b/libs/model-ad/ui/project.json
@@ -0,0 +1,27 @@
+{
+ "name": "model-ad-ui",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "library",
+ "sourceRoot": "libs/model-ad/ui/src",
+ "prefix": "model-ad",
+ "targets": {
+ "test": {
+ "executor": "@nx/jest:jest",
+ "outputs": [
+ "{workspaceRoot}/coverage/libs/model-ad/ui"
+ ],
+ "options": {
+ "jestConfig": "libs/model-ad/ui/jest.config.ts"
+ }
+ },
+ "lint": {
+ "executor": "@nx/eslint:lint"
+ }
+ },
+ "tags": [
+ "type:feature",
+ "scope:model-ad",
+ "language:typescript"
+ ],
+ "implicitDependencies": []
+}
\ No newline at end of file
diff --git a/libs/model-ad/ui/src/_lib-theme.scss b/libs/model-ad/ui/src/_lib-theme.scss
new file mode 100644
index 0000000000..f5d492663f
--- /dev/null
+++ b/libs/model-ad/ui/src/_lib-theme.scss
@@ -0,0 +1,5 @@
+@use './lib/footer/footer-theme' as footer;
+
+@mixin theme($theme) {
+ @include footer.theme($theme);
+}
diff --git a/libs/model-ad/ui/src/index.ts b/libs/model-ad/ui/src/index.ts
new file mode 100644
index 0000000000..e70ebd86fe
--- /dev/null
+++ b/libs/model-ad/ui/src/index.ts
@@ -0,0 +1 @@
+export * from './lib/footer/footer.component';
diff --git a/libs/model-ad/ui/src/lib/footer/_footer-theme.scss b/libs/model-ad/ui/src/lib/footer/_footer-theme.scss
new file mode 100644
index 0000000000..fee88f2524
--- /dev/null
+++ b/libs/model-ad/ui/src/lib/footer/_footer-theme.scss
@@ -0,0 +1,60 @@
+@use 'sass:map';
+@use '@angular/material' as mat;
+@use 'libs/model-ad/styles/src/lib/constants';
+
+@mixin color($theme) {
+ $config: mat.get-color-config($theme);
+ $primary: map.get($config, 'primary');
+ $accent: map.get($config, 'accent');
+ $warn: map.get($config, 'warn');
+
+ footer {
+ background-color: mat.get-color-from-palette($primary, 600);
+ color: #fff;
+ }
+ .footer-link-group a,
+ .footer-links a {
+ color: #fff;
+ }
+ .footer-bottom {
+ background-color: mat.get-color-from-palette($primary, 800);
+ }
+}
+
+@mixin typography($theme) {
+ $config: mat.get-typography-config($theme);
+
+ footer {
+ font-weight: 500;
+ line-height: normal;
+ }
+ .app-info {
+ font-size: 14px;
+ line-height: 21px;
+ }
+ .footer-link-group {
+ font-size: 16px;
+ }
+ .footer-subtext,
+ .footer-links,
+ .footer-links a {
+ font-size: 16px;
+ }
+ @media only screen and (max-width: constants.$md-breakpoint) {
+ .footer-link-group {
+ font-size: 14px !important;
+ }
+ }
+}
+
+@mixin theme($theme) {
+ $color-config: mat.get-color-config($theme);
+ @if $color-config != null {
+ @include color($theme);
+ }
+
+ $typography-config: mat.get-typography-config($theme);
+ @if $typography-config != null {
+ @include typography($theme);
+ }
+}
diff --git a/libs/model-ad/ui/src/lib/footer/footer.component.html b/libs/model-ad/ui/src/lib/footer/footer.component.html
new file mode 100644
index 0000000000..8bb1f00464
--- /dev/null
+++ b/libs/model-ad/ui/src/lib/footer/footer.component.html
@@ -0,0 +1,41 @@
+
diff --git a/libs/model-ad/ui/src/lib/footer/footer.component.scss b/libs/model-ad/ui/src/lib/footer/footer.component.scss
new file mode 100644
index 0000000000..f9fb0b6e21
--- /dev/null
+++ b/libs/model-ad/ui/src/lib/footer/footer.component.scss
@@ -0,0 +1,71 @@
+@use 'libs/model-ad/styles/src/lib/constants';
+
+footer {
+ width: 100%;
+ height: constants.$footer-height;
+ position: relative;
+ padding: 42px 52px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ box-sizing: border-box;
+}
+.footer-link-group {
+ width: 420px;
+ height: 30px;
+ padding: 0;
+ display: flex;
+ justify-content: space-between;
+ list-style: none;
+}
+.footer-link-group li {
+ flex: 0 0 auto;
+}
+.app-info {
+ text-align: right;
+ align-self: center;
+}
+.app-info ul {
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+}
+.footer-bottom {
+ bottom: 0;
+ left: 0px;
+ width: 100%;
+ height: 70px;
+ display: flex;
+ position: absolute;
+ align-items: center;
+ justify-content: center;
+}
+.footer-links,
+.footer-links a {
+ text-decoration: none;
+}
+.footer-links a:hover {
+ text-decoration: underline;
+}
+.logo {
+ height: 56px;
+}
+
+@media only screen and (max-width: constants.$md-breakpoint) {
+ footer {
+ height: 410px;
+ }
+ .about-oc,
+ .app-info,
+ .footer-link-group {
+ width: 100%;
+ text-align: center;
+ justify-content: space-around;
+ }
+ .footer-link-group li {
+ flex: 1;
+ }
+ .app-info {
+ margin-top: 45px;
+ }
+}
diff --git a/libs/model-ad/ui/src/lib/footer/footer.component.spec.ts b/libs/model-ad/ui/src/lib/footer/footer.component.spec.ts
new file mode 100644
index 0000000000..48a1b8798f
--- /dev/null
+++ b/libs/model-ad/ui/src/lib/footer/footer.component.spec.ts
@@ -0,0 +1,25 @@
+import { HttpClientModule } from '@angular/common/http';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { FooterComponent } from './footer.component';
+
+describe('FooterComponent', () => {
+ let component: FooterComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [HttpClientModule, RouterTestingModule],
+ }).compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FooterComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/libs/model-ad/ui/src/lib/footer/footer.component.ts b/libs/model-ad/ui/src/lib/footer/footer.component.ts
new file mode 100644
index 0000000000..5ea766931c
--- /dev/null
+++ b/libs/model-ad/ui/src/lib/footer/footer.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+
+@Component({
+ selector: 'model-ad-footer',
+ standalone: true,
+ imports: [CommonModule, RouterModule],
+ templateUrl: './footer.component.html',
+ styleUrls: ['./footer.component.scss'],
+})
+export class FooterComponent {
+ @Input({ required: true }) appVersion = '';
+ @Input({ required: true }) dataUpdatedOn = '';
+ @Input({ required: true }) privacyPolicyUrl = '';
+ @Input({ required: true }) termsOfUseUrl = '';
+ @Input({ required: true }) apiDocsUrl = '';
+}
diff --git a/libs/model-ad/ui/src/test-setup.ts b/libs/model-ad/ui/src/test-setup.ts
new file mode 100644
index 0000000000..1100b3e8a6
--- /dev/null
+++ b/libs/model-ad/ui/src/test-setup.ts
@@ -0,0 +1 @@
+import 'jest-preset-angular/setup-jest';
diff --git a/libs/model-ad/ui/tsconfig.json b/libs/model-ad/ui/tsconfig.json
new file mode 100644
index 0000000000..f96ad85d2e
--- /dev/null
+++ b/libs/model-ad/ui/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ },
+ {
+ "path": "./tsconfig.spec.json"
+ }
+ ],
+ "compilerOptions": {
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "target": "es2020"
+ },
+ "angularCompilerOptions": {
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
diff --git a/libs/model-ad/ui/tsconfig.lib.json b/libs/model-ad/ui/tsconfig.lib.json
new file mode 100644
index 0000000000..b228a1a081
--- /dev/null
+++ b/libs/model-ad/ui/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "declaration": true,
+ "declarationMap": true,
+ "inlineSources": true,
+ "types": []
+ },
+ "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts", "jest.config.ts"],
+ "include": ["**/*.ts"]
+}
diff --git a/libs/model-ad/ui/tsconfig.spec.json b/libs/model-ad/ui/tsconfig.spec.json
new file mode 100644
index 0000000000..d3889a9881
--- /dev/null
+++ b/libs/model-ad/ui/tsconfig.spec.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["jest", "node"]
+ },
+ "files": ["src/test-setup.ts"],
+ "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
+}
diff --git a/tsconfig.base.json b/tsconfig.base.json
index a6192bd034..4d136dd3e6 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -10,46 +10,89 @@
"importHelpers": true,
"target": "es2015",
"module": "esnext",
- "lib": ["es2017", "dom"],
+ "lib": [
+ "es2017",
+ "dom"
+ ],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"baseUrl": ".",
"paths": {
- "@sagebionetworks/openchallenges/about": ["libs/openchallenges/about/src/index.ts"],
+ "@sagebionetworks/openchallenges/about": [
+ "libs/openchallenges/about/src/index.ts"
+ ],
"@sagebionetworks/openchallenges/api-client-angular": [
"libs/openchallenges/api-client-angular/src/index.ts"
],
- "@sagebionetworks/openchallenges/assets": ["libs/openchallenges/assets/src/index.ts"],
- "@sagebionetworks/openchallenges/auth": ["libs/openchallenges/auth/src/index.ts"],
- "@sagebionetworks/openchallenges/challenge": ["libs/openchallenges/challenge/src/index.ts"],
+ "@sagebionetworks/openchallenges/assets": [
+ "libs/openchallenges/assets/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/auth": [
+ "libs/openchallenges/auth/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/challenge": [
+ "libs/openchallenges/challenge/src/index.ts"
+ ],
"@sagebionetworks/openchallenges/challenge-search": [
"libs/openchallenges/challenge-search/src/index.ts"
],
- "@sagebionetworks/openchallenges/config": ["libs/openchallenges/config/src/index.ts"],
- "@sagebionetworks/openchallenges/home": ["libs/openchallenges/home/src/index.ts"],
- "@sagebionetworks/openchallenges/login": ["libs/openchallenges/login/src/index.ts"],
- "@sagebionetworks/openchallenges/not-found": ["libs/openchallenges/not-found/src/index.ts"],
+ "@sagebionetworks/openchallenges/config": [
+ "libs/openchallenges/config/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/home": [
+ "libs/openchallenges/home/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/login": [
+ "libs/openchallenges/login/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/not-found": [
+ "libs/openchallenges/not-found/src/index.ts"
+ ],
"@sagebionetworks/openchallenges/org-profile": [
"libs/openchallenges/org-profile/src/index.ts"
],
- "@sagebionetworks/openchallenges/org-search": ["libs/openchallenges/org-search/src/index.ts"],
- "@sagebionetworks/openchallenges/pages": ["libs/openchallenges/pages/src/index.ts"],
- "@sagebionetworks/openchallenges/signup": ["libs/openchallenges/signup/src/index.ts"],
- "@sagebionetworks/openchallenges/styles": ["libs/openchallenges/styles/src/index.ts"],
- "@sagebionetworks/openchallenges/team": ["libs/openchallenges/team/src/index.ts"],
- "@sagebionetworks/openchallenges/themes": ["libs/openchallenges/themes/src/index.ts"],
- "@sagebionetworks/openchallenges/ui": ["libs/openchallenges/ui/src/index.ts"],
+ "@sagebionetworks/openchallenges/org-search": [
+ "libs/openchallenges/org-search/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/pages": [
+ "libs/openchallenges/pages/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/signup": [
+ "libs/openchallenges/signup/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/styles": [
+ "libs/openchallenges/styles/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/team": [
+ "libs/openchallenges/team/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/themes": [
+ "libs/openchallenges/themes/src/index.ts"
+ ],
+ "@sagebionetworks/openchallenges/ui": [
+ "libs/openchallenges/ui/src/index.ts"
+ ],
"@sagebionetworks/openchallenges/user-profile": [
"libs/openchallenges/user-profile/src/index.ts"
],
- "@sagebionetworks/openchallenges/util": ["libs/openchallenges/util/src/index.ts"],
- "@sagebionetworks/shared/util": ["libs/shared/typescript/util/src/index.ts"],
+ "@sagebionetworks/openchallenges/util": [
+ "libs/openchallenges/util/src/index.ts"
+ ],
+ "@sagebionetworks/shared/util": [
+ "libs/shared/typescript/util/src/index.ts"
+ ],
"@sagebionetworks/shared/web-components": [
"libs/shared/typescript/web-components/src/index.ts"
+ ],
+ "@sagebionetworks/model-ad/ui": [
+ "libs/model-ad/ui/src/index.ts"
]
}
},
- "exclude": ["node_modules", "tmp"]
-}
+ "exclude": [
+ "node_modules",
+ "tmp"
+ ]
+}
\ No newline at end of file