Skip to content

Commit f174f96

Browse files
authored
Merge pull request #1165 from kanishka-commits/toast-create
[FIX]: #1134 Create a Toast on top
2 parents 5aa8dd8 + 6c74b1e commit f174f96

File tree

2 files changed

+205
-4
lines changed

2 files changed

+205
-4
lines changed

src/theme/Root.module.css

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/* Base styles for the toast container */
2+
.toastContainer {
3+
position: fixed;
4+
top: 20px;
5+
right: 24px;
6+
border: 1px solid oklch(0.69 0 0);
7+
border-radius: 8px; /* Docusaurus --radius var is often 8px */
8+
padding: 12px 16px;
9+
font-size: 15px;
10+
font-weight: 500;
11+
z-index: 2147483647;
12+
display: flex;
13+
align-items: center;
14+
gap: 12px;
15+
max-width: 380px;
16+
line-height: 1.4;
17+
backdrop-filter: blur(8px);
18+
animation: slideDownFadeOut 10s ease-in-out forwards;
19+
transition:
20+
background 0.3s ease,
21+
color 0.3s ease,
22+
box-shadow 0.3s ease;
23+
}
24+
25+
/* Light theme specific styles */
26+
.toastLight {
27+
background: oklch(0.145 0 0 / 0.85); /* Added transparency for blur */
28+
color: oklch(0.985 0 0);
29+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
30+
}
31+
32+
/* Dark theme specific styles */
33+
.toastDark {
34+
background: oklch(0.985 0 0 / 0.85); /* Added transparency for blur */
35+
color: oklch(0.145 0 0);
36+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
37+
}
38+
39+
/* Style for the link inside the toast */
40+
.toastLink {
41+
text-decoration: underline;
42+
font-weight: 600;
43+
}
44+
.toastLight .toastLink {
45+
color: oklch(0.985 0 0); /* White in light mode */
46+
}
47+
.toastDark .toastLink {
48+
color: oklch(0.205 0 0); /* Dark in dark mode */
49+
}
50+
51+
/* Styles for the content area */
52+
.toastContent {
53+
flex-grow: 1; /* Allow content to fill space */
54+
}
55+
56+
/* Styles for the new icon */
57+
.toastIcon {
58+
flex-shrink: 0; /* Prevent icon from shrinking */
59+
/* Match icon color to text color */
60+
color: currentColor;
61+
opacity: 0.8;
62+
}
63+
64+
/* Minimalist close button */
65+
.toastCloseButton {
66+
flex-shrink: 0;
67+
background: none;
68+
border: none;
69+
padding: 4px;
70+
margin: -4px; /* Offset padding to align */
71+
line-height: 1;
72+
font-size: 20px;
73+
font-weight: 600;
74+
color: currentColor;
75+
opacity: 0.5;
76+
cursor: pointer;
77+
border-radius: 4px;
78+
transition:
79+
opacity 0.2s ease,
80+
background 0.2s ease;
81+
}
82+
83+
.toastCloseButton:hover {
84+
opacity: 1;
85+
}
86+
.toastLight .toastCloseButton:hover {
87+
background: oklch(1 0 0 / 0.1); /* Faint white bg on hover */
88+
}
89+
.toastDark .toastCloseButton:hover {
90+
background: oklch(0 0 0 / 0.1); /* Faint black bg on hover */
91+
}
92+
93+
/* Animation keyframes with a subtle scale for "pop" */
94+
@keyframes slideDownFadeOut {
95+
0% {
96+
opacity: 0;
97+
transform: translateY(-10px) scale(0.95);
98+
}
99+
10%,
100+
90% {
101+
opacity: 1;
102+
transform: translateY(0) scale(1);
103+
}
104+
100% {
105+
opacity: 0;
106+
transform: translateY(-10px) scale(0.95);
107+
}
108+
}

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)