diff --git a/.dockerignore b/.dockerignore index 8e3d0e1a7..bfc11840b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,28 @@ +# Python virtualenvs (note: "venv*" does NOT match ".venv" — list both) venv* env* +.venv/ +.env/ + +# local secrets / generated config oeplatform/securitysettings.py +# node deps (installed inside the image / named volume) node_modules/ + +# VCS + large runtime data that is bind-mounted, never needed at build time +.git/ +.gitignore +ontologies/ +media/ +static/ +data/ + +# editor / OS / build noise +.vscode/ +.idea/ +__pycache__/ +*.pyc +*.bak +*.bak-* +podman/ diff --git a/base/static/css/base-style.css b/base/static/css/base-style.css index 55880f4c0..44691f9ed 100644 --- a/base/static/css/base-style.css +++ b/base/static/css/base-style.css @@ -35,6 +35,12 @@ body { background-image: unset; } +@media screen and (max-width: 991.98px) { + .navbar-toggler + .navbar-brand { + margin-left: 2rem; + } +} + .site-header { text-align: center; width: 100%; diff --git a/base/static/css/index-style.css b/base/static/css/index-style.css index 21a19ea49..a96c575c2 100644 --- a/base/static/css/index-style.css +++ b/base/static/css/index-style.css @@ -7,200 +7,870 @@ align-items: center; } -.index-padding { - margin-top: 2em; +.index-home .btn-close { + -webkit-user-select: none; + user-select: none; } -.index-group { - height: 100%; +.index-animate-in { + opacity: 1; +} + +@media (prefers-reduced-motion: no-preference) { + .index-animate-in { + opacity: 0; + transform: translateY(20px); + transition: + opacity 250ms ease-out, + transform 250ms ease-out; + } + + .index-animate-in.is-visible { + opacity: 1; + transform: translateY(0); + } + + /* stagger cards within a row by 80ms each; nth-child is scoped per grid */ + .index-features-grid > .index-feature-card:nth-child(2) { + transition-delay: 80ms; + } + + .index-features-grid > .index-feature-card:nth-child(3) { + transition-delay: 160ms; + } + + .index-features-grid > .index-feature-card:nth-child(4) { + transition-delay: 240ms; + } + + .index-capabilities-list > .index-capability-card:nth-child(2) { + transition-delay: 80ms; + } + + .index-capabilities-list > .index-capability-card:nth-child(3) { + transition-delay: 160ms; + } + + .index-capabilities-list > .index-capability-card:nth-child(4) { + transition-delay: 240ms; + } + + /* sits beside .index-academy-intro in the same row, so it staggers after it */ + .index-academy-quickstart.index-animate-in { + transition-delay: 80ms; + } +} + +.index-hero { + background-color: var(--bs-primary); + padding: 96px 24px; display: flex; - flex-flow: column; + flex-direction: column; align-items: center; - justify-content: space-around; } -.index-tutorial { - padding: 2em 1em; +.index-hero-inner { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + width: 100%; + max-width: 1248px; } -.index-tutorial span { - line-height: 1.5em; +.index-hero-badge { + padding: 8px 0; + border-bottom: 2px solid var(--white); + font-size: 14px; + font-weight: 600; + letter-spacing: 0.14px; + color: var(--white); } -.index-tutorial a { - margin-top: 1em; - background-image: none; - border: 1px solid black; +.index-hero-title { + margin: 0; + font-size: 60px; + font-weight: 600; + line-height: 1.1; + letter-spacing: -1.2px; + color: var(--white); +} + +.index-hero-subtitle { + margin: 0; + max-width: 591px; + font-size: 20px; + font-weight: 300; + line-height: 1.4; + letter-spacing: 0.2px; + color: var(--white); } -.index-home h3 { +.index-hero-actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 16px; + padding: 24px 0; +} + +.index-hero-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + height: 46px; + padding: 0 24px; + border-radius: 4px; + font-size: 16px; font-weight: 600; - font-size: 32px; + letter-spacing: 0.25px; + text-decoration: none; + white-space: nowrap; + -webkit-user-select: none; + user-select: none; +} + +.index-hero-btn-light { + background-color: #f6f9fb; color: var(--primaryColor2); + border: none; } -.index-home span.subheader { - font-size: 24px; - color: var(--grey1); +.index-hero-btn-light:hover { + background-color: var(--white); + color: var(--primaryColor2); } -.index-home h4 { - font-weight: 600; - color: var(--primaryColor4); +.index-hero-btn-outline { + background-color: transparent; + color: var(--white); + border: 2px solid var(--white); +} + +.index-hero-btn-outline:hover { + background-color: rgba(255, 255, 255, 0.1); + color: var(--white); +} + +@media screen and (max-width: 800px) { + .index-hero { + padding: 48px 24px; + } + + .index-hero-title { + font-size: 36px; + } + + .index-hero-subtitle { + font-size: 16px; + } } -.index-tile { - transform: scale(0.8); - margin: -1.8em; - margin-bottom: 1em; - max-width: 350px; +.index-features { display: flex; flex-direction: column; align-items: center; - padding: 0.5em; + gap: 64px; + padding: 96px 24px; + width: 100%; } -.inner-index-tile { - padding-left: 5px; +.index-features-header { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + width: 100%; + max-width: 1248px; +} + +.index-features-title { + margin: 0; + font-size: 36px; + font-weight: 700; + letter-spacing: 0.72px; + color: #294456; +} + +.index-features-subtitle { + margin: 0; + max-width: 800px; + font-size: 20px; + line-height: 1.4; + letter-spacing: 0.2px; + color: #4d748f; +} + +.index-features-grid { + display: flex; + flex-wrap: wrap; + gap: 16px; + width: 100%; + max-width: 1248px; +} + +.index-features-grid-quad { + display: grid; + grid-template-columns: repeat(4, 1fr); +} + +@media screen and (max-width: 1024px) { + .index-features-grid-quad { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (max-width: 800px) { + .index-features-grid-quad { + grid-template-columns: 1fr; + } +} + +.index-feature-card { + display: flex; + flex: 1 0 240px; + flex-direction: column; + justify-content: space-between; + gap: 24px; + min-height: 300px; + padding: 24px; + border: 1px solid #e9f0f5; + border-radius: 4px; + background-color: var(--white); + box-shadow: 0 2px 1px rgba(41, 114, 166, 0.1); + text-align: left; +} + +.index-feature-card-body { display: flex; flex-direction: column; align-items: flex-start; - justify-content: space-around; + gap: 24px; } -.index-tile .btn{ - /* button on bottom of box */ - margin-top: auto; +.index-feature-icon { + width: 56px; + height: 56px; + filter: drop-shadow(0px 8px 10px rgba(41, 114, 166, 0.1)); } +.index-feature-card-title { + margin: 0; + font-size: 20px; + font-weight: 700; + line-height: 24px; + color: #294456; +} -.index-tile img { - align-self: center; - height: 60px; - width: 60px; - padding-top: 15px; - padding-left: 15px; +.index-feature-card-description { + margin: 0; + font-size: 16px; + line-height: 24px; + color: #294456; } -.index-tile a { - color: var(--white); +.index-feature-link { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-size: 16px; + font-weight: 700; + letter-spacing: 0.32px; + line-height: 24px; + color: var(--bs-primary); + text-decoration: none; background-image: none; border: none; + padding: 0; + -webkit-user-select: none; + user-select: none; +} + +.index-feature-link-arrow { + flex-shrink: 0; + transition: transform 0.2s ease; +} + +.index-feature-link:hover .index-feature-link-arrow, +.index-feature-link:focus-visible .index-feature-link-arrow { + transform: translateX(4px); +} + +@media screen and (max-width: 800px) { + .index-features { + padding: 48px 24px; + } + .index-features-title { + font-size: 28px; + } + + .index-feature-card { + flex: 1 0 100%; + } +} + +.index-capabilities { + display: flex; + flex-direction: column; + align-items: center; + gap: 64px; + padding: 96px 24px; width: 100%; + background-color: #f6fbff; } -.index-tile-color-1 a { - background-color: var(--primaryColor1); +.index-capabilities-header { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + width: 100%; + max-width: 1248px; } -.index-tile-color-2 a { - background-color: var(--primaryColor2); +.index-capabilities-title { + margin: 0; + font-size: 36px; + font-weight: 700; + letter-spacing: 0.72px; + color: #294456; +} + +.index-capabilities-subtitle { + margin: 0; + max-width: 800px; + font-size: 20px; + line-height: 1.4; + letter-spacing: 0.2px; + color: #4d748f; +} + +.index-capabilities-list { + display: flex; + flex-direction: column; + gap: 24px; + width: 100%; + max-width: 1248px; } -.index-tile-color-3 a { - background-color: var(--primaryColor3); +.index-capability-card { + display: flex; + flex-direction: column; + gap: 32px; + width: 100%; + padding: 32px; + border: 1px solid #f6f9fb; + border-radius: 4px; + background-color: var(--white); + box-shadow: 0 2px 1px rgba(41, 114, 166, 0.1); + text-align: left; } -.index-tile-color-4 a { - background-color: var(--primaryColor4); +.index-capability-card-header { + display: flex; + gap: 24px; + align-items: flex-start; + width: 100%; } -.index-tile-color-5 a { - background-color: var(--primaryColor5); +.index-capability-card-heading { + display: flex; + flex-direction: column; + gap: 8px; } -.index-tile-colored { - background-color: white; - border: 2px groove var(--primaryColor1); - border-radius: 5px; +.index-capability-card-title { + margin: 0; + font-size: 24px; + font-weight: 700; + line-height: 24px; + color: #294456; } -.index-tile-bordered a { - border: 1px solid var(--primaryColor4); - color: var(--primaryColor4); +.index-capability-card-description { + margin: 0; + font-size: 16px; + line-height: 24px; + color: #4d748f; } -.index-about-container-background { - background-color: var(--secondaryColor1); +.index-capability-divider { width: 100%; + margin: 0; + border: none; + border-top: 1px solid #e9f0f5; } -.index-about-container { - padding: 2em 1em; +.index-capability-columns { + display: flex; + gap: 48px; width: 100%; +} - display: grid; +.index-capability-column { + display: flex; + flex: 1 0 0; + flex-direction: column; + gap: 16px; + min-width: 0; +} - grid-template-columns: repeat(3, 1fr); - grid-gap: 48px; - max-width: 800px; - margin: auto; +.index-capability-column-title { + margin: 0; + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: #294456; +} +.index-feature-list { + display: flex; + flex-direction: column; + gap: 12px; + margin: 0; + padding: 0; + list-style: none; +} + +.index-feature-list li { + display: flex; + align-items: center; + gap: 12px; +} + +.index-feature-list span { + font-size: 16px; + line-height: 24px; +} + +.index-capability-check { + flex-shrink: 0; +} + +.index-capability-feature-list span { + color: #294456; +} + +.index-capability-resource-list { + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; +} + +.index-resource-link { + display: flex; + align-items: center; + gap: 16px; + width: 100%; + padding: 8px 16px; + border: 1px solid #d7e2ea; + border-radius: 4px; font-size: 14px; + font-weight: 700; + line-height: 24px; + color: var(--bs-primary); + text-decoration: none; + background-image: none; + -webkit-user-select: none; + user-select: none; +} + +.index-resource-link:hover .index-feature-link-arrow, +.index-resource-link:focus-visible .index-feature-link-arrow { + transform: translateX(4px); +} + +@media screen and (max-width: 800px) { + .index-capabilities { + padding: 48px 24px; + } + + .index-capabilities-title { + font-size: 28px; + } + + .index-capability-card { + padding: 24px; + } + + .index-capability-columns { + flex-direction: column; + gap: 24px; + } +} + +.index-academy { + display: flex; + justify-content: center; + width: 100%; + padding: 96px 24px; + background-color: var(--bs-primary); +} + +.index-academy-inner { + display: flex; + gap: 64px; + align-items: flex-start; + width: 100%; + max-width: 1248px; +} + +.index-academy-intro { + display: flex; + flex: 1 1 0; + gap: 32px; + align-items: flex-start; + min-width: 0; +} + +.index-academy-icon { + flex-shrink: 0; + width: 106px; + height: 106px; +} + +.index-academy-content { + display: flex; + flex: 1 1 0; + flex-direction: column; + gap: 32px; + align-items: flex-start; + min-width: 0; + text-align: left; +} + +.index-academy-heading { + display: flex; + flex-direction: column; + gap: 8px; +} + +.index-academy-title { + margin: 0; + font-size: 36px; + font-weight: 700; + letter-spacing: 0.72px; + color: var(--white); +} + +.index-academy-subtitle { + margin: 0; + font-size: 20px; + line-height: 1.4; + letter-spacing: 0.2px; + color: #e7f1f9; +} - color: var(--primaryColor3); +.index-academy-feature-list { + width: 100%; } -.index-about-column img { - height: 32px; +.index-academy-feature-list span { + color: var(--white); } -.index-about-column { - transform: scale(0.8); +.index-academy-quickstart { display: flex; + flex: 0 0 384px; flex-direction: column; - min-height: 150px; + gap: 32px; + padding: 32px; + border: 1px solid #f6f9fb; + border-radius: 4px; + background-color: var(--white); + box-shadow: 0 4px 2px rgba(41, 114, 166, 0.25); + text-align: left; +} +.index-academy-quickstart-title { + margin: 0; + font-size: 24px; + font-weight: 700; + letter-spacing: 0.48px; + color: #294456; +} +.index-academy-quickstart-list { + display: flex; + flex-direction: column; + gap: 12px; +} +.index-academy-quickstart-item { + display: flex; + gap: 16px; + align-items: center; + padding: 16px; + border: 1px solid #d7e2ea; + border-radius: 4px; } -.index-about-column .btn{ - /* button on bottom of box */ - margin-top: auto; +.index-academy-quickstart-icon { + flex-shrink: 0; + width: 24px; + height: 24px; } +.index-academy-quickstart-item-title { + margin: 0; + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: #294456; +} +.index-academy-quickstart-item-description { + margin: 0; + font-size: 14px; + line-height: 1.4; + color: #4d748f; +} -.index-about-column a { +@media screen and (max-width: 1024px) { + .index-academy-quickstart { + flex-basis: 320px; + } +} + +@media screen and (max-width: 800px) { + .index-academy { + padding: 48px 24px; + } + + .index-academy-inner { + flex-direction: column; + } + + .index-academy-intro { + flex-direction: column; + } + + .index-academy-title { + font-size: 28px; + } + + .index-academy-quickstart { + flex: 1 1 auto; + width: 100%; + } +} + +.index-navbar .container-fluid { + padding-left: 2rem; + padding-right: 2rem; +} + +.index-navbar .nav-link { + position: relative; color: var(--white); - background-color: var(--primaryColor3); - background-image: none; - border: none; + font-size: 0.875rem; + -webkit-user-select: none; + user-select: none; +} - padding: 4px 12px; +.index-navbar .navbar-toggler { + -webkit-user-select: none; + user-select: none; } -.index-tile-container { - display: grid; - grid-template-columns: repeat(5, auto); - grid-gap: 2em; - padding: 2em 0; +/* dropdown-toggle items already use ::after for Bootstrap's caret, + so the underline uses ::before there instead to avoid clobbering it */ +.index-navbar .nav-link:not(.dropdown-toggle)::after, +.index-navbar .nav-link.dropdown-toggle::before { + content: ""; + position: absolute; + left: 0; + bottom: 0; + width: 0%; + height: 2px; + background-color: var(--white); + transition: width 0.2s ease; +} + +.index-navbar .nav-link:not(.dropdown-toggle):hover::after, +.index-navbar .nav-link.dropdown-toggle:hover::before { + width: 100%; +} + +/* replace Bootstrap's border-triangle caret with a chevron, same size */ +.index-navbar .dropdown-toggle::after { + display: inline-block; + width: 0.45em; + height: 0.45em; + margin-left: 0.35em; + vertical-align: 0.1em; + content: ""; + border: 0; + border-right: 2px solid currentColor; + border-bottom: 2px solid currentColor; + transform: rotate(45deg); +} + +.index-navbar .dropdown-menu { + margin-top: 0.5rem; + padding: 0.5rem; + border: 1px solid #e9f0f5; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(41, 114, 166, 0.15); + font-size: 0.875rem; +} + +.index-navbar .dropdown-item { + padding: 0.625rem 0.75rem; + border-radius: 4px; + color: #294456; +} + +.index-navbar .dropdown-item:hover, +.index-navbar .dropdown-item:focus { + background-color: #eaf3fa; + color: #1f567d; +} + +.index-navbar .dropdown-item.active, +.index-navbar .dropdown-item:active { + background-color: var(--bs-primary); + color: var(--white); +} - justify-items: center; +.index-navbar .dropdown-menu.show { + animation: index-dropdown-fade 0.15s ease; } -/* -.index-tile .hovertext { - visibility: hidden; - width: auto; - height: auto; - background-color: var(--secondaryColor1); - color: var(--primaryColor2); - justify-content: center; - align-items: center; - position: absolute; - z-index: 1; +@keyframes index-dropdown-fade { + from { + opacity: 0; + } + to { + opacity: 1; } +} + +.index-footer { + display: flex; + justify-content: center; + width: 100%; + padding: 96px 24px; + background-color: var(--bs-primary); +} + +.index-footer-inner { + display: flex; + flex-direction: column; + gap: 96px; + width: 100%; + max-width: 1248px; +} + +.index-footer-top { + display: flex; + align-items: flex-start; + gap: 48px; + width: 100%; + text-align: left; +} + +.index-footer-brand { + display: flex; + flex: 0 0 293px; + flex-direction: column; + gap: 16px; +} + +.index-footer-logo { + display: flex; + align-items: center; + gap: 12px; +} + +.index-footer-brand-name { + margin: 0; + font-size: 20px; + font-weight: 700; + line-height: 24px; + color: var(--white); +} + +.index-footer-tagline { + margin: 0; + font-size: 14px; + line-height: 20px; + color: #e7f1f9; +} + +.index-footer-columns { + display: flex; + flex: 1 0 0; + gap: 48px; +} - .index-tile:hover .hovertext { - visibility: visible; - } */ +.index-footer-column { + display: flex; + flex: 1 0 0; + flex-direction: column; + gap: 16px; + min-width: 0; +} + +.index-footer-column-title { + margin: 0; + font-size: 16px; + font-weight: 700; + color: var(--white); +} + +.index-footer-link-list { + display: flex; + flex-direction: column; + gap: 4px; + margin: 0; + padding: 0; + list-style: none; +} + +.index-footer-link-list a { + font-size: 14px; + color: #e7f1f9; + text-decoration: none; + background-image: none; +} + +.index-footer-link-list a:hover { + color: var(--white); + text-decoration: underline; +} + +.index-footer-copyright { + margin: 0; + font-size: 14px; + text-align: center; + color: #e7f1f9; +} @media screen and (max-width: 800px) { - .index-tile-container { - grid-template-columns: repeat(2, auto); - grid-template-rows: repeat(2, auto); + .index-footer { + padding: 48px 24px; + } + + .index-footer-inner { + gap: 48px; + } + + .index-footer-top { + flex-direction: column; + gap: 32px; + } + + .index-footer-brand { + flex: 1 1 auto; + } + + .index-footer-columns { + flex-direction: column; + gap: 24px; } } diff --git a/base/static/img/welcome/i_courses.svg b/base/static/img/welcome/i_courses.svg new file mode 100644 index 000000000..d0039b732 --- /dev/null +++ b/base/static/img/welcome/i_courses.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_academy.svg b/base/static/img/welcome/i_hex_blue_academy.svg new file mode 100644 index 000000000..6cc870033 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_academy.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_api.svg b/base/static/img/welcome/i_hex_blue_api.svg new file mode 100644 index 000000000..c1a66d894 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_api.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_database.svg b/base/static/img/welcome/i_hex_blue_database.svg new file mode 100644 index 000000000..33eef6da8 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_database.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_docs.svg b/base/static/img/welcome/i_hex_blue_docs.svg new file mode 100644 index 000000000..709f3fbb5 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_docs.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_factsheets.svg b/base/static/img/welcome/i_hex_blue_factsheets.svg new file mode 100644 index 000000000..733220657 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_factsheets.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_ontology.svg b/base/static/img/welcome/i_hex_blue_ontology.svg new file mode 100644 index 000000000..79907578e --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_ontology.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_repo.svg b/base/static/img/welcome/i_hex_blue_repo.svg new file mode 100644 index 000000000..f6fe310a5 --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_repo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_blue_scenario_bundles.svg b/base/static/img/welcome/i_hex_blue_scenario_bundles.svg new file mode 100644 index 000000000..7c594a89b --- /dev/null +++ b/base/static/img/welcome/i_hex_blue_scenario_bundles.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_light_analysis.svg b/base/static/img/welcome/i_hex_light_analysis.svg new file mode 100644 index 000000000..c79487359 --- /dev/null +++ b/base/static/img/welcome/i_hex_light_analysis.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/base/static/img/welcome/i_hex_light_workflow.svg b/base/static/img/welcome/i_hex_light_workflow.svg new file mode 100644 index 000000000..fca2cccd1 --- /dev/null +++ b/base/static/img/welcome/i_hex_light_workflow.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_questions.svg b/base/static/img/welcome/i_questions.svg new file mode 100644 index 000000000..048f7c697 --- /dev/null +++ b/base/static/img/welcome/i_questions.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/base/static/img/welcome/i_tutorials.svg b/base/static/img/welcome/i_tutorials.svg new file mode 100644 index 000000000..788af5529 --- /dev/null +++ b/base/static/img/welcome/i_tutorials.svg @@ -0,0 +1,4 @@ + + + + diff --git a/base/templates/base/_header.html b/base/templates/base/_header.html index 448c4093f..ee1f7d4cf 100644 --- a/base/templates/base/_header.html +++ b/base/templates/base/_header.html @@ -11,7 +11,7 @@ logo