diff --git a/src/App/AppHeader/index.js b/src/App/AppHeader/index.js
index 8561df231a..592b7eb7cd 100644
--- a/src/App/AppHeader/index.js
+++ b/src/App/AppHeader/index.js
@@ -6,15 +6,11 @@ import routes from "../routes/all";
import SearchBox from "../utils/SearchBox";
-import swedbankpayLogo from "@src/img/swedbankpay/logo/swedbankpay-logo-h.svg";
-import payexLogo from "@src/img/payex/logo/payex-logo.svg";
-
-const brand = process.env.brand;
-const devLogo = brand === "swedbankpay" ? swedbankpayLogo : payexLogo;
-const isDev = process.env.version === "LOCAL_DEV";
-
const basename = process.env.basename;
+const brand = process.env.brand;
+// feature toggle. Switch once we switch default to topbar v2 (and update rest of docs and code)
+// other corresponding feature toggle for topbar at "src/App/utils/SelectPanel/index.js"
const useTopbarLegacy = true;
// mobile & tablet topbar and hamburger menu
diff --git a/src/App/ComponentsDocumentation/components/Topbar/constants.js b/src/App/ComponentsDocumentation/components/Topbar/constants.js
index 8dfe13fbda..191930391d 100644
--- a/src/App/ComponentsDocumentation/components/Topbar/constants.js
+++ b/src/App/ComponentsDocumentation/components/Topbar/constants.js
@@ -117,7 +117,6 @@ export const topbarShowcase = {
title: "Desktop",
description: (
- {/* TODO: mention it's legacy topbar and it all involve to use this in terms of breaking changes */}
The minimum requirement in a Topbar is to include the Swedbank Pay
Logotype, common additional functionality is a list with navigation
links. On desktop use{" "}
@@ -133,7 +132,6 @@ export const topbarShowcase = {
description: (
<>
- {/* TODO: mention it's legacy topbar and it all involve to use this in terms of breaking changes */}
The minimum requirement in a Topbar is to include the Swedbank Pay
Logotype, common additional functionality is a list with navigation
links. On smaller screens use a menu button to toggle a vertical
@@ -155,11 +153,8 @@ export const topbarShowcase = {
title: "Desktop",
description: (
- The minimum requirement in a Topbar is to include the Swedbank Pay
- Logotype, common additional functionality is a list with navigation
- links. On desktop use{" "}
- to show the links
- listed horizontally in the topbar.{" "}
+ The experimental desktop topbar involves breaking changes. Make sure
+ to check them out before switching.
),
},
@@ -169,19 +164,8 @@ export const topbarShowcase = {
title: "Mobile/tablet",
description: (
<>
-
- The minimum requirement in a Topbar is to include the Swedbank Pay
- Logotype, common additional functionality is a list with navigation
- links. On smaller screens use a menu button to toggle a vertical
- navigation drawer with links when the menu button is clicked.
-
-
- Be aware; The {" "}
- attribute for element {" "}
- when it is active is set to 2500px. This is to ensure animation for
- the transition to happen. You can easily alter this by creating
- custom css.
-
+ The experimental desktop topbar involves breaking changes. Make sure
+ to check them out before switching.
>
),
},
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js
index 9612da40a2..aacfcd08ca 100644
--- a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js
+++ b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js
@@ -8,9 +8,9 @@ test("Topbar page exist", async ({ page }) => {
name: "Components Find all currently available components here",
})
.click();
- await expect(page.getByRole("link", { name: "Topbar" })).toHaveCount(
- page.viewportSize().width < 991 ? 1 : 2
- );
+ await expect(
+ page.getByRole("link", { name: "Topbar", exact: true })
+ ).toHaveCount(page.viewportSize().width < 991 ? 1 : 2);
await page.getByText("call_to_actionTopbararrow_forward").click();
await expect(page).toHaveTitle(/Topbar/);
await expect(
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-closed-chromium-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-closed-chromium-darwin.png
deleted file mode 100644
index 60bc89d57a..0000000000
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-closed-chromium-darwin.png and /dev/null differ
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-links-ui-feedbacks-chromium-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-links-ui-feedbacks-chromium-darwin.png
deleted file mode 100644
index 69fafd1398..0000000000
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-links-ui-feedbacks-chromium-darwin.png and /dev/null differ
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-opened-chromium-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-opened-chromium-darwin.png
deleted file mode 100644
index 2ef4fee8ed..0000000000
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-desktop-opened-chromium-darwin.png and /dev/null differ
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-legacy-mobile-opened-webkit-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-legacy-mobile-opened-webkit-darwin.png
index ab2736b89f..9cac506809 100644
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-legacy-mobile-opened-webkit-darwin.png and b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-legacy-mobile-opened-webkit-darwin.png differ
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-closed-chromium-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-closed-chromium-darwin.png
deleted file mode 100644
index f65abe708d..0000000000
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-closed-chromium-darwin.png and /dev/null differ
diff --git a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-opened-chromium-darwin.png b/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-opened-chromium-darwin.png
deleted file mode 100644
index 7dd6c47b58..0000000000
Binary files a/src/App/ComponentsDocumentation/components/Topbar/topbar.e2e.spec.js-snapshots/SwedbankPay-topbar-mobile-opened-chromium-darwin.png and /dev/null differ
diff --git a/src/App/ComponentsDocumentation/components/TopbarMigratingToV2/index.js b/src/App/ComponentsDocumentation/components/TopbarMigratingToV2/index.js
index ce8e2ba06e..d1d70fd7af 100644
--- a/src/App/ComponentsDocumentation/components/TopbarMigratingToV2/index.js
+++ b/src/App/ComponentsDocumentation/components/TopbarMigratingToV2/index.js
@@ -1,5 +1,4 @@
-import React, { useEffect } from "react";
-import { Link } from "react-router-dom";
+import React from "react";
import { EditableComponentPreview, DocContainer } from "@docutils";
import CodeTags from "@components/CodeTags";
@@ -80,7 +79,8 @@ export const Migration = () => (
{"\n"}
{"\n"}
- {/* */}
+ {"// open/close menu button "}
+ {"\n"}
(
{"\n"}
{"\n"}
-
- {/* */}
+ {"// logo link to homepage "}
+ {"\n"}
{"\n"}
(
{"\n"}
{"\n"}
-
- {/* */}
+ {"// topbar/modal content "}
+ {"\n"}
{"\n"}
{"\n"}
- {/* */}
+ {"// content "}
+ {"\n"}
{"\n"}
@@ -142,7 +143,8 @@ export const Migration = () => (
{"\n"}
{"\n"}
- {/* */}
+ {"// logo link to homepage "}
+ {"\n"}
{"\n"}
(
{"\n"}
- {/* */}
+ {"// topbar/modal content "}
+ {"\n"}
{"\n"}
{"\n"}
- {/* */}
+ {"// links content "}
+ {"\n"}
{"\n"}
{"\n"}
- {/* */}
+ {"// open menu button "}
+ {"\n"}
{
}
};
-const TopbarBtn = ({ legacy = true }) => {
- return (
- <>
-
- {"\n\t\t"}
- menu
+const TopbarBtn = ({ legacy = true }) => (
+ <>
+
+ {"\n\t\t"}
+ menu
+ {"\n\t\t"}
+
+ {legacy && (
+
+ {"\n"}
+ close
{"\n\t\t"}
- {legacy && (
-
- {"\n"}
- close
- {"\n\t\t"}
-
- )}
- >
- );
-};
+ )}
+ >
+);
const ConditionalWrapper = ({ condition, wrapper, children }) =>
condition ? wrapper(children) : children;
diff --git a/src/App/routes/components.js b/src/App/routes/components.js
index 66383da406..120d261517 100644
--- a/src/App/routes/components.js
+++ b/src/App/routes/components.js
@@ -340,7 +340,7 @@ module.exports = [
componentPath: "components/TopbarMigratingToV2",
icon: "call_to_action",
outlined: true,
- statusBadges: ["javascript"],
+ statusBadges: ["javascript", "new"],
},
],
},
diff --git a/src/less/components/topbar-experimental.less b/src/less/components/topbar-experimental.less
new file mode 100644
index 0000000000..40cdfff640
--- /dev/null
+++ b/src/less/components/topbar-experimental.less
@@ -0,0 +1,522 @@
+@import "../global.less";
+
+.topbar.experimental {
+ --topbar-height: 60px;
+ --topbar-border-width: 0.5rem;
+ --topbar-opened-padding: 24px;
+ --topbar-opened-padding-body: 30px;
+ --topbar-spacing-horizontal: 32px;
+ --topbar-links-container-spacing: 60px;
+ --topbar-max-width: 960px;
+ --border-radius-topbar: 24px;
+ --border-radius-topbar-nav: 32px;
+
+ // TODO: once color-mix get enough support we can replace this by CSS var. Postcss does not parse a color-mix fallback if css-var (since cannot predict ahead of time the dynamic aspect of it)
+ height: var(--topbar-height);
+ width: calc(100% - 2 * var(--topbar-spacing-horizontal, 32px));
+ max-width: var(--topbar-max-width, 960px);
+ z-index: calc(var(--topbar-z-index, 400) - 1);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 0 1.5rem;
+ position: relative;
+ border-radius: 0 0 var(--border-radius-topbar, 24px)
+ var(--border-radius-topbar, 24px);
+ margin: 0 auto;
+
+ &::before {
+ content: "";
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ backdrop-filter: blur(10px) brightness(1.1);
+ z-index: -1;
+ background-color: color-mix(in srgb, @brand-bg-gray, transparent 35%);
+ border-radius: 0 0 var(--border-radius-topbar, 24px)
+ var(--border-radius-topbar, 24px);
+ }
+
+ .nav-container {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ &.topbar-sticky {
+ position: sticky;
+ top: 0;
+ }
+
+ .topbar-nav-closing
+ :is(.topbar-modal-header, .topbar-link-container, .topbar-modal-footer) {
+ visibility: hidden;
+ }
+
+ // LESS func to generate classes for triggering sticky starting from a breakpoints
+ each(@grid-breakpoints, .(@min-width, @infix) {
+ &.topbar-min-@{infix}-sticky {
+ @media screen and (min-width: @min-width) {
+ .topbar-sticky();
+ }
+ }
+ });
+
+ // LESS func to generate classes for triggering sticky ending at a breakpoint
+ each(@grid-breakpoints-max, .(@max-width, @infix) {
+ &.topbar-max-@{infix}-sticky {
+ @media screen and (max-width: @max-width) {
+ .topbar-sticky();
+ }
+ }
+ });
+
+ .topbar-logo {
+ background-size: cover;
+ border: none;
+ display: flex;
+
+ & img {
+ height: 32px;
+ width: 67px;
+ }
+ }
+
+ & .topbar-btn {
+ user-select: none;
+ background: none;
+ padding: 0;
+ border: 0;
+ align-self: center;
+ font-weight: bold;
+
+ &:focus {
+ border-radius: 0.125rem;
+ box-shadow: 0 0 0 2px @black;
+ outline: none;
+ }
+ }
+
+ // once :has() is supported, we can remove the script that add inline-style display: none/flex to .topbar-btn when open & close
+ &:has(.topbar-nav-open) .topbar-btn {
+ display: none;
+ }
+
+ // hamburger menu btn to open the topbar-nav dialog
+ .topbar-btn {
+ display: flex;
+ outline: 1px solid transparent;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+
+ // topbar-link-right is the class for the first link aligned on the right side
+ > .topbar-link-right {
+ display: none;
+ }
+
+ // topbar-nav is the container for links in both topbar up top and when dialog opened
+ .topbar-nav {
+ position: fixed;
+ inset: 0;
+ width: 100vw;
+ height: 100vh;
+ background: transparent;
+ display: none;
+
+ &.topbar-nav-closing {
+ animation: fade-out ease-in-out 0.3s forwards;
+ }
+
+ // topbar when dialog is opened
+ &.topbar-nav-open {
+ animation: fade-in ease-in-out 0.3s forwards;
+ position: fixed;
+ display: flex;
+ justify-content: flex-end;
+
+ .topbar-link-container {
+ animation-name: slide-in-from-right;
+ animation-duration: 0.4s;
+ animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
+ position: relative;
+ padding: 0;
+ border-width: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ width: calc(100% - var(--topbar-links-container-spacing, 60px));
+
+ > .topbar-modal-body {
+ background-color: var(--white, #ffffff);
+ flex-direction: column;
+ align-items: stretch;
+ padding: var(--topbar-opened-padding, 24px)
+ calc(var(--topbar-opened-padding-body, 30px) - 10px)
+ var(--topbar-opened-padding, 24px)
+ var(--topbar-opened-padding-body, 30px);
+ flex: 1;
+ border-top: 1px solid var(--gray);
+ border-bottom: 1px solid var(--gray);
+
+ .topbar-link-right {
+ margin: initial;
+
+ .material-icons {
+ margin: 0;
+ }
+ }
+
+ // links in open modal
+ > a {
+ font-size: 1.125rem;
+ padding: 1rem 0;
+ border-bottom: 1px solid
+ color-mix(in srgb, @brand-secondary, transparent 60%);
+
+ &:first-of-type {
+ padding-top: 0;
+ }
+ }
+
+ > button {
+ margin-top: 0.75rem;
+
+ &:first-of-type {
+ margin-top: auto;
+ }
+ }
+ }
+
+ > :is(.topbar-modal-header, .topbar-modal-footer) {
+ display: flex;
+ background-color: var(--white, #ffffff);
+ padding: var(--topbar-opened-padding, 24px);
+ }
+
+ .topbar-modal-header {
+ justify-content: flex-end;
+ border-radius: var(--border-radius-topbar-nav, 32px) 0 0 0;
+
+ & > button.topbar-close {
+ height: var(--topbar-spacing-horizontal, 32px);
+ width: var(--topbar-spacing-horizontal, 32px);
+ background-color: var(--gray);
+ border: transparent;
+
+ > i {
+ font-size: 24px;
+ }
+ }
+ }
+
+ .topbar-modal-footer {
+ justify-content: center;
+ border-radius: 0 0 0 var(--border-radius-topbar-nav, 32px);
+
+ > button {
+ width: 220px;
+ }
+ }
+ }
+ }
+
+ .topbar-link-container {
+ z-index: var(--topbar-z-index, 400);
+ width: 100%;
+
+ .topbar-modal-body {
+ display: flex;
+ justify-items: center start;
+ top: 0;
+ bottom: 0;
+ background-color: var(--white);
+ overflow-x: hidden;
+ overflow-y: auto;
+ overscroll-behavior: contain;
+
+ > a {
+ font-size: 1rem;
+ color: @brand-secondary;
+ cursor: pointer;
+ text-decoration: none;
+ display: flex;
+ gap: 0.5rem;
+ line-height: 1;
+ align-items: center;
+
+ > span {
+ font-family: var(--brand-headline);
+ font-weight: var(--font-weight-normal);
+
+ // for :before underline effect
+ position: relative;
+
+ // :before underline effect
+ &:before {
+ content: "";
+ position: absolute;
+ background-color: currentcolor;
+ height: 3px;
+ bottom: -4px;
+ left: 0;
+ right: 0;
+ margin-left: auto;
+ margin-right: auto;
+ width: 0;
+ }
+ }
+
+ // :hover underline expand width effects in non-opened topbar links
+ &:hover {
+ > span {
+ &:before {
+ display: block;
+ width: 100%;
+ transition: width 0.4s;
+ }
+
+ text-decoration: none;
+ }
+ }
+
+ // :active underline permanently displayed primary color
+ &.active {
+ > span {
+ &:before {
+ width: 100%;
+ background-color: var(--brand-primary);
+ }
+
+ text-decoration: none;
+ color: @black;
+ }
+ }
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+ }
+
+ @supports not selector(:has(a)) {
+ > .topbar-link-right {
+ margin-left: auto;
+ }
+ }
+
+ @supports selector(:has(a)) {
+ > .topbar-link-right,
+ &:not(&:has(.topbar-link-right)) button:first-of-type {
+ margin-left: auto;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ LESS mixin function scoped for the topbar on wider viewport, generated by the topbar mixin
+ 1. Create a mixin called .topbar-@{infix}-wide
+ 2. For each breakpoint in @grid-breakpoints, create a selector called .topbar-@{infix}-wide
+ 3. For each selector, create a media query for the breakpoint
+ 4. Inside each media query, call the mixin .topbar-wide()
+ */
+ // TODO: try to refactor it to make it more readable and not use LESS mixin, but native CSS
+
+ each(@grid-breakpoints, .(@min-width, @infix) {
+ &.topbar-@{infix}-wide:not(.legacy) {
+ @media screen and (min-width: @min-width) {
+ .topbar-wide();
+ }
+ }
+ });
+
+ .topbar-wide {
+ --topbar-height: 88px;
+ --modal-nav-width: 480px;
+
+ padding: 0 var(--topbar-spacing-horizontal);
+
+ .topbar-logo img {
+ height: var(--topbar-spacing-horizontal);
+ width: auto;
+ }
+
+ .topbar-nav {
+ display: flex;
+ position: static;
+ flex-grow: 1;
+ height: 100%;
+
+ &.topbar-nav-open {
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ justify-content: center;
+ align-items: center;
+
+ .topbar-link-container {
+ width: var(--modal-nav-width, 480px);
+ height: max-content;
+ max-height: calc(
+ 100% - 2 * var(--topbar-links-container-spacing, 60px)
+ );
+ margin: var(--topbar-links-container-spacing, 60px);
+ padding: 0;
+
+ .topbar-modal-body {
+ overflow-y: auto;
+ scrollbar-width: thin;
+ scrollbar-color: var(--brown-soft) transparent;
+ scrollbar-gutter: stable;
+
+ &::-webkit-scrollbar {
+ background-color: transparent;
+ width: 10px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: var(--brown-soft);
+ border-radius: 5rem;
+ }
+
+ > a,
+ > a:not(.pinned) {
+ display: flex;
+ font-size: 1.25rem;
+ padding: 1.5rem 0;
+
+ &:first-of-type {
+ padding-top: 0;
+ }
+ &:last-of-type {
+ padding-bottom: 0;
+ }
+ }
+ }
+
+ :is(.topbar-modal-header, .topbar-modal-footer) {
+ }
+
+ .topbar-modal-header {
+ border-radius: var(--border-radius-topbar-nav, 32)
+ var(--border-radius-topbar-nav, 32) 0 0;
+ }
+
+ .topbar-modal-footer {
+ border-radius: 0 0 var(--border-radius-topbar-nav, 32)
+ var(--border-radius-topbar-nav, 32);
+ }
+ }
+ }
+
+ // links container when in topbar only, not opened in dialog
+ &:not(.topbar-nav-open) .topbar-link-container {
+ .topbar-modal-body {
+ position: static;
+ background-color: transparent;
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ gap: 2rem;
+ padding: 0 2rem 0 3rem;
+ overflow: visible;
+
+ :is(a, button):not(.pinned) {
+ display: none;
+ }
+ }
+
+ :is(.topbar-modal-header, .topbar-modal-footer) {
+ display: none;
+ }
+ }
+ }
+ }
+
+ @keyframes fade-in {
+ 0% {
+ backdrop-filter: blur(0);
+ background-color: transparent;
+ }
+
+ 33% {
+ background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ }
+
+ 100% {
+ backdrop-filter: blur(20px);
+ background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ }
+ }
+
+ @keyframes fade-out {
+ 0% {
+ backdrop-filter: blur(20px);
+ background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ position: fixed;
+ inset: 0;
+ width: 100vw;
+ height: 100vh;
+ }
+
+ 1% {
+ backdrop-filter: blur(20px);
+ }
+
+ 33% {
+ backdrop-filter: blur(20px);
+ background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ }
+
+ 99% {
+ position: fixed;
+ inset: 0;
+ width: 100vw;
+ height: 100vh;
+ background: transparent;
+ }
+
+ 100% {
+ backdrop-filter: blur(0);
+ background-color: transparent;
+ }
+ }
+
+ @keyframes slide-in-from-right {
+ from {
+ transform: translateX(100%);
+ }
+
+ to {
+ transform: translateX(0);
+ }
+ }
+
+ @media (prefers-reduced-motion) {
+ // TODO: once finish animations / transition -> go through each & disable any animation/transition here
+ .topbar:not(.legacy)
+ nav.topbar-nav:is(.topbar-nav-open, .topbar-nav-closing) {
+ animation-duration: 0ms;
+
+ & > .topbar-link-container {
+ animation-duration: 0ms;
+ }
+ }
+ }
+
+ @media (forced-colors: active) {
+ a {
+ border-bottom: 1px solid;
+
+ &:focus,
+ &:hover,
+ &.active {
+ border-bottom: 4px solid;
+ }
+ }
+ }
+}
diff --git a/src/less/components/topbar-legacy.less b/src/less/components/topbar-legacy.less
deleted file mode 100644
index 20d39cf1ce..0000000000
--- a/src/less/components/topbar-legacy.less
+++ /dev/null
@@ -1,721 +0,0 @@
-@import "../global.less";
-
-@topbar-height: 80px;
-@topbar-border-width: 0.5rem;
-@topbar-header-height: calc(@topbar-height + @topbar-border-width);
-@topbar-border-top: @topbar-border-width solid @brand-primary;
-@topbar-link-container-width: 288px;
-
-.topbar:not(.experimental) {
- border-top: @topbar-border-top;
- background-color: @white;
- margin: 0 auto;
- height: @topbar-height;
- width: 100%;
- z-index: var(--topbar-z-index, 400);
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 0 1.25rem;
- position: relative;
-
- .nav-container {
- display: flex;
- width: 100%;
- justify-content: center;
- }
-
- &.topbar-sticky {
- position: sticky;
- top: 0;
- box-shadow: 0 4px 4px rgba(227, 209, 195, 0.25);
- }
-
- each(@grid-breakpoints, .(@min-width, @infix) {
- &.topbar-min-@{infix}-sticky {
- @media screen and (min-width: @min-width) {
- .topbar-sticky();
- }
- }
- });
-
- each(@grid-breakpoints-max, .(@max-width, @infix) {
- &.topbar-max-@{infix}-sticky {
- @media screen and (max-width: @max-width) {
- .topbar-sticky();
- }
- }
- });
-
- .topbar-logo {
- background-size: cover;
- border: none;
- display: flex;
-
- &.topbar-logo-png {
- justify-content: center;
- }
-
- .logotype-vertical {
- @media (max-width: @screen-xs-max) {
- width: 1.5rem;
- }
- }
- }
-
- .topbar-btn {
- user-select: none;
- background: none;
- font-weight: bold;
- display: flex;
- position: absolute;
- left: 1rem;
- padding: 0;
- border: 0;
- outline: 1px solid transparent;
- align-self: center;
-
- &:hover {
- cursor: pointer;
- }
-
- &:focus {
- border-radius: 0.125rem;
- box-shadow: 0 0 0 2px @black;
- outline: none;
- }
-
- &:last-child {
- span {
- margin-right: 0.2rem;
- }
- }
- }
-
- .topbar-close {
- display: none;
- user-select: none;
- background: none;
- font-weight: bold;
- position: absolute;
- left: 1.25rem;
- padding: 0;
- border: 0;
- outline: 0;
- cursor: pointer;
- align-self: center;
-
- &:hover {
- color: var(--brand-secondary);
- text-decoration: none;
- }
-
- &:focus,
- &.focus {
- border-radius: 0.125rem;
- box-shadow: 0 0 0 2px @black;
- outline: none;
- }
-
- &[active],
- &:active,
- &.active {
- outline: 0;
- background-image: none;
- box-shadow: none;
-
- &:focus,
- &.focus {
- box-shadow: none;
- }
- }
-
- .material-icons {
- margin: 0;
- }
- }
-
- > .topbar-link-right {
- display: none;
- }
-
- .topbar-nav {
- position: absolute;
- top: calc(
- (@topbar-height + @topbar-border-width) - 16px
- ); // - 16px is due to the drop shadow of the sticky topbar
- right: 0;
- width: 100%;
- height: calc(100vh - (@topbar-height + @topbar-border-width - 8px));
- background: transparent;
- display: none;
-
- .sidebar {
- display: none;
- position: relative;
- height: 100%;
- margin-top: 0;
- top: 0;
- padding-left: 1rem;
-
- &.has-secondary-nav {
- padding-right: 0;
- }
-
- &.sidebar-topbar-sticky {
- top: @topbar-height;
-
- .sidebar-nav {
- max-height: calc((100vh - @topbar-height));
- }
- }
-
- each(@grid-breakpoints, .(@min-width, @infix) {
- &.sidebar-topbar-min-@{infix}-sticky {
- @media screen and (min-width: @min-width) {
- .sidebar-topbar-sticky();
- }
- }
- });
-
- each(@grid-breakpoints-max, .(@max-width, @infix) {
- &.sidebar-topbar-max-@{infix}-sticky {
- @media screen and (max-width: @max-width) {
- .sidebar-topbar-sticky();
- }
- }
- });
-
- .sidebar-nav {
- max-height: none;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
-
- .main-nav-ul {
- list-style: none;
- padding: 0;
-
- .nav-group {
- .nav-ul-active() {
- > .nav-ul {
- max-height: 2500px;
- transition: max-height 1.5s ease-in-out;
- visibility: visible;
- }
- }
-
- .nav-heading-active() {
- color: @brand-secondary;
-
- i {
- transform: rotate(90deg);
- transition: transform 0.3s;
- }
- }
-
- &.active {
- .nav-ul-active();
-
- > .nav-group-heading {
- .nav-heading-active();
- }
- }
-
- .nav-group-heading {
- all: unset;
- display: flex;
- padding: 0.5rem;
- padding-left: 0;
- border: 2px solid transparent;
- font-weight: var(--font-weight-bold);
- line-height: 1.5rem;
-
- i {
- margin-right: 0.5rem;
- }
-
- &:hover,
- &:focus {
- cursor: pointer;
-
- span {
- text-decoration: underline;
- }
- }
-
- &:focus {
- border: 2px solid @brand-secondary;
- border-radius: 2px;
- }
- }
-
- .nav-ul {
- list-style: none;
- padding-left: 0.75rem;
- max-height: 0;
- overflow: hidden;
- visibility: hidden;
-
- .nav-leaf {
- position: relative;
- display: flex;
- align-items: center;
- min-height: 2.5rem;
-
- &.active,
- &:hover {
- &:before {
- background-color: @brand-secondary;
- }
- }
-
- &:before {
- content: "";
- position: absolute;
- height: 100%;
- width: 0.125rem;
- left: 0;
- top: 0;
- background-color: @brand-bg-gray;
- }
-
- a {
- font-size: 0.875rem;
- line-height: 1.25rem;
- color: @brand-secondary;
- text-decoration: none;
- padding: 0.625rem 1.75rem;
- width: 100%;
- height: 100%;
- }
- }
- }
- }
- }
- }
- }
-
- .topbar-nav-header {
- position: relative;
- display: none;
- height: @topbar-header-height;
- justify-content: center;
- align-items: center;
- background-color: @white;
-
- .topbar-close {
- top: calc((@topbar-header-height / 2) - (var(--font-size-large) / 2));
- left: 1rem;
- }
- }
-
- .topbar-close {
- top: 1rem;
- right: 2rem;
- left: auto;
- display: inline-flex;
- align-items: center;
- position: absolute;
- font-weight: var(--font-weight-normal);
- font-family: var(--brand-headline);
- text-align: center;
- text-decoration: none;
- touch-action: manipulation;
- cursor: pointer;
- line-height: 1rem;
- border: 1px solid transparent;
- white-space: nowrap;
- user-select: none;
- background-color: transparent;
- margin-right: -0.5rem;
-
- &:hover,
- &:focus,
- &.focus {
- color: var(--brand-secondary);
- text-decoration: none;
- }
-
- &[active],
- &:active,
- &.active {
- outline: 0;
- background-image: none;
- box-shadow: none;
-
- &:focus,
- &.focus {
- box-shadow: none;
- }
- }
-
- .material-icons {
- margin: 0;
- }
- }
-
- &.topbar-nav-open {
- animation: fade-in-legacy 0.5s forwards;
- border-top: solid 1px @brand-bg-gray;
-
- .topbar-link-container {
- animation: slide-in-legacy 0.5s ease forwards;
-
- .sidebar {
- display: block;
- box-shadow: none;
- }
-
- .topbar-nav-header {
- display: flex;
- }
-
- > a:first-of-type {
- margin-top: 1rem;
- }
-
- > a {
- color: @brand-secondary;
- padding-left: 1rem;
-
- span {
- margin-left: 1rem;
- }
-
- .material-icons + span {
- margin-left: 0;
- }
- }
-
- .topbar-link-right {
- margin: initial;
-
- .material-icons {
- margin: 0;
- }
- }
- }
- }
-
- &.topbar-nav-closing {
- animation: fade-out-legacy 0.3s forwards;
-
- .topbar-link-container {
- animation: slide-out-legacy 0.3s ease alternate;
-
- > a:first-of-type {
- margin-top: 1rem;
- }
- }
- }
-
- .topbar-link-container {
- width: @topbar-link-container-width;
- position: absolute;
- top: 0;
- bottom: 0;
- background-color: @white;
- overflow-x: hidden;
- overflow-y: auto;
- z-index: var(--topbar-z-index, 400);
- padding: 0;
- align-items: center;
- transform: translateX(-100%);
-
- .sidebar:not(:first-child) {
- margin-left: 1.5rem;
- }
-
- > a {
- font-family: var(--brand-headline);
- font-weight: var(--font-weight-normal);
- font-size: 1.125rem;
- color: @text-gray;
- cursor: pointer;
- text-decoration: none;
- display: flex;
- padding: 0.75rem 0;
- line-height: 1;
- align-items: center;
-
- .material-icons {
- padding: 0 0.5rem 0 0;
- user-select: none;
- }
-
- &:hover {
- > span {
- &:before {
- display: none;
- }
-
- text-decoration: underline;
- }
- }
-
- &.active {
- > span {
- text-decoration: underline;
- }
- }
- }
-
- .topbar-link-right {
- margin-left: auto;
- color: @black;
-
- .material-icons {
- margin: 0;
- }
- }
-
- .close-topbar-nav {
- position: absolute;
- user-select: none;
- top: 1.5rem;
- right: 2rem;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
- }
-
- &.topbar-xl-wide {
- padding: 0 1.5rem;
- }
- .topbar-wide {
- .topbar-btn {
- display: none;
- }
-
- .topbar-logo {
- margin-top: 0;
- margin-right: 2rem;
- }
-
- .topbar-link-right {
- margin-left: auto;
- padding: 0;
- align-items: center;
- font-family: var(--brand-headline);
- font-weight: var(--font-weight-normal);
- color: var(--brand-secondary);
- cursor: pointer;
- text-decoration: none;
- display: flex;
- }
-
- .topbar-nav {
- display: flex;
- position: static;
- flex-grow: 1;
- height: 100%;
-
- .topbar-close {
- display: none;
- }
-
- .topbar-link-container {
- position: static;
- background-color: transparent;
- width: 100%;
- display: flex;
- padding: 0;
- overflow: visible;
- transform: translateX(0%);
-
- > a:not(.close-topbar-nav) {
- margin-top: 8px;
-
- &:hover {
- > span {
- &:before {
- display: block;
- width: 100%;
- transition: width 0.4s;
- }
-
- text-decoration: none;
- }
- }
-
- &.active {
- > span {
- &:before {
- width: 100%;
- }
-
- text-decoration: none;
- color: @black;
- }
- }
-
- > span {
- position: relative;
-
- &:before {
- content: "";
- position: absolute;
- background-color: @brand-primary;
- height: 4px;
- bottom: -4px;
- left: 0;
- right: 0;
- margin-left: auto;
- margin-right: auto;
- width: 0;
- }
- }
-
- &:not(.topbar-link-right) {
- .material-icons,
- &.material-icons {
- display: none;
- }
- }
- }
-
- > *:not(.close-topbar-nav):not(.topbar-link-right) {
- text-decoration: none;
- margin-left: 1rem;
- margin-right: 1rem;
- }
-
- .close-topbar-nav {
- display: none;
- }
- }
- }
- }
-
- each(@grid-breakpoints, .(@min-width, @infix) {
- &.topbar-@{infix}-wide {
- @media screen and (min-width: @min-width) {
- .topbar-wide();
- }
- }
- });
-
- // Keyframe animations
- @keyframes slide-in-legacy {
- 100% {
- transform: translateX(0%);
- }
- }
-
- @keyframes slide-out-legacy {
- 0% {
- transform: translateX(0%);
- }
-
- 100% {
- transform: translateX(-100%);
- }
- }
-
- @keyframes fade-in-legacy {
- 0% {
- background: transparent;
- }
-
- 100% {
- background: fade(@black, 50%);
- }
- }
-
- @keyframes fade-out-legacy {
- 0% {
- background: fade(@black, 50%);
- }
-
- 100% {
- background: transparent;
- }
- }
-
- @media (prefers-reduced-motion) {
- .topbar {
- .topbar-nav {
- .sidebar {
- .sidebar-nav {
- .main-nav-ul {
- .nav-group {
- .nav-ul-active() {
- > .nav-ul {
- transition: max-height 0s ease-in-out;
- }
- }
- }
- }
- }
- }
-
- &.topbar-nav-open {
- animation: fade-in-legacy 0s forwards;
-
- .topbar-link-container {
- animation: slide-in-legacy 0s ease forwards;
- }
- }
-
- &.topbar-nav-closing {
- animation: fade-out-legacy 0s forwards;
-
- .topbar-link-container {
- animation: slide-out-legacy 0s ease alternate;
- }
- }
- }
- }
- }
-
- @media (forced-colors: active) {
- #dg-topbar {
- border-bottom: 3px solid;
- }
-
- .topbar-link-container {
- border: 10px solid;
- }
-
- .topbar {
- .topbar-close {
- outline: 2px solid;
-
- &:hover,
- &:focus,
- &.focus {
- outline: 2px solid;
- }
-
- &[active],
- &:active,
- &.active {
- outline: 2px solid;
- }
-
- &:focus,
- &.focus {
- outline: 2px solid;
- }
- }
- }
-
- .nav-group {
- .nav-leaf {
- a {
- border-bottom: 1px solid;
-
- &:focus,
- &:hover,
- &.active {
- border-bottom: 4px solid;
- }
- }
- }
- }
- }
-}
diff --git a/src/less/components/topbar.less b/src/less/components/topbar.less
index 8b2b4bfb13..bffc0a3e00 100644
--- a/src/less/components/topbar.less
+++ b/src/less/components/topbar.less
@@ -1,349 +1,512 @@
-@import url("../global.less");
-@import url("./topbar-legacy.less");
-
-.topbar.experimental {
- --topbar-height: 60px;
- --topbar-border-width: 0.5rem;
- --topbar-opened-padding: 24px;
- --topbar-opened-padding-body: 30px;
- --topbar-spacing-horizontal: 32px;
- --topbar-links-container-spacing: 60px;
- --topbar-max-width: 960px;
- --border-radius-topbar: 24px;
- --border-radius-topbar-nav: 32px;
-
- // TODO: once color-mix get enough support we can replace this by CSS var. Postcss does not parse a color-mix fallback if css-var (since cannot predict ahead of time the dynamic aspect of it)
- height: var(--topbar-height);
- width: calc(100% - 2 * var(--topbar-spacing-horizontal, 32px));
- max-width: var(--topbar-max-width, 960px);
- z-index: calc(var(--topbar-z-index, 400) - 1);
+@import "../global.less";
+@import "./topbar-experimental.less";
+
+@topbar-height: 80px;
+@topbar-border-width: 0.5rem;
+@topbar-header-height: calc(@topbar-height + @topbar-border-width);
+@topbar-border-top: @topbar-border-width solid @brand-primary;
+@topbar-link-container-width: 288px;
+
+.topbar:not(.experimental) {
+ border-top: @topbar-border-top;
+ background-color: @white;
+ margin: 0 auto;
+ height: @topbar-height;
+ width: 100%;
+ z-index: var(--topbar-z-index, 400);
display: flex;
justify-content: center;
align-items: center;
- padding: 0 1.5rem;
+ padding: 0 1.25rem;
position: relative;
- border-radius: 0 0 var(--border-radius-topbar, 24px)
- var(--border-radius-topbar, 24px);
- margin: 0 auto;
-
- &::before {
- content: "";
- position: absolute;
- width: 100%;
- height: 100%;
- backdrop-filter: blur(10px) brightness(1.1);
- z-index: -1;
- background-color: color-mix(in srgb, @brand-bg-gray, transparent 35%);
- border-radius: 0 0 var(--border-radius-topbar, 24px)
- var(--border-radius-topbar, 24px);
- }
.nav-container {
display: flex;
width: 100%;
- justify-content: space-between;
- align-items: center;
+ justify-content: center;
}
&.topbar-sticky {
position: sticky;
top: 0;
+ box-shadow: 0 4px 4px rgba(227, 209, 195, 0.25);
}
- .topbar-nav-closing
- :is(.topbar-modal-header, .topbar-link-container, .topbar-modal-footer) {
- visibility: hidden;
- }
-
- // LESS func to generate classes for triggering sticky starting from a breakpoints
each(@grid-breakpoints, .(@min-width, @infix) {
- &.topbar-min-@{infix}-sticky {
- @media screen and (min-width: @min-width) {
- .topbar-sticky();
- }
- }
- });
+ &.topbar-min-@{infix}-sticky {
+ @media screen and (min-width: @min-width) {
+ .topbar-sticky();
+ }
+ }
+ });
- // LESS func to generate classes for triggering sticky ending at a breakpoint
each(@grid-breakpoints-max, .(@max-width, @infix) {
- &.topbar-max-@{infix}-sticky {
- @media screen and (max-width: @max-width) {
- .topbar-sticky();
- }
- }
- });
+ &.topbar-max-@{infix}-sticky {
+ @media screen and (max-width: @max-width) {
+ .topbar-sticky();
+ }
+ }
+ });
.topbar-logo {
background-size: cover;
border: none;
display: flex;
- & img {
- height: 32px;
- width: 67px;
+ &.topbar-logo-png {
+ justify-content: center;
+ }
+
+ .logotype-vertical {
+ @media (max-width: @screen-xs-max) {
+ width: 1.5rem;
+ }
}
}
- & .topbar-btn {
+ .topbar-btn {
user-select: none;
background: none;
+ font-weight: bold;
+ display: flex;
+ position: absolute;
+ left: 1rem;
padding: 0;
border: 0;
+ outline: 1px solid transparent;
align-self: center;
- font-weight: bold;
+
+ &:hover {
+ cursor: pointer;
+ }
&:focus {
border-radius: 0.125rem;
box-shadow: 0 0 0 2px @black;
outline: none;
}
- }
- // once :has() is supported, we can remove the script that add inline-style display: none/flex to .topbar-btn when open & close
- &:has(.topbar-nav-open) .topbar-btn {
- display: none;
+ &:last-child {
+ span {
+ margin-right: 0.2rem;
+ }
+ }
}
- // hamburger menu btn to open the topbar-nav dialog
- .topbar-btn {
- display: flex;
- outline: 1px solid transparent;
+ .topbar-close {
+ display: none;
+ user-select: none;
+ background: none;
+ font-weight: bold;
+ position: absolute;
+ left: 1.25rem;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ cursor: pointer;
+ align-self: center;
&:hover {
- cursor: pointer;
+ color: var(--brand-secondary);
+ text-decoration: none;
+ }
+
+ &:focus,
+ &.focus {
+ border-radius: 0.125rem;
+ box-shadow: 0 0 0 2px @black;
+ outline: none;
+ }
+
+ &[active],
+ &:active,
+ &.active {
+ outline: 0;
+ background-image: none;
+ box-shadow: none;
+
+ &:focus,
+ &.focus {
+ box-shadow: none;
+ }
+ }
+
+ .material-icons {
+ margin: 0;
}
}
- // topbar-link-right is the class for the first link aligned on the right side
> .topbar-link-right {
display: none;
}
- // topbar-nav is the container for links in both topbar up top and when dialog opened
.topbar-nav {
- position: fixed;
- inset: 0;
- width: 100vw;
- height: 100vh;
+ position: absolute;
+ top: calc(
+ (@topbar-height + @topbar-border-width) - 16px
+ ); // - 16px is due to the drop shadow of the sticky topbar
+ right: 0;
+ width: 100%;
+ height: calc(100vh - (@topbar-height + @topbar-border-width - 8px));
background: transparent;
display: none;
- &.topbar-nav-closing {
- animation: fade-out ease-in-out 0.3s forwards;
- }
+ .sidebar {
+ display: none;
+ position: relative;
+ height: 100%;
+ margin-top: 0;
+ top: 0;
+ padding-left: 1rem;
- // topbar when dialog is opened
- &.topbar-nav-open {
- animation: fade-in ease-in-out 0.3s forwards;
- position: fixed;
- display: flex;
- justify-content: flex-end;
+ &.has-secondary-nav {
+ padding-right: 0;
+ }
- .topbar-link-container {
- animation-name: slide-in-from-right;
- animation-duration: 0.4s;
- animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
- position: relative;
- padding: 0;
- border-width: 0;
+ &.sidebar-topbar-sticky {
+ top: @topbar-height;
+
+ .sidebar-nav {
+ max-height: calc((100vh - @topbar-height));
+ }
+ }
+
+ each(@grid-breakpoints, .(@min-width, @infix) {
+ &.sidebar-topbar-min-@{infix}-sticky {
+ @media screen and (min-width: @min-width) {
+ .sidebar-topbar-sticky();
+ }
+ }
+ });
+
+ each(@grid-breakpoints-max, .(@max-width, @infix) {
+ &.sidebar-topbar-max-@{infix}-sticky {
+ @media screen and (max-width: @max-width) {
+ .sidebar-topbar-sticky();
+ }
+ }
+ });
+
+ .sidebar-nav {
+ max-height: none;
+ overflow-y: auto;
display: flex;
flex-direction: column;
- align-items: stretch;
- width: calc(100% - var(--topbar-links-container-spacing, 60px));
-
- > .topbar-modal-body {
- background-color: var(--white, #ffffff);
- flex-direction: column;
- align-items: stretch;
- padding: var(--topbar-opened-padding, 24px)
- calc(var(--topbar-opened-padding-body, 30px) - 10px)
- var(--topbar-opened-padding, 24px)
- var(--topbar-opened-padding-body, 30px);
- flex: 1;
- border-top: 1px solid var(--gray);
- border-bottom: 1px solid var(--gray);
-
- .topbar-link-right {
- margin: initial;
-
- .material-icons {
- margin: 0;
+
+ .main-nav-ul {
+ list-style: none;
+ padding: 0;
+
+ .nav-group {
+ .nav-ul-active() {
+ > .nav-ul {
+ max-height: 2500px;
+ transition: max-height 1.5s ease-in-out;
+ visibility: visible;
+ }
}
- }
- // links in open modal
- > a {
- font-size: 1.125rem;
- padding: 1rem 0;
- border-bottom: 1px solid
- color-mix(in srgb, @brand-secondary, transparent 60%);
+ .nav-heading-active() {
+ color: @brand-secondary;
- &:first-of-type {
- padding-top: 0;
+ i {
+ transform: rotate(90deg);
+ transition: transform 0.3s;
+ }
}
- }
- > button {
- margin-top: 0.75rem;
+ &.active {
+ .nav-ul-active();
- &:first-of-type {
- margin-top: auto;
+ > .nav-group-heading {
+ .nav-heading-active();
+ }
}
- }
- }
- > :is(.topbar-modal-header, .topbar-modal-footer) {
- display: flex;
- background-color: var(--white, #ffffff);
- padding: var(--topbar-opened-padding, 24px);
- }
+ .nav-group-heading {
+ all: unset;
+ display: flex;
+ padding: 0.5rem;
+ padding-left: 0;
+ border: 2px solid transparent;
+ font-weight: var(--font-weight-bold);
+ line-height: 1.5rem;
+
+ i {
+ margin-right: 0.5rem;
+ }
- .topbar-modal-header {
- justify-content: flex-end;
- border-radius: var(--border-radius-topbar-nav, 32px) 0 0 0;
+ &:hover,
+ &:focus {
+ cursor: pointer;
- & > button.topbar-close {
- height: var(--topbar-spacing-horizontal, 32px);
- width: var(--topbar-spacing-horizontal, 32px);
- background-color: var(--gray);
- border: transparent;
+ span {
+ text-decoration: underline;
+ }
+ }
- > i {
- font-size: 24px;
+ &:focus {
+ border: 2px solid @brand-secondary;
+ border-radius: 2px;
+ }
+ }
+
+ .nav-ul {
+ list-style: none;
+ padding-left: 0.75rem;
+ max-height: 0;
+ overflow: hidden;
+ visibility: hidden;
+
+ .nav-leaf {
+ position: relative;
+ display: flex;
+ align-items: center;
+ min-height: 2.5rem;
+
+ &.active,
+ &:hover {
+ &:before {
+ background-color: @brand-secondary;
+ }
+ }
+
+ &:before {
+ content: "";
+ position: absolute;
+ height: 100%;
+ width: 0.125rem;
+ left: 0;
+ top: 0;
+ background-color: @brand-bg-gray;
+ }
+
+ a {
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: @brand-secondary;
+ text-decoration: none;
+ padding: 0.625rem 1.75rem;
+ width: 100%;
+ height: 100%;
+ }
+ }
}
}
}
+ }
+ }
- .topbar-modal-footer {
- justify-content: center;
- border-radius: 0 0 0 var(--border-radius-topbar-nav, 32px);
+ .topbar-nav-header {
+ position: relative;
+ display: none;
+ height: @topbar-header-height;
+ justify-content: center;
+ align-items: center;
+ background-color: @white;
+
+ .topbar-close {
+ top: calc((@topbar-header-height / 2) - (var(--font-size-large) / 2));
+ left: 1rem;
+ }
+ }
- > button {
- width: 220px;
- }
+ .topbar-close {
+ top: 1rem;
+ right: 2rem;
+ left: auto;
+ display: inline-flex;
+ align-items: center;
+ position: absolute;
+ font-weight: var(--font-weight-normal);
+ font-family: var(--brand-headline);
+ text-align: center;
+ text-decoration: none;
+ touch-action: manipulation;
+ cursor: pointer;
+ line-height: 1rem;
+ border: 1px solid transparent;
+ white-space: nowrap;
+ user-select: none;
+ background-color: transparent;
+ margin-right: -0.5rem;
+
+ &:hover,
+ &:focus,
+ &.focus {
+ color: var(--brand-secondary);
+ text-decoration: none;
+ }
+
+ &[active],
+ &:active,
+ &.active {
+ outline: 0;
+ background-image: none;
+ box-shadow: none;
+
+ &:focus,
+ &.focus {
+ box-shadow: none;
}
}
+
+ .material-icons {
+ margin: 0;
+ }
}
- .topbar-link-container {
- z-index: var(--topbar-z-index, 400);
- width: 100%;
+ &.topbar-nav-open {
+ animation: fade-in-legacy 0.5s forwards;
+ border-top: solid 1px @brand-bg-gray;
- .topbar-modal-body {
- display: flex;
- justify-items: center start;
- top: 0;
- bottom: 0;
- background-color: var(--white);
- overflow-x: hidden;
- overflow-y: auto;
- overscroll-behavior: contain;
+ .topbar-link-container {
+ animation: slide-in-legacy 0.5s ease forwards;
- > a {
- font-size: 1rem;
- color: @brand-secondary;
- cursor: pointer;
- text-decoration: none;
+ .sidebar {
+ display: block;
+ box-shadow: none;
+ }
+
+ .topbar-nav-header {
display: flex;
- gap: 0.5rem;
- line-height: 1;
- align-items: center;
+ }
- > span {
- font-family: var(--brand-headline);
- font-weight: var(--font-weight-normal);
+ > a:first-of-type {
+ margin-top: 1rem;
+ }
- // for :before underline effect
- position: relative;
+ > a {
+ color: @brand-secondary;
+ padding-left: 1rem;
- // :before underline effect
- &:before {
- content: "";
- position: absolute;
- background-color: currentcolor;
- height: 3px;
- bottom: -4px;
- left: 0;
- right: 0;
- margin-left: auto;
- margin-right: auto;
- width: 0;
- }
+ span {
+ margin-left: 1rem;
}
- // :hover underline expand width effects in non-opened topbar links
- &:hover {
- > span {
- &:before {
- display: block;
- width: 100%;
- transition: width 0.4s;
- }
+ .material-icons + span {
+ margin-left: 0;
+ }
+ }
- text-decoration: none;
- }
+ .topbar-link-right {
+ margin: initial;
+
+ .material-icons {
+ margin: 0;
}
+ }
+ }
+ }
- // :active underline permanently displayed primary color
- &.active {
- > span {
- &:before {
- width: 100%;
- background-color: var(--brand-primary);
- }
+ &.topbar-nav-closing {
+ animation: fade-out-legacy 0.3s forwards;
- text-decoration: none;
- color: @black;
+ .topbar-link-container {
+ animation: slide-out-legacy 0.3s ease alternate;
+
+ > a:first-of-type {
+ margin-top: 1rem;
+ }
+ }
+ }
+
+ .topbar-link-container {
+ width: @topbar-link-container-width;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ background-color: @white;
+ overflow-x: hidden;
+ overflow-y: auto;
+ z-index: var(--topbar-z-index, 400);
+ padding: 0;
+ align-items: center;
+ transform: translateX(-100%);
+
+ .sidebar:not(:first-child) {
+ margin-left: 1.5rem;
+ }
+
+ > a {
+ font-family: var(--brand-headline);
+ font-weight: var(--font-weight-normal);
+ font-size: 1.125rem;
+ color: @text-gray;
+ cursor: pointer;
+ text-decoration: none;
+ display: flex;
+ padding: 0.75rem 0;
+ line-height: 1;
+ align-items: center;
+
+ .material-icons {
+ padding: 0 0.5rem 0 0;
+ user-select: none;
+ }
+
+ &:hover {
+ > span {
+ &:before {
+ display: none;
}
- }
- &:last-of-type {
- border-bottom: none;
+ text-decoration: underline;
}
}
- @supports not selector(:has(a)) {
- > .topbar-link-right {
- margin-left: auto;
+ &.active {
+ > span {
+ text-decoration: underline;
}
}
+ }
- @supports selector(:has(a)) {
- > .topbar-link-right,
- &:not(&:has(.topbar-link-right)) button:first-of-type {
- margin-left: auto;
- }
+ .topbar-link-right {
+ margin-left: auto;
+ color: @black;
+
+ .material-icons {
+ margin: 0;
}
}
- }
- }
- /*
- LESS mixin function scoped for the topbar on wider viewport, generated by the topbar mixin
- 1. Create a mixin called .topbar-@{infix}-wide
- 2. For each breakpoint in @grid-breakpoints, create a selector called .topbar-@{infix}-wide
- 3. For each selector, create a media query for the breakpoint
- 4. Inside each media query, call the mixin .topbar-wide()
- */
- // TODO: try to refactor it to make it more readable and not use LESS mixin, but native CSS
+ .close-topbar-nav {
+ position: absolute;
+ user-select: none;
+ top: 1.5rem;
+ right: 2rem;
- each(@grid-breakpoints, .(@min-width, @infix) {
- &.topbar-@{infix}-wide:not(.legacy) {
- @media screen and (min-width: @min-width) {
- .topbar-wide();
+ &:hover {
+ cursor: pointer;
}
+ }
}
- });
+ }
+ &.topbar-xl-wide {
+ padding: 0 1.5rem;
+ }
.topbar-wide {
- --topbar-height: 88px;
- --modal-nav-width: 480px;
+ .topbar-btn {
+ display: none;
+ }
- padding: 0 var(--topbar-spacing-horizontal);
+ .topbar-logo {
+ margin-top: 0;
+ margin-right: 2rem;
+ }
- .topbar-logo img {
- height: var(--topbar-spacing-horizontal);
- width: auto;
+ .topbar-link-right {
+ margin-left: auto;
+ padding: 0;
+ align-items: center;
+ font-family: var(--brand-headline);
+ font-weight: var(--font-weight-normal);
+ color: var(--brand-secondary);
+ cursor: pointer;
+ text-decoration: none;
+ display: flex;
}
.topbar-nav {
@@ -352,171 +515,207 @@
flex-grow: 1;
height: 100%;
- &.topbar-nav-open {
- width: 100vw;
- height: 100vh;
- position: fixed;
- justify-content: center;
- align-items: center;
+ .topbar-close {
+ display: none;
+ }
- .topbar-link-container {
- width: var(--modal-nav-width, 480px);
- height: max-content;
- max-height: calc(
- 100% - 2 * var(--topbar-links-container-spacing, 60px)
- );
- margin: var(--topbar-links-container-spacing, 60px);
- padding: 0;
+ .topbar-link-container {
+ position: static;
+ background-color: transparent;
+ width: 100%;
+ display: flex;
+ padding: 0;
+ overflow: visible;
+ transform: translateX(0%);
- .topbar-modal-body {
- overflow-y: auto;
- scrollbar-width: thin;
- scrollbar-color: var(--brown-soft) transparent;
- scrollbar-gutter: stable;
+ > a:not(.close-topbar-nav) {
+ margin-top: 8px;
- &::-webkit-scrollbar {
- background-color: transparent;
- width: 10px;
- }
+ &:hover {
+ > span {
+ &:before {
+ display: block;
+ width: 100%;
+ transition: width 0.4s;
+ }
- &::-webkit-scrollbar-thumb {
- background: var(--brown-soft);
- border-radius: 5rem;
+ text-decoration: none;
}
+ }
- > a,
- > a:not(.pinned) {
- display: flex;
- font-size: 1.25rem;
- padding: 1.5rem 0;
-
- &:first-of-type {
- padding-top: 0;
- }
- &:last-of-type {
- padding-bottom: 0;
+ &.active {
+ > span {
+ &:before {
+ width: 100%;
}
+
+ text-decoration: none;
+ color: @black;
}
}
- :is(.topbar-modal-header, .topbar-modal-footer) {
- }
+ > span {
+ position: relative;
- .topbar-modal-header {
- border-radius: var(--border-radius-topbar-nav, 32)
- var(--border-radius-topbar-nav, 32) 0 0;
+ &:before {
+ content: "";
+ position: absolute;
+ background-color: @brand-primary;
+ height: 4px;
+ bottom: -4px;
+ left: 0;
+ right: 0;
+ margin-left: auto;
+ margin-right: auto;
+ width: 0;
+ }
}
- .topbar-modal-footer {
- border-radius: 0 0 var(--border-radius-topbar-nav, 32)
- var(--border-radius-topbar-nav, 32);
+ &:not(.topbar-link-right) {
+ .material-icons,
+ &.material-icons {
+ display: none;
+ }
}
}
- }
- // links container when in topbar only, not opened in dialog
- &:not(.topbar-nav-open) .topbar-link-container {
- .topbar-modal-body {
- position: static;
- background-color: transparent;
- width: 100%;
- display: flex;
- justify-content: flex-start;
- gap: 2rem;
- padding: 0 2rem 0 3rem;
- overflow: visible;
-
- :is(a, button):not(.pinned) {
- display: none;
- }
+ > *:not(.close-topbar-nav):not(.topbar-link-right) {
+ text-decoration: none;
+ margin-left: 1rem;
+ margin-right: 1rem;
}
- :is(.topbar-modal-header, .topbar-modal-footer) {
+ .close-topbar-nav {
display: none;
}
}
}
}
- @keyframes fade-in {
- 0% {
- backdrop-filter: blur(0);
- background-color: transparent;
- }
-
- 33% {
- background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ each(@grid-breakpoints, .(@min-width, @infix) {
+ &.topbar-@{infix}-wide {
+ @media screen and (min-width: @min-width) {
+ .topbar-wide();
+ }
}
+ });
+ // Keyframe animations
+ @keyframes slide-in-legacy {
100% {
- backdrop-filter: blur(20px);
- background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ transform: translateX(0%);
}
}
- @keyframes fade-out {
+ @keyframes slide-out-legacy {
0% {
- backdrop-filter: blur(20px);
- background-color: color-mix(in srgb, @brand-primary, transparent 40%);
- position: fixed;
- inset: 0;
- width: 100vw;
- height: 100vh;
+ transform: translateX(0%);
}
- 1% {
- backdrop-filter: blur(20px);
- }
-
- 33% {
- backdrop-filter: blur(20px);
- background-color: color-mix(in srgb, @brand-primary, transparent 40%);
+ 100% {
+ transform: translateX(-100%);
}
+ }
- 99% {
- position: fixed;
- inset: 0;
- width: 100vw;
- height: 100vh;
+ @keyframes fade-in-legacy {
+ 0% {
background: transparent;
}
100% {
- backdrop-filter: blur(0);
- background-color: transparent;
+ background: fade(@black, 50%);
}
}
- @keyframes slide-in-from-right {
- from {
- transform: translateX(100%);
+ @keyframes fade-out-legacy {
+ 0% {
+ background: fade(@black, 50%);
}
- to {
- transform: translateX(0);
+ 100% {
+ background: transparent;
}
}
@media (prefers-reduced-motion) {
- // TODO: once finish animations / transition -> go through each & disable any animation/transition here
- .topbar:not(.legacy)
- nav.topbar-nav:is(.topbar-nav-open, .topbar-nav-closing) {
- animation-duration: 0ms;
+ .topbar {
+ .topbar-nav {
+ .sidebar {
+ .sidebar-nav {
+ .main-nav-ul {
+ .nav-group {
+ .nav-ul-active() {
+ > .nav-ul {
+ transition: max-height 0s ease-in-out;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &.topbar-nav-open {
+ animation: fade-in-legacy 0s forwards;
- & > .topbar-link-container {
- animation-duration: 0ms;
+ .topbar-link-container {
+ animation: slide-in-legacy 0s ease forwards;
+ }
+ }
+
+ &.topbar-nav-closing {
+ animation: fade-out-legacy 0s forwards;
+
+ .topbar-link-container {
+ animation: slide-out-legacy 0s ease alternate;
+ }
+ }
}
}
}
@media (forced-colors: active) {
- a {
- border-bottom: 1px solid;
+ #dg-topbar {
+ border-bottom: 3px solid;
+ }
- &:focus,
- &:hover,
- &.active {
- border-bottom: 4px solid;
+ .topbar-link-container {
+ border: 10px solid;
+ }
+
+ .topbar {
+ .topbar-close {
+ outline: 2px solid;
+
+ &:hover,
+ &:focus,
+ &.focus {
+ outline: 2px solid;
+ }
+
+ &[active],
+ &:active,
+ &.active {
+ outline: 2px solid;
+ }
+
+ &:focus,
+ &.focus {
+ outline: 2px solid;
+ }
+ }
+ }
+
+ .nav-group {
+ .nav-leaf {
+ a {
+ border-bottom: 1px solid;
+
+ &:focus,
+ &:hover,
+ &.active {
+ border-bottom: 4px solid;
+ }
+ }
}
}
}
diff --git a/src/less/documentation-swedbankpay.less b/src/less/documentation-swedbankpay.less
index 3e62e8585d..35d4ae0c6d 100644
--- a/src/less/documentation-swedbankpay.less
+++ b/src/less/documentation-swedbankpay.less
@@ -1058,11 +1058,15 @@
}
}
+ // TODO: delete once support for has() is good enough
+ // which means probably around mid-January 2024 for FF support on FF v.120 (Nov 2023) + 2 versions
@supports not selector(:has(a, b)) {
+ div.d-flex > div.d-flex {
max-width: 100%;
}
}
+
+ // prevents components inside doc component preview to overflow outside the component-preview container
@supports selector(:has(a, b)) {
+ div > div:has(> .component-preview) {
max-width: 100%;