diff --git a/deployments/mit-ol/mfe_slot_config/frontend/mitx/public/index.html b/deployments/mit-ol/mfe_slot_config/frontend/mitx/public/index.html index 870979a8..12903b85 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/mitx/public/index.html +++ b/deployments/mit-ol/mfe_slot_config/frontend/mitx/public/index.html @@ -1,6 +1,8 @@ + + MITx diff --git a/deployments/mit-ol/mfe_slot_config/frontend/mitxonline/public/index.html b/deployments/mit-ol/mfe_slot_config/frontend/mitxonline/public/index.html index 99a98add..cb104b2e 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/mitxonline/public/index.html +++ b/deployments/mit-ol/mfe_slot_config/frontend/mitxonline/public/index.html @@ -1,6 +1,8 @@ + + MIT OpenLearning diff --git a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/footer/index.tsx b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/footer/index.tsx index 03a4a0c5..6686530d 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/footer/index.tsx +++ b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/footer/index.tsx @@ -1,10 +1,6 @@ -import { - useSiteConfig, - WidgetOperationTypes, - LayoutOperationTypes, -} from "@openedx/frontend-base"; +import { Slot, useSiteConfig, WidgetOperationTypes } from "@openedx/frontend-base"; import type { App, SlotOperation } from "@openedx/frontend-base"; -import { Hyperlink } from "@openedx/paragon"; +import { Hyperlink, Image } from "@openedx/paragon"; /** * Shape of the MIT OL footer config expected in @@ -19,6 +15,8 @@ export interface MITOLFooterConfig { supportUrl?: string; accessibilityUrl?: string; copyrightText?: string; + footerLogoUrl?: string; + footerLogoDestination?: string; } function useMITOLFooterConfig(): MITOLFooterConfig { @@ -29,109 +27,256 @@ function useMITOLFooterConfig(): MITOLFooterConfig { function CopyrightNotice() { const { copyrightText } = useMITOLFooterConfig(); - if (!copyrightText) return null; - return
{copyrightText}
; + // Support a `{year}` placeholder in the configured copyright text so the year + // stays current without a code change (e.g. "© {year} MIT xPRO. All rights + // reserved."). Text without the placeholder is rendered verbatim. + const text = copyrightText?.replace( + "{year}", + String(new Date().getFullYear()), + ); + return ( +
+ {text &&
{text}
} +
+ edX and Open edX are registered trademarks of edX LLC. +
+
+ ); } -function AboutLink() { - const { aboutUrl } = useMITOLFooterConfig(); - if (!aboutUrl) return null; - return About Us; +/** + * Footer logo (left side). Reads footerLogoUrl from the runtime config; + * falls back to the shell's default (headerLogoImageUrl) if not set. + */ +function FooterLogo() { + const { footerLogoUrl, footerLogoDestination } = useMITOLFooterConfig(); + const { headerLogoImageUrl, siteName } = useSiteConfig(); + const src = footerLogoUrl || headerLogoImageUrl; + if (!src) return null; + const img = ( + {siteName + ); + if (footerLogoDestination) { + return {img}; + } + return img; } -function SupportLink() { - const { supportUrl } = useMITOLFooterConfig(); - if (!supportUrl) return null; - return Contact; +/** Recreation of the shell's PoweredBy widget (it is not exported from the root). */ +function PoweredBy() { + return ( + + Powered by Open edX + + ); } -function AccessibilityLink() { - const { accessibilityUrl } = useMITOLFooterConfig(); - if (!accessibilityUrl) return null; - return Accessibility; -} +/** + * Custom desktop footer layout replacing the shell's DesktopFooterLayout so we + * match the legacy learning MFE at every width: a 3-part row of logo (left), + * centered links, and the "Powered by Open edX" logo (right), with the + * copyright/trademark notice on a full-width centered row below. The row is + * intentionally NOT collapsed to a vertical stack on mobile so the placement + * mirrors legacy (the links themselves still stack — see MITOLFooterLinks). + * The shell layout used `justify-content-between` (a paragon-layer `!important` + * utility we cannot override from our site layer), which forced a large gap + * between the links and copyright and pushed the "Powered by" logo to the bottom. + */ +function MITOLDesktopFooterLayout() { + return ( + + ); } -function TermsOfServiceLink() { - const { termsOfServiceUrl } = useMITOLFooterConfig(); - if (!termsOfServiceUrl) return null; +/** + * Footer link types the MIT OL footer can render, each mapped to its display + * label and the runtime-config field holding its URL. + */ +export type FooterLinkKey = + | "about" + | "privacy" + | "honor" + | "tos" + | "accessibility" + | "help"; + +const FOOTER_LINK_DEFS: Record< + FooterLinkKey, + { label: string; field: keyof MITOLFooterConfig } +> = { + about: { label: "About Us", field: "aboutUrl" }, + privacy: { label: "Privacy Policy", field: "privacyPolicyUrl" }, + honor: { label: "Honor Code", field: "honorCodeUrl" }, + tos: { label: "Terms of Service", field: "termsOfServiceUrl" }, + accessibility: { label: "Accessibility", field: "accessibilityUrl" }, + help: { label: "Help", field: "supportUrl" }, +}; + +/** + * Default footer link set/order — the legacy learning MFE footer used by mitx + * and mitxonline (About Us · Terms of Service · Accessibility · Help). + * Deployments needing a different set pass `linkOrder` to createMITOLFooterApp + * (e.g. xPRO adds Privacy Policy + Honor Code). + */ +const DEFAULT_FOOTER_LINK_ORDER: FooterLinkKey[] = [ + "about", + "tos", + "accessibility", + "help", +]; + +/** + * Single centered horizontal row of footer links (no column labels), rendered + * in the given order. Each link is omitted if its URL is missing from the + * runtime config. + */ +function MITOLFooterLinks({ order }: { order: FooterLinkKey[] }) { + const config = useMITOLFooterConfig(); + const links = order + .map((key) => ({ + url: config[FOOTER_LINK_DEFS[key].field], + label: FOOTER_LINK_DEFS[key].label, + })) + .filter((link): link is { url: string; label: string } => + Boolean(link.url), + ); + if (links.length === 0) return null; return ( - Terms of Service + ); } -function HonorCodeLink() { - const { honorCodeUrl } = useMITOLFooterConfig(); - if (!honorCodeUrl) return null; - return Honor Code; -} - /** * Returns an App that injects MIT OL footer content into footerApp's slots. * All link URLs are read at render time from SiteConfig.commonAppConfig.mitolFooter, * populated via FRONTEND_SITE_CONFIG in the LMS Django settings. A widget renders * nothing if its URL is absent from the runtime config. */ -export function createMITOLFooterApp(): App { +export function createMITOLFooterApp(options?: { + /** Ordered footer link keys to render. Defaults to the mitx/mitxonline set. */ + linkOrder?: FooterLinkKey[]; +}): App { + const linkOrder = options?.linkOrder ?? DEFAULT_FOOTER_LINK_ORDER; + // Close over the resolved order so the slot widget (which the shell renders + // without props) shows this deployment's link set. + const FooterLinks = () => ; const slots: SlotOperation[] = [ + // Replace the shell's desktop footer layout with our own so we control the + // link/copyright spacing and place "Powered by Open edX" at the top right. { - slotId: "org.openedx.frontend.slot.footer.desktopLegalNotices.v1", - id: "mitol.footer.copyright", - op: WidgetOperationTypes.APPEND, - component: CopyrightNotice, + slotId: "org.openedx.frontend.slot.footer.desktop.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopLayout.v1", + id: "mitol.footer.desktopLayout", + op: WidgetOperationTypes.REPLACE, + component: MITOLDesktopFooterLayout, }, - // Column 1: Resources + // Remove the shell's default copyright line (e.g. "© 2026 MIT Learn (dev).") + // so only the MIT OL copyright + trademark notice remain, matching the + // legacy learning MFE footer. { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink1.v1", - op: LayoutOperationTypes.OPTIONS, - options: { label: "Resources" }, + slotId: "org.openedx.frontend.slot.footer.desktopLegalNotices.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopCopyrightNotice.v1", + op: WidgetOperationTypes.REMOVE, }, { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink1.v1", - id: "mitol.footer.col1.about", + slotId: "org.openedx.frontend.slot.footer.desktopLegalNotices.v1", + id: "mitol.footer.copyright", op: WidgetOperationTypes.APPEND, - component: AboutLink, + component: CopyrightNotice, }, + // Replace the shell's default logo (which uses headerLogoImageUrl) with + // our FooterLogo component that reads footerLogoUrl from the config. { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink1.v1", - id: "mitol.footer.col1.contact", - op: WidgetOperationTypes.APPEND, - component: SupportLink, + slotId: "org.openedx.frontend.slot.footer.desktopLeftLinks.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopLeftLinksLogo.v1", + id: "mitol.footer.logo", + op: WidgetOperationTypes.REPLACE, + component: FooterLogo, }, + // Single centered horizontal row of links (no column labels) matching + // the legacy learning MFE footer. Append directly to the center-links + // container (CenterLinks layout) instead of a desktopCenterLinkN.v1 slot + // so the links are NOT wrapped in frontend-base's LabeledLinkColumn + // (which forces `small` font + a flex column). Remove the 4 default + // column slots so only our row renders. { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink1.v1", - id: "mitol.footer.col1.accessibility", - op: WidgetOperationTypes.APPEND, - component: AccessibilityLink, + slotId: "org.openedx.frontend.slot.footer.desktopCenterLinks.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopCenterLink1.v1", + op: WidgetOperationTypes.REMOVE, }, - // Column 2: Policies { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink2.v1", - op: LayoutOperationTypes.OPTIONS, - options: { label: "Policies" }, + slotId: "org.openedx.frontend.slot.footer.desktopCenterLinks.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopCenterLink2.v1", + op: WidgetOperationTypes.REMOVE, }, { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink2.v1", - id: "mitol.footer.col2.privacy", - op: WidgetOperationTypes.APPEND, - component: PrivacyPolicyLink, + slotId: "org.openedx.frontend.slot.footer.desktopCenterLinks.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopCenterLink3.v1", + op: WidgetOperationTypes.REMOVE, }, { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink2.v1", - id: "mitol.footer.col2.tos", - op: WidgetOperationTypes.APPEND, - component: TermsOfServiceLink, + slotId: "org.openedx.frontend.slot.footer.desktopCenterLinks.v1", + relatedId: "org.openedx.frontend.widget.footer.desktopCenterLink4.v1", + op: WidgetOperationTypes.REMOVE, }, { - slotId: "org.openedx.frontend.slot.footer.desktopCenterLink2.v1", - id: "mitol.footer.col2.honor-code", + slotId: "org.openedx.frontend.slot.footer.desktopCenterLinks.v1", + id: "mitol.footer.links", op: WidgetOperationTypes.APPEND, - component: HonorCodeLink, + component: FooterLinks, }, ]; diff --git a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/header/index.tsx b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/header/index.tsx index 2c014438..36eba5ad 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/header/index.tsx +++ b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/header/index.tsx @@ -3,6 +3,7 @@ import { useSiteConfig, useAuthenticatedUser, WidgetOperationTypes, + Slot, } from "@openedx/frontend-base"; import type { App, SlotOperation } from "@openedx/frontend-base"; import { Dropdown, Hyperlink, Image } from "@openedx/paragon"; @@ -13,18 +14,28 @@ import { isLearnCourse, isMITxOnlineCourse } from "../utils/courseContext"; // --------------------------------------------------------------------------- const SLOT = { + desktop: "org.openedx.frontend.slot.header.desktop.v1", + mobile: "org.openedx.frontend.slot.header.mobile.v1", desktopLeft: "org.openedx.frontend.slot.header.desktopLeft.v1", desktopRight: "org.openedx.frontend.slot.header.desktopRight.v1", mobileCenter: "org.openedx.frontend.slot.header.mobileCenter.v1", + mobileRight: "org.openedx.frontend.slot.header.mobileRight.v1", secondaryLinks: "org.openedx.frontend.slot.header.secondaryLinks.v1", authenticatedMenu: "org.openedx.frontend.slot.header.authenticatedMenu.v1", } as const; const WIDGET = { + desktopLayout: "org.openedx.frontend.widget.header.desktopLayout.v1", + mobileLayout: "org.openedx.frontend.widget.header.mobileLayout.v1", desktopLogo: "org.openedx.frontend.widget.header.desktopLogo.v1", mobileLogo: "org.openedx.frontend.widget.header.mobileLogo.v1", desktopPrimaryLinks: "org.openedx.frontend.widget.header.desktopPrimaryLinks.v1", + desktopAuthenticatedMenu: + "org.openedx.frontend.widget.header.desktopAuthenticatedMenu.v1", + mobileAuthenticatedMenu: + "org.openedx.frontend.widget.header.mobileAuthenticatedMenu.v1", + help: "org.openedx.frontend.widget.header.help.v1", menuProfile: "org.openedx.frontend.widget.header.desktopAuthenticatedMenuProfile.v1", menuAccount: @@ -57,11 +68,18 @@ function useMITOLHeaderConfig(): MITOLHeaderConfig { const UserMenuToggle: FC = () => { const authenticatedUser = useAuthenticatedUser(); if (!authenticatedUser) return null; + const displayName = authenticatedUser.name || authenticatedUser.username; return ( (not a div) so the toggle is focusable and + // keyboard-activatable. aria-label gives it an accessible name in the + // icon-only state (the username is hidden below 992px — see the + // mitxonline.scss media query). + as="button" + type="button" + aria-label={displayName} id="user-nav-dropdown-custom" - className="d-flex align-items-center gap-2 cursor-pointer" + className="d-flex align-items-center gap-2 cursor-pointer bg-transparent" > {/* Person icon */} { fill="white" /> - - {authenticatedUser.name || authenticatedUser.username} - + {displayName} { ); }; +// --------------------------------------------------------------------------- +// Custom authenticated user menu — replaces the default AvatarButton toggle +// with UserMenuToggle (person icon + display name + chevron) while keeping the +// frontend-base authenticatedMenu slot for the dropdown items. +// --------------------------------------------------------------------------- + +const MITxOnlineAuthenticatedMenu: FC<{ className?: string }> = ({ + className, +}) => ( + + + + + + +); + +// --------------------------------------------------------------------------- +// Always-desktop header layout. The frontend-base shell swaps to a hamburger + +// centered-logo MobileLayout below 768px (via a JS media query). MIT OL keeps +// the desktop-style layout (logo left, course info, user menu right) at every +// width to match the rest of the platform, so we replace the shell's +// DesktopLayout with one that never applies `d-none` and replace MobileLayout +// with nothing. Narrow-width trimming is handled in the deployment SCSS. +// --------------------------------------------------------------------------- + +const AlwaysDesktopLayout: FC = () => ( + // Match the legacy header container exactly: a plain `.container-xl py-2` flex + // row. Paragon's can't emit `.container-xl` (its `fluid` prop is + // boolean-only, and `size="xl"` produces the wider `.container-mw-xl`), so we + // use a plain div — the same element the legacy header uses. `.container-xl` + // also lines up with the instructor-dashboard body (`#main-content.container-xl`). +
+
+ +
+
+ +
+
+); + +const NoMobileLayout: FC = () => null; + // --------------------------------------------------------------------------- // MITx Online header — full UAI/Learn course detection, custom logo, user menu // --------------------------------------------------------------------------- @@ -105,7 +165,10 @@ const MITxOnlineLogo: FC = () => { : `${marketingSiteBaseUrl ?? lmsBaseUrl}/dashboard/`; const { headerLogoImageUrl } = useSiteConfig(); return ( - + // `logo` class mirrors the legacy learning-header logo anchor so the + // mitxonline.scss `.logo img { height: 24px }` rule applies (matching the + // legacy 24px logo instead of the frontend-base default 2rem/32px). + { export function createMITxOnlineHeaderApp(): App { const slots: SlotOperation[] = [ + // Keep the desktop-style header layout at all widths (no mobile hamburger). + { + slotId: SLOT.desktop, + id: "mitol.header.mitxonline.desktopLayout", + relatedId: WIDGET.desktopLayout, + op: WidgetOperationTypes.REPLACE, + component: AlwaysDesktopLayout, + }, + { + slotId: SLOT.mobile, + id: "mitol.header.mitxonline.mobileLayout", + relatedId: WIDGET.mobileLayout, + op: WidgetOperationTypes.REPLACE, + component: NoMobileLayout, + }, // Replace desktop and mobile logo widgets with context-aware logo. { slotId: SLOT.desktopLeft, @@ -190,6 +268,28 @@ export function createMITxOnlineHeaderApp(): App { op: WidgetOperationTypes.PREPEND, component: MITxOnlineDashboardLink, }, + // Remove the default Help link from the header. + { + slotId: SLOT.secondaryLinks, + op: WidgetOperationTypes.REMOVE, + relatedId: WIDGET.help, + }, + // Replace the default avatar-button toggle with the custom MIT OL user menu + // (person icon + display name + chevron), on both desktop and mobile. + { + slotId: SLOT.desktopRight, + id: "mitol.header.mitxonline.desktopAuthenticatedMenu", + relatedId: WIDGET.desktopAuthenticatedMenu, + op: WidgetOperationTypes.REPLACE, + component: MITxOnlineAuthenticatedMenu, + }, + { + slotId: SLOT.mobileRight, + id: "mitol.header.mitxonline.mobileAuthenticatedMenu", + relatedId: WIDGET.mobileAuthenticatedMenu, + op: WidgetOperationTypes.REPLACE, + component: MITxOnlineAuthenticatedMenu, + }, // Replace all three default authenticated menu items with mitxonline-specific ones. { slotId: SLOT.authenticatedMenu, @@ -230,12 +330,6 @@ export function createMITxOnlineHeaderApp(): App { op: WidgetOperationTypes.APPEND, component: MITxOnlineLogoutMenuItem, }, - // TODO: Replace AuthenticatedMenu widget toggle with UserMenuToggle for custom SVG icon. - // Requires REPLACE on org.openedx.frontend.widget.header.desktopAuthenticatedMenu.v1 - // and org.openedx.frontend.widget.header.mobileAuthenticatedMenu.v1 — but these widgets - // embed both the toggle and the menu, so a full custom AuthenticatedMenu component is - // needed. Deferred until confirmed approach with UX. - // // TODO: Hide primary nav links on dashboard apps (gradebook, learner-dashboard). // This requires knowing which route roles those apps register. Add a condition with // condition: { active: [''] } once frontend-app-gradebook is a module. @@ -269,6 +363,22 @@ const MITxLogoutMenuItem: FC = () => { export function createMITxHeaderApp(): App { const slots: SlotOperation[] = [ + // Keep the desktop-style header layout at all widths (no mobile hamburger), + // matching the legacy MITx header. Narrow-width trimming is in mitx.scss. + { + slotId: SLOT.desktop, + id: "mitol.header.mitx.desktopLayout", + relatedId: WIDGET.desktopLayout, + op: WidgetOperationTypes.REPLACE, + component: AlwaysDesktopLayout, + }, + { + slotId: SLOT.mobile, + id: "mitol.header.mitx.mobileLayout", + relatedId: WIDGET.mobileLayout, + op: WidgetOperationTypes.REPLACE, + component: NoMobileLayout, + }, // Replace default menu items with LMS-based dashboard + logout. { slotId: SLOT.authenticatedMenu, @@ -346,6 +456,22 @@ const XProLogoutMenuItem: FC = () => { export function createXProHeaderApp(): App { const slots: SlotOperation[] = [ + // Keep the desktop-style header layout at all widths (no mobile hamburger), + // matching the legacy xPRO header. Narrow-width trimming is in mitx.scss. + { + slotId: SLOT.desktop, + id: "mitol.header.xpro.desktopLayout", + relatedId: WIDGET.desktopLayout, + op: WidgetOperationTypes.REPLACE, + component: AlwaysDesktopLayout, + }, + { + slotId: SLOT.mobile, + id: "mitol.header.xpro.mobileLayout", + relatedId: WIDGET.mobileLayout, + op: WidgetOperationTypes.REPLACE, + component: NoMobileLayout, + }, // Replace all default menu items with xPRO marketing-site links. { slotId: SLOT.authenticatedMenu, @@ -392,6 +518,3 @@ export function createXProHeaderApp(): App { return { appId: "mitol.header.xpro", slots }; } - -// Re-export for consumers that only need the shared toggle component. -export { UserMenuToggle }; diff --git a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitx.scss b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitx.scss index ba7ae8ae..e548856d 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitx.scss +++ b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitx.scss @@ -6,3 +6,69 @@ display: none; } } + +// Match the legacy MITx / xPRO header user menu, which shows just the username +// (no avatar). mitx and xpro use the default frontend-base AvatarButton toggle; +// hide its avatar image so only the username + caret remain. (mitxonline uses +// its own custom toggle — styled in mitxonline.scss — and is unaffected.) +header .pgn__avatar-button-avatar .pgn__avatar { + display: none !important; +} + +// Match the legacy header logo size (28px). The default frontend-base logo +// widget sets `max-height: 2rem` (32px) inline; override it. (The logo anchor +// links to "/"; mitxonline uses a custom logo so it's unaffected.) +header a[href="/"] img { + max-height: 1.75rem !important; +} + +// Match the legacy header height: its user-menu dropdown button is 48px (the +// tallest element in the row), while the frontend-base avatar button is ~44px. +// Bumping it makes the whole header 64px like legacy. +header .pgn__avatar-button-avatar { + min-height: 48px; +} + +// The default frontend-base Help widget renders as a full-height (64px) nav-link +// "tab" (height:64px + 18px vertical padding), which is taller than the 48px +// user-menu button and pushes the whole header to 80px. Legacy renders Help as a +// plain gray inline link (`text-gray-700`), not a tab. Reset the box to auto +// height / no vertical padding so the 48px user menu stays the tallest element +// and the header lands at 64px like legacy. The colour is already gray-700 +// (#454545), and the 16px right padding keeps the gap before the user menu. +header .secondary-nav-links .nav-link { + height: auto !important; + padding-top: 0 !important; + padding-bottom: 0 !important; + padding-left: 0 !important; + padding-right: 16px !important; +} + +// mitx and xpro keep the desktop-style header at all widths (AlwaysDesktopLayout +// in createMITxHeaderApp / createXProHeaderApp) to match the legacy header, +// which never collapses to a hamburger. At narrow widths, ellipsis-truncate the +// course number + title so the lockup stays one line each instead of wrapping +// and blowing up the header height (mirrors the legacy truncation). +@media (max-width: 768px) { + // Keep the always-desktop header on ONE row that fits the viewport. Let the + // left side (logo + course lockup) shrink (min-width:0 breaks the flex + // min-content floor) and ellipsis-truncate the course number + title to + // whatever space is left after the logo and right-side controls — otherwise + // the row overflows horizontally and opening the menu scrolls the logo off + // the left edge. The lockup is: + //
{number}{title}
+ header .d-flex.flex-grow-1, + header .nav:has(.course-title), + header div:has(> .course-title) { + min-width: 0; + } + header .nav:has(.course-title) { + overflow: hidden; + } + header div:has(> .course-title) > span { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} diff --git a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitxonline.scss b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitxonline.scss index 9e039a18..e256f80d 100644 --- a/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitxonline.scss +++ b/deployments/mit-ol/mfe_slot_config/frontend/shared/src/styles/mitxonline.scss @@ -1,16 +1,31 @@ -.learning-header, .site-header-desktop { +.learning-header, .site-header-desktop, header.border-bottom { background-color: #303337 !important; color: #FFF !important; font-family: neue-haas-grotesk-text, sans-serif !important; font-style: normal !important; font-size: 14px !important; line-height: 18px !important; + // Remove the shell's light-grey bottom border. The `.border-bottom` utility + // lives in the paragon cascade layer with !important, so a site-layer + // !important override cannot win; instead we zero the CSS variable it + // resolves (--pgn-size-border-width), which removes the line without fighting + // the cascade. Children with explicit borders (dropdown toggle/menu) are + // unaffected because they set their own border values. + --pgn-size-border-width: 0; + box-shadow: none !important; .user-dropdown .btn { height: 40px !important; } - .container-xl{ + // Match the legacy learning-header row height (72px). The intended 16px + // vertical padding loses to the `.py-2` utility on the container (it sets + // padding-top/bottom !important from an unlayered utility that our layered + // site rule can't outrank), so we also pin `min-height` — which no utility + // sets, so it always wins — and the row's `align-items-center` keeps the + // content vertically centred. 72px = 40px content + 16px×2. + .container-xl, .container-mw-xl, .container-fluid { padding: 16px 8px !important; + min-height: 72px !important; } .dropdown-toggle::after{ @@ -21,6 +36,11 @@ height: 24px !important; } + // Spacing between the Dashboard button group and the user menu dropdown. + .secondary-nav-links { + margin-right: 16px !important; + } + .font-weight-bold { font-weight: 400 !important; } @@ -38,6 +58,9 @@ align-items: center !important; gap: 8px; color: #FFF !important; + // Reset the native