Skip to content

Commit 9b9efd8

Browse files
authored
feature: UNI/277: Dark Mode Flashing when content is not mounted (#300)
* dark mode border on navbar changed * provided fix for flashing when refreshing or changing pages in dark mode * fixed flashing when content is not mounted * addes session user accessToken back * updated theme-color colors to match bg * removed scraper files * added more docs to the functions and descriptions ---------
1 parent 8b891bb commit 9b9efd8

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

frontend/src/app/layout.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,33 @@ export default async function RootLayout({
1414
const session = await getServerSession(authOptions);
1515

1616
return (
17-
<html lang='en' className='font-custom'>
18-
<body>
17+
<html lang='en' className='font-custom '>
18+
<head>
19+
{/* Only used in Safari - Change Navbar to slate-800 colors when dark mode */}
20+
<meta name="theme-color" content="#ffffff" />
21+
{/* Fetch theme of user before page is loaded in order to avoid flashing in safari.
22+
also sets theme-color meta tag to the appropriate color */}
23+
<script
24+
dangerouslySetInnerHTML={{
25+
__html: `
26+
try {
27+
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
28+
document.documentElement.classList.add('dark')
29+
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#1e293b')
30+
} else {
31+
document.documentElement.classList.remove('dark')
32+
}
33+
} catch (_) {}
34+
`,
35+
}}
36+
/>
37+
</head>
38+
<body className="bg-white dark:bg-slate-800 dark:text-gray-200">
1939
<Provider session={session}>
2040
<AlertProvider>
2141
<ThemeProviderComponent>
2242
<Navbar userZid={session?.user?.id} />
23-
<div className='ml-20 xs:ml-15 bg-white dark:bg-slate-800 dark:text-gray-200 h-screen overflow-y-scroll'>
43+
<div className='ml-20 xs:ml-15 h-screen overflow-y-scroll'>
2444
{children}
2545
</div>
2646
</ThemeProviderComponent>

frontend/src/app/user/[zid]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default async function UserPage({
3030
const { user } = await validatedReq(
3131
"GET",
3232
`/user/${params.zid}`,
33-
"",
33+
session?.user?.accessToken ?? "",
3434
params.zid
3535
);
3636

frontend/src/components/ThemeComponents/ThemeProvider.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ type Props = {
99
children: string | React.ReactNode;
1010
};
1111

12-
export default function ThemeProviderComponent({ children }: Props) {
12+
/**
13+
* Component that provides a theme to its child components.
14+
*
15+
* @param {Props} props - The component props.
16+
* @param {React.ReactNode} props.children - The child components to be wrapped by the theme provider.
17+
* @returns {JSX.Element | null} - If page is mounted then show the page otherwise it will make browser show no content.
18+
*/
19+
export default function ThemeProviderComponent({ children }: Props): JSX.Element | null {
1320
const [mounted, setMounted] = useState(false);
1421

1522
useEffect(() => {

frontend/src/components/ThemeComponents/ThemeSwitcher.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,44 @@ import { useTheme } from "next-themes";
55
import { SunIcon, MoonIcon } from "@heroicons/react/24/outline";
66
import Tooltip from "@/components/Tooltip/Tooltip";
77

8-
interface ThemeSwitcherProps {
9-
collapsed: boolean;
10-
}
8+
/**
9+
* Renders a theme switcher component.
10+
*
11+
* @param {object} props - The component props.
12+
* @param {boolean} props.collapsed - Indicates whether the theme switcher is collapsed.
13+
* @returns {JSX.Element | null} The rendered theme switcher component or null if not mounted.
14+
*/
1115

12-
export default function ThemeSwitcher({ collapsed }: ThemeSwitcherProps) {
16+
export default function ThemeSwitcher({ collapsed }: { collapsed: boolean }): JSX.Element | null {
1317
const [mounted, setMounted] = useState<boolean>(false);
14-
const { systemTheme, theme, setTheme } = useTheme();
18+
const { systemTheme, theme, setTheme, resolvedTheme } = useTheme();
1519

1620
useEffect(() => {
1721
setMounted(true);
1822
}, []);
1923

24+
useEffect(() => {
25+
if (resolvedTheme === 'dark') {
26+
// Change theme-color meta tag to slate-800 color when dark mode
27+
document
28+
.querySelector('meta[name="theme-color"]')!
29+
.setAttribute('content', '#1e293b')
30+
} else {
31+
// Change theme-color meta tag to white when light mode
32+
document
33+
.querySelector('meta[name="theme-color"]')!
34+
.setAttribute('content', '#ffffff')
35+
}
36+
}, [resolvedTheme])
37+
2038
if (!mounted) {
2139
return null;
2240
}
2341

42+
/**
43+
* Renders the theme changer component based on the current theme.
44+
* @returns The rendered theme changer component.
45+
*/
2446
const renderThemeChanger = () => {
2547
const currentTheme = theme === "system" ? systemTheme : theme;
2648

0 commit comments

Comments
 (0)