Skip to content

Commit 70e6683

Browse files
Create Toast
1 parent 5aa8dd8 commit 70e6683

1 file changed

Lines changed: 97 additions & 4 deletions

File tree

src/theme/Root.tsx

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,105 @@
1-
import React from "react";
1+
import React, { useEffect, useState, useRef } from "react";
2+
import Link from "@docusaurus/Link";
23
import { Analytics } from "@vercel/analytics/react";
4+
import clsx from "clsx"; // Import clsx for conditional classes
5+
import styles from "./Root.module.css"; // Import the CSS module
6+
7+
// A simple Trophy SVG icon component
8+
function TrophyIcon() {
9+
return (
10+
<svg
11+
xmlns="http://www.w3.org/2000/svg"
12+
width="18"
13+
height="18"
14+
viewBox="0 0 24 24"
15+
fill="none"
16+
stroke="currentColor"
17+
strokeWidth="2"
18+
strokeLinecap="round"
19+
strokeLinejoin="round"
20+
className={styles.toastIcon}
21+
>
22+
<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6" />
23+
<path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18" />
24+
<path d="M4 22h16" />
25+
<path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22" />
26+
<path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22" />
27+
<path d="M18 2H6v7a6 6 0 0 0 12 0V2Z" />
28+
</svg>
29+
);
30+
}
31+
32+
export default function Root({ children }: { children: React.ReactNode }) {
33+
const [showToast, setShowToast] = useState(false);
34+
const [isDark, setIsDark] = useState(false);
35+
const timerRef = useRef<NodeJS.Timeout | null>(null);
36+
37+
// Theme detection logic
38+
useEffect(() => {
39+
const html = document.documentElement;
40+
const checkTheme = () => {
41+
const attrDark = html.getAttribute("data-theme") === "dark";
42+
const classDark = html.classList.contains("dark");
43+
setIsDark(attrDark || classDark);
44+
};
45+
46+
checkTheme();
47+
const observer = new MutationObserver(checkTheme);
48+
observer.observe(html, {
49+
attributes: true,
50+
attributeFilter: ["data-theme", "class"],
51+
});
52+
53+
// Show toast and set timer
54+
setShowToast(true);
55+
timerRef.current = setTimeout(() => setShowToast(false), 10000);
56+
57+
return () => {
58+
if (timerRef.current) {
59+
clearTimeout(timerRef.current);
60+
}
61+
observer.disconnect();
62+
};
63+
}, []);
64+
65+
// Handle manual close
66+
const handleCloseToast = () => {
67+
setShowToast(false);
68+
if (timerRef.current) {
69+
clearTimeout(timerRef.current);
70+
}
71+
};
372

4-
// Default implementation, that you can customize
5-
export default function Root({ children }) {
673
return (
774
<>
875
{children}
9-
{/* Only load analytics in production */}
76+
77+
{showToast && (
78+
<div
79+
// Use clsx to combine base class with theme-specific class
80+
className={clsx(
81+
styles.toastContainer,
82+
isDark ? styles.toastDark : styles.toastLight,
83+
)}
84+
>
85+
<TrophyIcon />
86+
<div className={styles.toastContent}>
87+
Check out our latest{" "}
88+
<Link to="/dashboard#leaderboard" className={styles.toastLink}>
89+
leaderboard
90+
</Link>
91+
!
92+
</div>
93+
<button
94+
onClick={handleCloseToast}
95+
className={styles.toastCloseButton}
96+
aria-label="Close notification"
97+
>
98+
&times;
99+
</button>
100+
</div>
101+
)}
102+
10103
{process.env.NODE_ENV === "production" && <Analytics />}
11104
</>
12105
);

0 commit comments

Comments
 (0)