diff --git a/frontends/main/src/app-pages/AboutPage/AboutPage.tsx b/frontends/main/src/app-pages/AboutPage/AboutPage.tsx
index 0c1aecdefb..0b011cc018 100644
--- a/frontends/main/src/app-pages/AboutPage/AboutPage.tsx
+++ b/frontends/main/src/app-pages/AboutPage/AboutPage.tsx
@@ -10,6 +10,7 @@ import {
import * as urls from "@/common/urls"
import React from "react"
import domeImage from "@/public/mit-dome-2.jpg"
+import Image from "next/image"
const WHAT_IS_MIT_OPEN_FRAGMENT_IDENTIFIER = "what-is-mit-learn"
const NON_DEGREE_LEARNING_FRAGMENT_IDENTIFIER = "non-degree-learning"
@@ -81,13 +82,15 @@ const SubHeaderTextContainer = styled.div({
alignSelf: "flex-start",
})
-const SubHeaderImage = styled.img({
+const SubHeaderImageContainer = styled.div({
flexGrow: 1,
alignSelf: "stretch",
+ position: "relative",
+})
+
+const SubHeaderImage = styled(Image)({
borderRadius: "8px",
- backgroundSize: "cover",
- backgroundPosition: "center",
- backgroundImage: `url(${domeImage.src})`,
+ objectFit: "cover",
[theme.breakpoints.down("md")]: {
height: "300px",
},
@@ -165,7 +168,13 @@ const AboutPage: React.FC = () => {
Continue your education at your own pace
-
+
+
+
diff --git a/frontends/main/src/app-pages/ChannelPage/ChannelPage.test.tsx b/frontends/main/src/app-pages/ChannelPage/ChannelPage.test.tsx
index fdd6177a76..2c85049974 100644
--- a/frontends/main/src/app-pages/ChannelPage/ChannelPage.test.tsx
+++ b/frontends/main/src/app-pages/ChannelPage/ChannelPage.test.tsx
@@ -379,7 +379,7 @@ describe("Channel Pages, Topic only", () => {
})
describe("Channel Pages, Unit only", () => {
- it("Displays the channel title, banner, and avatar", async () => {
+ it("Displays the channel title, banner", async () => {
const { channel } = setupApis({
search_filter: "offered_by=ocw",
channel_type: "unit",
@@ -388,9 +388,24 @@ describe("Channel Pages, Unit only", () => {
url: `/c/${channel.channel_type}/${channel.name}`,
})
- const title = await screen.findByRole("heading", { name: channel.title })
- getByImageSrc(title, `${window.origin}${channel.configuration.logo}`)
+ await screen.findByRole("heading", { name: channel.title })
})
+
+ it("Displays the channel logo", async () => {
+ const { channel } = setupApis({
+ name: "ocw",
+ channel_type: "unit",
+ })
+ renderWithProviders(, {
+ url: `/c/${channel.channel_type}/${channel.name}`,
+ })
+
+ const images = await screen.findAllByRole("img", {
+ name: "MIT OpenCourseWare",
+ })
+ expect(images[0]).toHaveAttribute("src", "/images/unit_logos/ocw.svg")
+ })
+
it("Displays a featured carousel if the channel type is 'unit'", async () => {
const { channel } = setupApis({
search_filter: "offered_by=ocw",
diff --git a/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx b/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx
index cc9cdbb121..4114a0b4f4 100644
--- a/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx
+++ b/frontends/main/src/app-pages/ChannelPage/DefaultChannelTemplate.tsx
@@ -1,5 +1,6 @@
import React from "react"
import { styled, Breadcrumbs, Banner } from "ol-components"
+import { backgroundSrcSetCSS } from "ol-utilities"
import { SearchSubscriptionToggle } from "@/page-components/SearchSubscriptionToggle/SearchSubscriptionToggle"
import { useChannelDetail } from "api/hooks/channels"
import ChannelMenu from "@/components/ChannelMenu/ChannelMenu"
@@ -10,6 +11,7 @@ import {
CHANNEL_TYPE_BREADCRUMB_TARGETS,
ChannelControls,
} from "./ChannelPageTemplate"
+import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
const ChildrenContainer = styled.div(({ theme }) => ({
paddingTop: "40px",
@@ -57,6 +59,7 @@ const DefaultChannelTemplate: React.FC = ({
const channel = useChannelDetail(String(channelType), String(name))
const urlParams = new URLSearchParams(channel.data?.search_filter)
const displayConfiguration = channel.data?.configuration
+
return (
<>
= ({
title={channel.data?.title}
header={displayConfiguration?.heading}
subHeader={displayConfiguration?.sub_heading}
- backgroundUrl={displayConfiguration?.banner_background}
+ backgroundUrl={
+ displayConfiguration?.banner_background ??
+ backgroundSrcSetCSS(backgroundSteps)
+ }
extraActions={
diff --git a/frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx b/frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx
index 412a25c23a..f4b2a5de69 100644
--- a/frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx
+++ b/frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx
@@ -23,8 +23,9 @@ import {
useLearningResourceTopic,
useLearningResourceTopics,
} from "api/hooks/learningResources"
-import { propsNotNil } from "ol-utilities"
+import { propsNotNil, backgroundSrcSetCSS } from "ol-utilities"
import invariant from "tiny-invariant"
+import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
const ChildrenContainer = styled.div(({ theme }) => ({
paddingTop: "40px",
@@ -222,6 +223,7 @@ const TopicChannelTemplateInternal: React.FC<
) : (
)
+
return (
<>
}
backgroundUrl={
displayConfiguration?.banner_background ??
- "/images/backgrounds/background_steps.jpg"
+ backgroundSrcSetCSS(backgroundSteps)
}
extraActions={
diff --git a/frontends/main/src/app-pages/ChannelPage/UnitChannelTemplate.tsx b/frontends/main/src/app-pages/ChannelPage/UnitChannelTemplate.tsx
index e939d42b29..d6e8b6c9e0 100644
--- a/frontends/main/src/app-pages/ChannelPage/UnitChannelTemplate.tsx
+++ b/frontends/main/src/app-pages/ChannelPage/UnitChannelTemplate.tsx
@@ -8,7 +8,9 @@ import {
BannerBackground,
Typography,
VisuallyHidden,
+ UnitLogo,
} from "ol-components"
+import { OfferedByEnum, SourceTypeEnum } from "api"
import { SearchSubscriptionToggle } from "@/page-components/SearchSubscriptionToggle/SearchSubscriptionToggle"
import { ChannelDetails } from "@/page-components/ChannelDetails/ChannelDetails"
import { useChannelDetail } from "api/hooks/channels"
@@ -16,7 +18,6 @@ import ChannelMenu from "@/components/ChannelMenu/ChannelMenu"
import ResourceCarousel, {
ResourceCarouselProps,
} from "@/page-components/ResourceCarousel/ResourceCarousel"
-import { SourceTypeEnum } from "api"
import { getSearchParamMap } from "@/common/utils"
import { HOME as HOME_URL, UNITS as UNITS_URL } from "../../common/urls"
import { ChannelTypeEnum } from "api/v0"
@@ -38,13 +39,13 @@ const FeaturedCoursesCarousel = styled(ResourceCarousel)(({ theme }) => ({
},
}))
-const UnitLogo = styled.img(({ theme }) => ({
+const UnitLogoInverted = styled(UnitLogo)(({ theme }) => ({
filter: "saturate(0%) invert(100%)",
+ height: 50,
maxWidth: "100%",
- width: "auto",
- height: "50px",
[theme.breakpoints.down("md")]: {
- height: "40px",
+ height: 40,
+ width: "auto",
},
}))
@@ -126,7 +127,10 @@ const UnitChannelTemplate: React.FC = ({
{channel.data?.title}
{channel.data ? (
-
+
) : null}
diff --git a/frontends/main/src/app-pages/DepartmentListingPage/DepartmentListingPage.tsx b/frontends/main/src/app-pages/DepartmentListingPage/DepartmentListingPage.tsx
index 32e308a1ea..8399d741db 100644
--- a/frontends/main/src/app-pages/DepartmentListingPage/DepartmentListingPage.tsx
+++ b/frontends/main/src/app-pages/DepartmentListingPage/DepartmentListingPage.tsx
@@ -13,7 +13,7 @@ import {
Banner,
Breadcrumbs,
} from "ol-components"
-import { pluralize } from "ol-utilities"
+import { pluralize, backgroundSrcSetCSS } from "ol-utilities"
import type { LearningResourceSchool } from "api"
import { useSchoolsList } from "api/hooks/learningResources"
import {
@@ -27,7 +27,7 @@ import {
RiTerminalBoxLine,
} from "@remixicon/react"
import { HOME } from "@/common/urls"
-
+import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
@@ -201,7 +201,6 @@ const DepartmentListingPage: React.FC = () => {
return (
<>
{
current="Departments"
/>
}
+ backgroundUrl={backgroundSrcSetCSS(backgroundSteps)}
/>
diff --git a/frontends/main/src/app-pages/HomePage/PersonalizeSection.tsx b/frontends/main/src/app-pages/HomePage/PersonalizeSection.tsx
index 93bd620af7..e20e788483 100644
--- a/frontends/main/src/app-pages/HomePage/PersonalizeSection.tsx
+++ b/frontends/main/src/app-pages/HomePage/PersonalizeSection.tsx
@@ -1,11 +1,14 @@
import React from "react"
import { Typography, styled, Container, ButtonLink } from "ol-components"
+import { backgroundSrcSetCSS } from "ol-utilities"
import { useUserMe } from "api/hooks/user"
import * as urls from "@/common/urls"
+import personalizeImage from "@/public/images/homepage/personalize-image.png"
+import personalizeBgImage from "@/public/images/homepage/personalize-bg.png"
const FullWidthBackground = styled.div(({ theme }) => ({
padding: "80px 0",
- background: 'url("/images/homepage/personalize-bg.png") center top no-repeat',
+ background: `${backgroundSrcSetCSS(personalizeBgImage)} center top no-repeat`,
backgroundSize: "cover",
[theme.breakpoints.down("md")]: {
padding: "40px 0",
@@ -108,7 +111,7 @@ const PersonalizeSection = () => {
return (
-
+
diff --git a/frontends/main/src/app-pages/LearningPathListingPage/LearningPathListingPage.tsx b/frontends/main/src/app-pages/LearningPathListingPage/LearningPathListingPage.tsx
index 94502ce32a..8c0066287d 100644
--- a/frontends/main/src/app-pages/LearningPathListingPage/LearningPathListingPage.tsx
+++ b/frontends/main/src/app-pages/LearningPathListingPage/LearningPathListingPage.tsx
@@ -84,11 +84,6 @@ const LearningPathListingPage: React.FC = () => {
src="/images/backgrounds/course_search_banner.png"
className="learningpaths-page"
>
- {/* TODO
-
-
-
- */}
diff --git a/frontends/main/src/app-pages/ProgramLetterPage/[id]/view/ProgramLetter.test.tsx b/frontends/main/src/app-pages/ProgramLetterPage/ProgramLetter.test.tsx
similarity index 100%
rename from frontends/main/src/app-pages/ProgramLetterPage/[id]/view/ProgramLetter.test.tsx
rename to frontends/main/src/app-pages/ProgramLetterPage/ProgramLetter.test.tsx
diff --git a/frontends/main/src/app-pages/ProgramLetterPage/[id]/view/ProgramLetterPage.tsx b/frontends/main/src/app-pages/ProgramLetterPage/ProgramLetterPage.tsx
similarity index 100%
rename from frontends/main/src/app-pages/ProgramLetterPage/[id]/view/ProgramLetterPage.tsx
rename to frontends/main/src/app-pages/ProgramLetterPage/ProgramLetterPage.tsx
diff --git a/frontends/main/src/app-pages/TermsPage/TermsPage.tsx b/frontends/main/src/app-pages/TermsPage/TermsPage.tsx
index 73e2bc2b21..d44e161d91 100644
--- a/frontends/main/src/app-pages/TermsPage/TermsPage.tsx
+++ b/frontends/main/src/app-pages/TermsPage/TermsPage.tsx
@@ -1,7 +1,7 @@
"use client"
import React from "react"
-// Not urrently linked to. See https://github.com/mitodl/hq/issues/4639
+// Not currently linked to. See https://github.com/mitodl/hq/issues/4639
import {
Breadcrumbs,
Container,
diff --git a/frontends/main/src/app-pages/TopicsListingPage/TopicsListingPage.tsx b/frontends/main/src/app-pages/TopicsListingPage/TopicsListingPage.tsx
index 922cb42f3f..3177059a4f 100644
--- a/frontends/main/src/app-pages/TopicsListingPage/TopicsListingPage.tsx
+++ b/frontends/main/src/app-pages/TopicsListingPage/TopicsListingPage.tsx
@@ -14,14 +14,14 @@ import {
Breadcrumbs,
} from "ol-components"
import Link from "next/link"
-import { propsNotNil } from "ol-utilities"
-
+import { propsNotNil, backgroundSrcSetCSS } from "ol-utilities"
import { useLearningResourceTopics } from "api/hooks/learningResources"
import { LearningResourceTopic } from "api"
import RootTopicIcon from "@/components/RootTopicIcon/RootTopicIcon"
import { HOME } from "@/common/urls"
import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
+import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
type ChannelSummary = {
id: number | string
@@ -275,6 +275,7 @@ const TopicsListingPage: React.FC = () => {
}
title="Browse by Topic"
header="Select a topic below to explore relevant learning resources across all Academic and Professional units."
+ backgroundUrl={backgroundSrcSetCSS(backgroundSteps)}
/>
diff --git a/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx b/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
index 224323731c..39e5e5ee2a 100644
--- a/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
+++ b/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
@@ -1,6 +1,13 @@
import React from "react"
import { LearningResourceOfferorDetail, OfferedByEnum } from "api"
-import { Card, Skeleton, Typography, styled, theme } from "ol-components"
+import {
+ Card,
+ Skeleton,
+ Typography,
+ styled,
+ theme,
+ UnitLogo,
+} from "ol-components"
import { useChannelDetail } from "api/hooks/channels"
const CardStyled = styled(Card)({
@@ -34,14 +41,12 @@ const LogoContainer = styled.div({
margin: "0 auto",
},
},
-})
-
-const UnitLogo = styled.img({
- height: "50px",
- display: "block",
- [theme.breakpoints.down("md")]: {
- height: "40px",
- margin: "0 auto",
+ img: {
+ display: "block",
+ [theme.breakpoints.down("md")]: {
+ height: "40px",
+ margin: "0 auto",
+ },
},
})
@@ -108,15 +113,6 @@ const CountsText = styled(Typography)(({ theme }) => ({
},
}))
-const unitLogos = {
- [OfferedByEnum.Mitx]: "/images/unit_logos/mitx.svg",
- [OfferedByEnum.Ocw]: "/images/unit_logos/ocw.svg",
- [OfferedByEnum.Bootcamps]: "/images/unit_logos/bootcamps.svg",
- [OfferedByEnum.Xpro]: "/images/unit_logos/xpro.svg",
- [OfferedByEnum.Mitpe]: "/images/unit_logos/mitpe.svg",
- [OfferedByEnum.See]: "/images/unit_logos/see.svg",
-}
-
interface UnitCardsProps {
units: LearningResourceOfferorDetail[] | undefined
courseCounts: Record
@@ -125,13 +121,12 @@ interface UnitCardsProps {
interface UnitCardProps {
unit: LearningResourceOfferorDetail
- logo: string
courseCount: number
programCount: number
}
const UnitCard: React.FC = (props) => {
- const { unit, logo, courseCount, programCount } = props
+ const { unit, courseCount, programCount } = props
const channelDetailQuery = useChannelDetail("unit", unit.code)
const channelDetail = channelDetailQuery.data
const unitUrl = channelDetail?.channel_url
@@ -144,7 +139,7 @@ const UnitCard: React.FC = (props) => {
-
+
@@ -197,14 +192,10 @@ export const UnitCards: React.FC = (props) => {
{units?.map((unit) => {
const courseCount = courseCounts[unit.code] || 0
const programCount = programCounts[unit.code] || 0
- const logo =
- unitLogos[unit.code as OfferedByEnum] ||
- `/images/unit_logos/${unit.code}.svg`
return unit.value_prop ? (
diff --git a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx
index 574ccb3b42..112de6ea7e 100644
--- a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx
+++ b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx
@@ -11,7 +11,8 @@ import {
theme,
Breadcrumbs,
} from "ol-components"
-
+import { backgroundSrcSetCSS } from "ol-utilities"
+import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { RiBookOpenLine, RiSuitcaseLine } from "@remixicon/react"
import { LearningResourceOfferorDetail } from "api"
import { HOME } from "@/common/urls"
@@ -248,6 +249,7 @@ const UnitsListingPage: React.FC = () => {
}
title="Academic & Professional Learning"
header="Non-degree learning resources tailored to the needs of students and working professionals."
+ backgroundUrl={backgroundSrcSetCSS(backgroundSteps)}
/>
diff --git a/frontends/main/src/app/program_letter/[id]/view/page.tsx b/frontends/main/src/app/program_letter/[id]/view/page.tsx
index faa058688c..849a6050e5 100644
--- a/frontends/main/src/app/program_letter/[id]/view/page.tsx
+++ b/frontends/main/src/app/program_letter/[id]/view/page.tsx
@@ -1,5 +1,5 @@
import React from "react"
-import ProgramLetterPage from "@/app-pages/ProgramLetterPage/[id]/view/ProgramLetterPage"
+import ProgramLetterPage from "@/app-pages/ProgramLetterPage/ProgramLetterPage"
const Page: React.FC = () => {
return
diff --git a/frontends/main/src/page-components/Header/Header.tsx b/frontends/main/src/page-components/Header/Header.tsx
index e5cb4b7584..93ef5bcdb9 100644
--- a/frontends/main/src/page-components/Header/Header.tsx
+++ b/frontends/main/src/page-components/Header/Header.tsx
@@ -295,7 +295,7 @@ const Header: FunctionComponent = () => {
desktopTrigger.current,
mobileTrigger.current,
]}
- navdata={navData}
+ navData={navData}
open={drawerOpen}
onClose={toggleDrawer.off}
/>
diff --git a/frontends/ol-components/src/components/Banner/Banner.tsx b/frontends/ol-components/src/components/Banner/Banner.tsx
index a908fb5a74..22dd0bdaa6 100644
--- a/frontends/ol-components/src/components/Banner/Banner.tsx
+++ b/frontends/ol-components/src/components/Banner/Banner.tsx
@@ -27,26 +27,32 @@ const BannerBackground = styled.div(
backgroundUrl = DEFAULT_BACKGROUND_IMAGE_URL,
backgroundSize = "cover",
backgroundDim = 0,
- }) => ({
- backgroundAttachment: "fixed",
- backgroundImage: backgroundDim
- ? `linear-gradient(rgba(0 0 0 / ${backgroundDim}%), rgba(0 0 0 / ${backgroundDim}%)), url('${backgroundUrl}')`
- : `url(${backgroundUrl})`,
- backgroundSize: backgroundSize,
- backgroundPosition: "center top",
- backgroundRepeat: "no-repeat",
- color: theme.custom.colors.white,
- padding: "48px 0 48px 0",
- [theme.breakpoints.up("lg")]: {
- backgroundSize:
- backgroundUrl === DEFAULT_BACKGROUND_IMAGE_URL
- ? "140%"
- : backgroundSize,
- },
- [theme.breakpoints.down("sm")]: {
- padding: "32px 0 32px 0",
- },
- }),
+ }) => {
+ const backgroundUrlFn = backgroundUrl.startsWith("image-set(")
+ ? backgroundUrl
+ : `url('${backgroundUrl}')`
+
+ return {
+ backgroundAttachment: "fixed",
+ backgroundImage: backgroundDim
+ ? `linear-gradient(rgba(0 0 0 / ${backgroundDim}%), rgba(0 0 0 / ${backgroundDim}%)), ${backgroundUrlFn}`
+ : backgroundUrlFn,
+ backgroundSize: backgroundSize,
+ backgroundPosition: "center top",
+ backgroundRepeat: "no-repeat",
+ color: theme.custom.colors.white,
+ padding: "48px 0 48px 0",
+ [theme.breakpoints.up("lg")]: {
+ backgroundSize:
+ backgroundUrl === DEFAULT_BACKGROUND_IMAGE_URL
+ ? "140%"
+ : backgroundSize,
+ },
+ [theme.breakpoints.down("sm")]: {
+ padding: "32px 0 32px 0",
+ },
+ }
+ },
)
const InnerContainer = styled.div(({ theme }) => ({
diff --git a/frontends/ol-components/src/components/EmbedlyCard/EmbedlyCard.tsx b/frontends/ol-components/src/components/EmbedlyCard/EmbedlyCard.tsx
index 94c36354b7..6064544f4c 100644
--- a/frontends/ol-components/src/components/EmbedlyCard/EmbedlyCard.tsx
+++ b/frontends/ol-components/src/components/EmbedlyCard/EmbedlyCard.tsx
@@ -6,9 +6,10 @@ import {
embedlyCardHtml,
EmbedlyEventTypes,
ensureEmbedlyPlatform,
- getEmbedlyKey,
} from "./util"
+const EMBEDLY_KEY = process.env.NEXT_PUBLIC_EMBEDLY_KEY as string
+
type EmbedlyCardProps = {
url: string
className?: string
@@ -51,7 +52,6 @@ const Container = styled.div<{ aspectRatio?: number }>`
const EmbedlyCard: React.FC = ({
className,
url,
- embedlyKey,
aspectRatio,
}) => {
const [container, setContainer] = useState(null)
@@ -85,12 +85,12 @@ const EmbedlyCard: React.FC = ({
const a = document.createElement("a")
a.dataset.cardChrome = "0"
a.dataset.cardControls = "0"
- a.dataset.cardKey = embedlyKey ?? getEmbedlyKey() ?? ""
+ a.dataset.cardKey = EMBEDLY_KEY
a.href = url
a.classList.add("embedly-card")
a.dataset["testid"] = "embedly-card"
container.appendChild(a)
- }, [embedlyKey, container, url])
+ }, [container, url])
return (
{
head.appendChild(style)
}
-const getEmbedlyKey = (): string | null => {
- const key = process.env.NEXT_PUBLIC_EMBEDLY_KEY
- if (typeof key === "string") return key
- console.warn("process.env.NEXT_PUBLIC_EMBEDLY_KEY should be a string.")
- return null
-}
-
const embedlyCardHtml = (url: string) => {
- const embedlyKey = getEmbedlyKey()
return ``
}
@@ -101,7 +95,6 @@ const embedlyCardHtml = (url: string) => {
export {
createStylesheet,
ensureEmbedlyPlatform,
- getEmbedlyKey,
EmbedlyEventTypes,
dispatchCardCreated,
embedlyCardHtml,
diff --git a/frontends/ol-components/src/components/LearningResourceCard/LearningResourceListCard.tsx b/frontends/ol-components/src/components/LearningResourceCard/LearningResourceListCard.tsx
index 1757cffa63..d80859d49a 100644
--- a/frontends/ol-components/src/components/LearningResourceCard/LearningResourceListCard.tsx
+++ b/frontends/ol-components/src/components/LearningResourceCard/LearningResourceListCard.tsx
@@ -11,7 +11,6 @@ import { ResourceTypeEnum, LearningResource } from "api"
import {
formatDate,
getReadableResourceType,
- // embedlyCroppedImage,
DEFAULT_RESOURCE_IMG,
pluralize,
getLearningResourcePrices,
@@ -106,14 +105,6 @@ type ResourceIdCallback = (
resourceId: number,
) => void
-// TODO confirm use of Next.js image optimizer in place of Embedly
-// const getEmbedlyUrl = (url: string, isMobile: boolean) => {
-// return embedlyCroppedImage(url, {
-// key: process.env.NEXT_PUBLIC_EMBEDLY_KEY!,
-// ...IMAGE_SIZES[isMobile ? "mobile" : "desktop"],
-// })
-// }
-
/* This displays a single price for courses with no free option
* (price includes the certificate). For free courses with the
* option of a paid certificate, the certificate price displayed
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpanded.stories.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpanded.stories.tsx
index c6af08ffb4..27d7e2524c 100644
--- a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpanded.stories.tsx
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpanded.stories.tsx
@@ -21,7 +21,6 @@ const meta: Meta = {
component: LearningResourceExpandedV1,
args: {
imgConfig: {
- key: "",
width: 385,
height: 200,
},
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.test.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.test.tsx
index 1e38706ff4..8a1a54df9d 100644
--- a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.test.tsx
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.test.tsx
@@ -11,10 +11,9 @@ import { ThemeProvider } from "../ThemeProvider/ThemeProvider"
import invariant from "tiny-invariant"
import type { LearningResource } from "api"
import { faker } from "@faker-js/faker/locale/en"
-import { PLATFORMS } from "../Logo/Logo"
+import { PLATFORM_LOGOS } from "../Logo/Logo"
const IMG_CONFIG: LearningResourceExpandedV1Props["imgConfig"] = {
- key: "fake-key",
width: 385,
height: 200,
}
@@ -151,7 +150,7 @@ describe("Learning Resource Expanded", () => {
.find((img) => img.getAttribute("alt")?.includes("xPRO"))
expect(xproImage).toBeInTheDocument()
- expect(xproImage).toHaveAttribute("alt", PLATFORMS["xpro"].name)
+ expect(xproImage).toHaveAttribute("alt", PLATFORM_LOGOS["xpro"].name)
},
)
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.tsx
index 5af9ac6066..a0155829db 100644
--- a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.tsx
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV1.tsx
@@ -2,26 +2,26 @@ import React, { useEffect, useState } from "react"
import styled from "@emotion/styled"
import Skeleton from "@mui/material/Skeleton"
import Typography from "@mui/material/Typography"
+import { default as NextImage } from "next/image"
import { ButtonLink } from "../Button/Button"
import type { LearningResource, LearningResourceRun } from "api"
import { ResourceTypeEnum, PlatformEnum } from "api"
import {
formatDate,
capitalize,
- resourceThumbnailSrc,
DEFAULT_RESOURCE_IMG,
showStartAnytime,
} from "ol-utilities"
import { RiExternalLinkLine } from "@remixicon/react"
-import type { EmbedlyConfig } from "ol-utilities"
import { theme } from "../ThemeProvider/ThemeProvider"
import { SimpleSelect } from "../SimpleSelect/SimpleSelect"
import type { SimpleSelectProps } from "../SimpleSelect/SimpleSelect"
-import { EmbedlyCard } from "../EmbedlyCard/EmbedlyCard"
-import { PlatformLogo, PLATFORMS } from "../Logo/Logo"
+import { PlatformLogo, PLATFORM_LOGOS } from "../Logo/Logo"
import InfoSectionV1 from "./InfoSectionV1"
import type { User } from "api/hooks/user"
import { LearningResourceCardProps } from "../LearningResourceCard/LearningResourceCard"
+import type { ImageConfig } from "../../constants/imgConfigs"
+import VideoFrame from "./VideoFrame"
const Container = styled.div<{ padTop?: boolean }>`
display: flex;
@@ -76,8 +76,13 @@ const DateLabel = styled.span`
margin-right: 16px;
`
-const Image = styled.img<{ aspect: number }>`
- aspect-ratio: ${({ aspect }) => aspect};
+const ImageContainer = styled.div<{ aspect: number }>`
+ position: relative;
+ width: 100%;
+ padding-bottom: ${({ aspect }) => 100 / aspect}%;
+`
+
+const Image = styled(NextImage)`
border-radius: 8px;
width: 100%;
object-fit: cover;
@@ -141,38 +146,39 @@ const OnPlatform = styled.span`
type LearningResourceExpandedV1Props = {
resource?: LearningResource
user?: User
- imgConfig: EmbedlyConfig
+ imgConfig: ImageConfig
onAddToLearningPathClick?: LearningResourceCardProps["onAddToLearningPathClick"]
onAddToUserListClick?: LearningResourceCardProps["onAddToUserListClick"]
}
const ImageSection: React.FC<{
resource?: LearningResource
- config: EmbedlyConfig
+ config: ImageConfig
}> = ({ resource, config }) => {
+ const aspect = config.width / config.height
if (resource?.resource_type === "video" && resource?.url) {
return (
-
+
)
} else if (resource?.image) {
return (
-
+
+
+
)
} else if (resource) {
return (
-
+
+
+
)
} else {
return (
@@ -218,7 +224,7 @@ const CallToActionSection = ({
(offeredBy?.code as PlatformEnum) === PlatformEnum.Xpro
? (offeredBy?.code as PlatformEnum)
: (platform?.code as PlatformEnum)
- const platformImage = PLATFORMS[platformCode]?.image
+ const platformImage = PLATFORM_LOGOS[platformCode]?.image
const getCallToActionText = (resource: LearningResource): string => {
if (resource?.platform?.code === PlatformEnum.Ocw) {
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.test.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.test.tsx
index 1d40a84d27..0f242e754e 100644
--- a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.test.tsx
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.test.tsx
@@ -12,11 +12,10 @@ import { factories } from "api/test-utils"
import { ThemeProvider } from "../ThemeProvider/ThemeProvider"
import invariant from "tiny-invariant"
import type { LearningResource } from "api"
-import { PLATFORMS } from "../Logo/Logo"
+import { PLATFORM_LOGOS } from "../Logo/Logo"
import _ from "lodash"
const IMG_CONFIG: LearningResourceExpandedV2Props["imgConfig"] = {
- key: "fake-key",
width: 385,
height: 200,
}
@@ -152,7 +151,7 @@ describe("Learning Resource Expanded", () => {
.find((img) => img.getAttribute("alt")?.includes("xPRO"))
expect(xproImage).toBeInTheDocument()
- expect(xproImage).toHaveAttribute("alt", PLATFORMS["xpro"].name)
+ expect(xproImage).toHaveAttribute("alt", PLATFORM_LOGOS["xpro"].name)
},
)
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.tsx
index 5b3506d9a8..d273f2f9cb 100644
--- a/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.tsx
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/LearningResourceExpandedV2.tsx
@@ -2,28 +2,25 @@ import React from "react"
import styled from "@emotion/styled"
import Skeleton from "@mui/material/Skeleton"
import Typography from "@mui/material/Typography"
+import { default as NextImage } from "next/image"
import { ActionButton, ButtonLink } from "../Button/Button"
import type { LearningResource } from "api"
import { ResourceTypeEnum, PlatformEnum } from "api"
-import {
- resourceThumbnailSrc,
- DEFAULT_RESOURCE_IMG,
- getReadableResourceType,
-} from "ol-utilities"
+import { DEFAULT_RESOURCE_IMG, getReadableResourceType } from "ol-utilities"
import {
RiBookmarkLine,
RiCloseLargeLine,
RiExternalLinkLine,
RiMenuAddLine,
} from "@remixicon/react"
-import type { EmbedlyConfig } from "ol-utilities"
+import type { ImageConfig } from "../../constants/imgConfigs"
import { theme } from "../ThemeProvider/ThemeProvider"
-import { EmbedlyCard } from "../EmbedlyCard/EmbedlyCard"
-import { PlatformLogo, PLATFORMS } from "../Logo/Logo"
+import { PlatformLogo, PLATFORM_LOGOS } from "../Logo/Logo"
import InfoSectionV2 from "./InfoSectionV2"
import type { User } from "api/hooks/user"
import { LearningResourceCardProps } from "../LearningResourceCard/LearningResourceCard"
import { CardActionButton } from "../LearningResourceCard/LearningResourceListCard"
+import VideoFrame from "./VideoFrame"
const Container = styled.div({
display: "flex",
@@ -81,17 +78,17 @@ const RightContainer = styled.div({
},
})
-const EmbedlyContainer = styled.div({
- width: "100%",
- overflow: "hidden",
-})
+const ImageContainer = styled.div<{ aspect: number }>`
+ position: relative;
+ width: 100%;
+ padding-bottom: ${({ aspect }) => 100 / aspect}%;
+`
-const Image = styled.img<{ aspect: number }>((aspect) => ({
- aspectRatio: aspect.aspect,
+const Image = styled(NextImage)({
borderRadius: "8px",
width: "100%",
objectFit: "cover",
-}))
+})
const SkeletonImage = styled(Skeleton)<{ aspect: number }>((aspect) => ({
borderRadius: "8px",
@@ -168,7 +165,7 @@ const ListButtonContainer = styled.div({
type LearningResourceExpandedV2Props = {
resource?: LearningResource
user?: User
- imgConfig: EmbedlyConfig
+ imgConfig: ImageConfig
onAddToLearningPathClick?: LearningResourceCardProps["onAddToLearningPathClick"]
onAddToUserListClick?: LearningResourceCardProps["onAddToUserListClick"]
closeDrawer?: () => void
@@ -237,33 +234,32 @@ const TitleSection: React.FC<{
const ImageSection: React.FC<{
resource?: LearningResource
- config: EmbedlyConfig
+ config: ImageConfig
}> = ({ resource, config }) => {
+ const aspect = config.width / config.height
if (resource?.resource_type === "video" && resource?.url) {
return (
-
-
-
+
)
} else if (resource?.image) {
return (
-
+
+
+
)
} else if (resource) {
return (
-
+
+
+
)
} else {
return (
@@ -323,7 +319,7 @@ const CallToActionSection = ({
onAddToLearningPathClick,
onAddToUserListClick,
}: {
- imgConfig: EmbedlyConfig
+ imgConfig: ImageConfig
resource?: LearningResource
hide?: boolean
user?: User
@@ -350,7 +346,7 @@ const CallToActionSection = ({
(offeredBy?.code as PlatformEnum) === PlatformEnum.Xpro
? (offeredBy?.code as PlatformEnum)
: (platform?.code as PlatformEnum)
- const platformImage = PLATFORMS[platformCode]?.image
+ const platformImage = PLATFORM_LOGOS[platformCode]?.image
const cta = getCallToActionText(resource)
return (
diff --git a/frontends/ol-components/src/components/LearningResourceExpanded/VideoFrame.tsx b/frontends/ol-components/src/components/LearningResourceExpanded/VideoFrame.tsx
new file mode 100644
index 0000000000..3f76c24609
--- /dev/null
+++ b/frontends/ol-components/src/components/LearningResourceExpanded/VideoFrame.tsx
@@ -0,0 +1,32 @@
+import React from "react"
+import styled from "@emotion/styled"
+import { EmbedlyCard } from "../EmbedlyCard/EmbedlyCard"
+
+const IFrame = styled.iframe`
+ border-radius: 8px;
+ border: none;
+ width: 100%;
+ aspect-ratio: 16 / 9;
+`
+
+const VideoFrame: React.FC<{
+ src: string
+ title: string
+ aspect: number
+}> = ({ src, title, aspect }) => {
+ if (src?.startsWith("https://www.youtube.com/watch?v=")) {
+ const videoId = src?.split("v=")[1]
+ return (
+
+ )
+ }
+ return
+}
+
+export default VideoFrame
diff --git a/frontends/ol-components/src/components/Logo/Logo.stories.tsx b/frontends/ol-components/src/components/Logo/Logo.stories.tsx
index 7f210685a6..b08359741d 100644
--- a/frontends/ol-components/src/components/Logo/Logo.stories.tsx
+++ b/frontends/ol-components/src/components/Logo/Logo.stories.tsx
@@ -1,6 +1,6 @@
import React from "react"
import type { Meta, StoryObj } from "@storybook/react"
-import { PlatformLogo, PLATFORMS } from "./Logo"
+import { PlatformLogo, PLATFORM_LOGOS } from "./Logo"
import Grid from "@mui/material/Grid"
import styled from "@emotion/styled"
import { PlatformEnum } from "api"
@@ -27,7 +27,7 @@ const meta: Meta = {
iconHeight
args are only for this story. Not applicable to the actual component.
- {Object.entries(PLATFORMS).map(([platformCode, platform]) => (
+ {Object.entries(PLATFORM_LOGOS).map(([platformCode, platform]) => (
{platformCode}
diff --git a/frontends/ol-components/src/components/Logo/Logo.tsx b/frontends/ol-components/src/components/Logo/Logo.tsx
index 6524b292e3..5c9d8f52fc 100644
--- a/frontends/ol-components/src/components/Logo/Logo.tsx
+++ b/frontends/ol-components/src/components/Logo/Logo.tsx
@@ -1,5 +1,5 @@
import React from "react"
-import { PlatformEnum } from "api"
+import { PlatformEnum, OfferedByEnum } from "api"
import Image from "next/image"
type WithImage = {
@@ -13,50 +13,61 @@ type WithoutImage = {
image?: null
}
-type PlatformObject = WithImage | WithoutImage
+type LogoObject = WithImage | WithoutImage
-export const PLATFORMS: Record = {
- [PlatformEnum.Ocw]: {
- name: "MIT OpenCourseWare",
- image: "/unit_logos/ocw.svg",
- aspect: 6.03,
- },
- [PlatformEnum.Edx]: {
- name: "edX",
- image: "/platform_logos/edx.svg",
- aspect: 1.77,
- },
- [PlatformEnum.Mitxonline]: {
+export const UNIT_LOGOS: Record = {
+ [OfferedByEnum.Mitx]: {
name: "MITx Online",
- image: "/unit_logos/mitx.svg",
+ image: "/images/unit_logos/mitx.svg",
aspect: 3.32,
},
- [PlatformEnum.Bootcamps]: {
+ [OfferedByEnum.Ocw]: {
+ name: "MIT OpenCourseWare",
+ image: "/images/unit_logos/ocw.svg",
+ aspect: 6.03,
+ },
+ [OfferedByEnum.Bootcamps]: {
name: "Bootcamps",
- image: "/platform_logos/bootcamps.svg",
+ image: "/images/platform_logos/bootcamps.svg",
aspect: 5.25,
},
- [PlatformEnum.Xpro]: {
+ [OfferedByEnum.Xpro]: {
name: "MIT xPRO",
- image: "/unit_logos/xpro.svg",
+ image: "/images/unit_logos/xpro.svg",
aspect: 3.56,
},
+ [OfferedByEnum.Mitpe]: {
+ name: "MIT Professional Education",
+ image: "/images/unit_logos/mitpe.svg",
+ aspect: 5.23,
+ },
+ [OfferedByEnum.See]: {
+ name: "MIT Sloan Executive Education",
+ image: "/images/unit_logos/see.svg",
+ aspect: 7.61,
+ },
+}
+
+export const PLATFORM_LOGOS: Record = {
+ [PlatformEnum.Ocw]: UNIT_LOGOS[OfferedByEnum.Ocw],
+ [PlatformEnum.Edx]: {
+ name: "edX",
+ image: "/images/platform_logos/edx.svg",
+ aspect: 1.77,
+ },
+ [PlatformEnum.Mitxonline]: UNIT_LOGOS[OfferedByEnum.Mitx],
+ [PlatformEnum.Bootcamps]: UNIT_LOGOS[OfferedByEnum.Bootcamps],
+ [PlatformEnum.Xpro]: UNIT_LOGOS[OfferedByEnum.Xpro],
[PlatformEnum.Podcast]: {
name: "Podcast",
},
[PlatformEnum.Csail]: {
name: "CSAIL",
- image: "/platform_logos/csail.svg",
+ image: "/images/platform_logos/csail.svg",
aspect: 1.76,
},
- [PlatformEnum.Mitpe]: {
- name: "MIT Professional Education",
- },
- [PlatformEnum.See]: {
- name: "MIT Sloan Executive Education",
- image: "/unit_logos/see.svg",
- aspect: 7.73,
- },
+ [PlatformEnum.Mitpe]: UNIT_LOGOS[OfferedByEnum.Mitpe],
+ [PlatformEnum.See]: UNIT_LOGOS[OfferedByEnum.See],
[PlatformEnum.Scc]: {
name: "Schwarzman College of Computing",
},
@@ -80,7 +91,7 @@ export const PLATFORMS: Record = {
},
[PlatformEnum.Oll]: {
name: "Open Learning Library",
- image: "/platform_logos/oll.svg",
+ image: "/images/platform_logos/oll.svg",
aspect: 5.25,
},
[PlatformEnum.Youtube]: {
@@ -90,14 +101,15 @@ export const PLATFORMS: Record = {
const DEFAULT_WIDTH = 200
-export const PlatformLogo: React.FC<{
- platformCode?: PlatformEnum
+const Logo: React.FC<{
+ name: string
+ image: string
+ aspect: number
className?: string
width?: number
height?: number
-}> = ({ platformCode, className, width, height }) => {
- const platform = PLATFORMS[platformCode!]
- if (!platform?.image) {
+}> = ({ name, image, aspect, className, width, height }) => {
+ if (!image) {
return null
}
@@ -109,21 +121,63 @@ export const PlatformLogo: React.FC<{
* not actually applying - "Using `
` could result in slower LCP and higher bandwidth.".
*/
if (width && !height) {
- height = width / platform.aspect
+ height = width / aspect
}
if (!width && height) {
- width = height * platform.aspect
+ width = height * aspect
}
if (!width) {
width = DEFAULT_WIDTH
- height = width / platform.aspect
+ height = width / aspect
}
return (
+ )
+}
+
+export const UnitLogo: React.FC<{
+ unitCode: OfferedByEnum
+ className?: string
+ width?: number
+ height?: number
+}> = ({ unitCode, className, width, height }) => {
+ const unit = UNIT_LOGOS[unitCode]
+ if (!unit?.image) return null
+ const { name, image, aspect } = unit
+ return (
+
+ )
+}
+
+export const PlatformLogo: React.FC<{
+ platformCode: PlatformEnum
+ className?: string
+ width?: number
+ height?: number
+}> = ({ platformCode, className, width, height }) => {
+ const platform = PLATFORM_LOGOS[platformCode]
+ if (!platform?.image) return null
+ const { name, image, aspect } = platform
+ return (
+
diff --git a/frontends/ol-components/src/components/NavDrawer/NavDrawer.stories.tsx b/frontends/ol-components/src/components/NavDrawer/NavDrawer.stories.tsx
index 1421e4d897..366876f94f 100644
--- a/frontends/ol-components/src/components/NavDrawer/NavDrawer.stories.tsx
+++ b/frontends/ol-components/src/components/NavDrawer/NavDrawer.stories.tsx
@@ -1,29 +1,44 @@
-import React from "react"
+import React, { MouseEvent } from "react"
import type { Meta, StoryObj } from "@storybook/react"
import { NavData, NavDrawer } from "./NavDrawer"
import MuiButton from "@mui/material/Button"
import styled from "@emotion/styled"
+import { RiPencilRulerLine } from "@remixicon/react"
import { useToggle } from "ol-utilities"
const NavDrawerDemo = () => {
const [open, setOpen] = useToggle(false)
- const handleClickOpen = () => setOpen(!open)
+ const handleClickOpen = (event: MouseEvent) => {
+ setOpen(true)
+ event.stopPropagation()
+ }
const navData: NavData = {
sections: [
{
- title: "TEST",
+ title: "Nav Drawer Title",
items: [
{
- title: "Link and description",
- description: "This item has a link and a description",
+ title: "Link with description",
+ description: "This link has a description",
href: "https://mit.edu",
},
{
- title: "Link but no description",
+ title: "Link with no description",
href: "https://ocw.mit.edu",
},
+ {
+ title: "Link with icon",
+ icon: ,
+ href: "https://mit.edu",
+ },
+ {
+ title: "Link with icon and description",
+ description: "This link has an icon and a description",
+ icon: ,
+ href: "https://mit.edu",
+ },
],
},
],
@@ -39,7 +54,7 @@ const NavDrawerDemo = () => {
Toggle drawer
-
+
)
}
diff --git a/frontends/ol-components/src/components/NavDrawer/NavDrawer.test.tsx b/frontends/ol-components/src/components/NavDrawer/NavDrawer.test.tsx
index 3e20d8a100..09f771f012 100644
--- a/frontends/ol-components/src/components/NavDrawer/NavDrawer.test.tsx
+++ b/frontends/ol-components/src/components/NavDrawer/NavDrawer.test.tsx
@@ -3,6 +3,7 @@ import { render, screen } from "@testing-library/react"
import user from "@testing-library/user-event"
import React from "react"
import { ThemeProvider } from "../ThemeProvider/ThemeProvider"
+import Image from "next/image"
describe("NavDrawer", () => {
it("Renders the expected drawer contents", () => {
@@ -13,7 +14,15 @@ describe("NavDrawer", () => {
items: [
{
title: "Link and description with icon",
- icon: "/path/to/image.svg",
+ icon: (
+
+ ),
description: "This item has a link, description and icon",
href: "https://mit.edu",
},
@@ -30,7 +39,7 @@ describe("NavDrawer", () => {
},
],
}
- render(, {
+ render(, {
wrapper: ThemeProvider,
})
const links = screen.getAllByTestId("nav-link")
@@ -70,7 +79,7 @@ describe("NavDrawer", () => {
test("close button calls onClose", async () => {
const onClose = jest.fn()
- render(, {
+ render(, {
wrapper: ThemeProvider,
})
const close = screen.getByRole("button", { name: "Close Navigation" })
@@ -80,7 +89,7 @@ describe("NavDrawer", () => {
test("escape calls onClose", async () => {
const onClose = jest.fn()
- render(, {
+ render(, {
wrapper: ThemeProvider,
})
const links = screen.getAllByRole("link")
@@ -98,7 +107,7 @@ describe("NavDrawer", () => {
[excluded.current]}
onClose={onClose}
- navdata={NAV_DATA}
+ navData={NAV_DATA}
open={true}
/>
@@ -121,7 +130,7 @@ describe("NavDrawer", () => {
test("clicking a link navigates and closes the drawer", async () => {
const onClose = jest.fn()
- render(, {
+ render(, {
wrapper: ThemeProvider,
})
diff --git a/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx b/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx
index 9ed6fc6af7..f8ed70bb54 100644
--- a/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx
+++ b/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx
@@ -83,12 +83,6 @@ const NavIconContainer = styled.div({
alignItems: "flex-start",
})
-const NavIcon = styled.img({
- width: "22px",
- height: "22px",
- opacity: ".7",
-})
-
const NavTextContainer = styled.div({
display: "flex",
flex: "1 0 0",
@@ -118,32 +112,29 @@ export interface NavData {
sections: NavSection[]
}
-export interface NavSection {
+interface NavSection {
title: string
items: NavItem[]
}
-export interface NavItem {
+interface NavItem {
title: string
- icon?: string | ReactElement
+ icon?: ReactElement
description?: string
href: string
+}
+
+type NavItemProps = NavItem & {
onClick?: () => void
}
-const NavItem: React.FC = (props) => {
+const NavItem: React.FC = (props) => {
const { title, icon, description, href, onClick } = props
+
const navItem = (
- {typeof icon === "string" ? (
-
- ) : null}
- {typeof icon !== "string" ? icon : null}
+ {icon}
@@ -165,7 +156,7 @@ const NavItem: React.FC = (props) => {
}
type NavDrawerProps = {
- navdata: NavData
+ navData: NavData
onClose: () => void
/**
* Returns a list of HTMLElements that should not trigger the drawer to close
@@ -175,12 +166,12 @@ type NavDrawerProps = {
} & DrawerProps
const NavDrawer = ({
- navdata,
+ navData,
onClose,
getClickAwayExcluded = () => [],
...others
}: NavDrawerProps) => {
- const navSections = navdata.sections.map((section, i) => {
+ const navSections = navData.sections.map((section, i) => {
const navItemElements = section.items.map((item) => (
+} satisfies Record
export { imgConfigs }
diff --git a/frontends/ol-utilities/package.json b/frontends/ol-utilities/package.json
index b9af50c386..cec5f66007 100644
--- a/frontends/ol-utilities/package.json
+++ b/frontends/ol-utilities/package.json
@@ -7,7 +7,7 @@
"./test-utils/factories": "./src/test-utils/factories.ts"
},
"peerDependencies": {
- "next": "*",
+ "next": "^14.2.15",
"react": "18.3.1"
},
"dependencies": {
diff --git a/frontends/ol-utilities/src/images/backgroundImages.ts b/frontends/ol-utilities/src/images/backgroundImages.ts
new file mode 100644
index 0000000000..a292365651
--- /dev/null
+++ b/frontends/ol-utilities/src/images/backgroundImages.ts
@@ -0,0 +1,27 @@
+import { getImageProps } from "next/image"
+import type { ImageProps } from "next/image"
+
+/* Generates a CSS `image-set()` declaration for a statically imported image.
+ * The Next.js server optimizes the image at resolutions requested, allowing the
+ * browser to select the best-suited image size based on the device's pixel density.
+ *
+ * https://nextjs.org/docs/app/api-reference/components/image#background-css
+ */
+
+export const backgroundSrcSetCSS = (image: ImageProps["src"]) => {
+ const { props } = getImageProps({
+ alt: "",
+ quality: 100,
+ src: image,
+ })
+
+ const imageSet = props.srcSet
+ ?.split(", ")
+ .map((str) => {
+ const [url, dpi] = str.split(" ")
+ return `url("${url}") ${dpi}`
+ })
+ .join(", ")
+
+ return `image-set(${imageSet})`
+}
diff --git a/frontends/ol-utilities/src/index.ts b/frontends/ol-utilities/src/index.ts
index 428a646c59..eefe535703 100644
--- a/frontends/ol-utilities/src/index.ts
+++ b/frontends/ol-utilities/src/index.ts
@@ -13,3 +13,4 @@ export * from "./predicates"
export * from "./hooks"
export * from "./querystrings"
export * from "./lib"
+export * from "./images/backgroundImages"
diff --git a/yarn.lock b/yarn.lock
index 7f49a37188..1eb696bb7d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16114,7 +16114,7 @@ __metadata:
striptags: "npm:^3.2.0"
tiny-invariant: "npm:^1.3.1"
peerDependencies:
- next: "*"
+ next: ^14.2.15
react: 18.3.1
languageName: unknown
linkType: soft