Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Set title of header using Portal (#177)
Browse files Browse the repository at this point in the history
* Set title using Portal

* cleanup
  • Loading branch information
JibrilExe authored Apr 6, 2024
1 parent d2cf519 commit 3d10ef7
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 27 deletions.
3 changes: 3 additions & 0 deletions frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"home": {
"title": "Homepage"
},
"header": {
"myProjects": "My Projects",
"myCourses": "My Courses",
Expand Down
3 changes: 3 additions & 0 deletions frontend/public/locales/nl/translation.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"home": {
"title": "Homepagina"
},
"header": {
"myProjects": "Mijn Projecten",
"myCourses": "Mijn Vakken",
Expand Down
26 changes: 3 additions & 23 deletions frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import MenuIcon from "@mui/icons-material/Menu";
import { useTranslation } from "react-i18next";
import { useEffect, useState } from "react";
import LanguageIcon from "@mui/icons-material/Language";
import { Link, useLocation } from "react-router-dom";
import { Link } from "react-router-dom";
import { TitlePortal } from "./TitlePortal";

/**
* The header component for the application that will be rendered at the top of the page.
Expand All @@ -41,7 +42,6 @@ export function Header(): JSX.Element {
setLanguageMenuAnchor(null);
};

const location = useLocation();
const [open, setOpen] = useState(false);
const [listItems, setListItems] = useState([
{ link: "/", text: t("homepage") }
Expand All @@ -61,18 +61,14 @@ export function Header(): JSX.Element {
}
}, [t]);

const title = getTitle(location.pathname, t);

return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="sticky">
<Toolbar disableGutters>
<IconButton edge="start" onClick={() => setOpen(!open)} sx={{ color: "white", marginLeft: 0 }}>
<MenuIcon style={{fontSize:"2rem"}} />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
{title}
</Typography>
<TitlePortal />
<Button color="inherit">{t("login")}</Button>
<div>
<IconButton onClick={handleLanguageMenu} color="inherit">
Expand Down Expand Up @@ -107,22 +103,6 @@ function isLoggedIn() {
return true;
}

/**
* Get the title based on the given pathname.
* @param pathname - The current pathname.
* @param t - The translation function.
* @returns The title.
*/
function getTitle(pathname: string, t: (key: string) => string): string {
switch(pathname) {
case '/': return t('home');
case '/login': return t('login');
case '/courses': return t('myCourses');
case '/projects': return t('myProjects');
default: return t('home');
}
}

/**
* Renders the drawer menu component.
* @param open - Whether the drawer menu is open or not.
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/components/Header/PageTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const PageTitle = ({ title, defaultTitle, className }: {title:string,defaultTitle:string,className:string}) => {

return (
<span className={className}>
{!title ? (
<span>{defaultTitle}</span>
) : typeof title === 'string' ? (
<span>{title}</span>
) : (
title
)}
</span>
);
};
51 changes: 51 additions & 0 deletions frontend/src/components/Header/Title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import PropTypes from 'prop-types';

export const Title = (props: TitleProps) => {
const { defaultTitle, title } = props;
const [container, setContainer] = useState(() =>
typeof document !== 'undefined'
? document.getElementById('react-admin-title')
: null
);

// on first mount, we don't have the container yet, so we wait for it
useEffect(() => {
setContainer(container => {
const isInTheDom =
typeof document !== 'undefined' &&
document.body.contains(container);
if (container && isInTheDom) return container;
return typeof document !== 'undefined'
? document.getElementById('react-admin-title')
: null;
});
}, []);

if (!container) return null;

return createPortal(
<>{title || defaultTitle}</>,
container
);
};

export const TitlePropType = PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
]);

Title.propTypes = {
defaultTitle: PropTypes.string,
className: PropTypes.string,
record: PropTypes.any,
title: TitlePropType,
};

export interface TitleProps {
className?: string;
defaultTitle?: string;
title?: string;
preferenceKey?: string;
}
14 changes: 14 additions & 0 deletions frontend/src/components/Header/TitlePortal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Typography, TypographyProps } from '@mui/material';

export const TitlePortal = (props: TypographyProps) => (
<Typography
flex="1"
textOverflow="ellipsis"
whiteSpace="nowrap"
overflow="hidden"
variant="h6"
color="inherit"
id="react-admin-title"
{...props}
/>
);
12 changes: 8 additions & 4 deletions frontend/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@

import { useTranslation } from "react-i18next";
import { Title } from "../../components/Header/Title";
/**
* This component is the home page component that will be rendered when on the index route.
* @returns - The home page component
*/
export default function Home() {
const { t } = useTranslation("translation", { keyPrefix: "home" });
return (
<div>
<h1></h1>
</div>
<>
<Title title={t('title')} />
<div>
</div>
</>
);
}

0 comments on commit 3d10ef7

Please sign in to comment.