Skip to content

Commit cded041

Browse files
committed
feat: dark/light mode toggle + scrollbar fix (Issue #1639) - made changes but cant able to start the server in my machine tell me if you can run in your machine
1 parent 538d3b9 commit cded041

14 files changed

Lines changed: 284 additions & 81 deletions

File tree

‎public/index.html‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@
3434
<title>ReactPlay - One app to learn, create, and share ReactJS projects.</title>
3535
</head>
3636
<body>
37+
<script>
38+
(function() {
39+
var t = localStorage.getItem('reactplay.theme');
40+
if (t !== 'light' && t !== 'dark') {
41+
t = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
42+
}
43+
document.documentElement.setAttribute('data-theme', t);
44+
})();
45+
</script>
3746
<noscript>You need to enable JavaScript to run this app.</noscript>
3847
<div id="root" class="app-container"></div>
3948
<!--

‎src/App.css‎

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ textarea {
5151
--color-neutral-10-rgb: 255, 255, 255;
5252
--color-neutral-100-rgb: 0, 0, 0;
5353

54+
--scrollbar-size: 12px;
55+
--scrollbar-track: rgba(var(--color-neutral-10-rgb), 0.08);
56+
--scrollbar-thumb: var(--color-brand-primary);
57+
5458
/* Font Family */
5559
--ff-default: Poppins, -apple-system, Roboto, Helvetica Neue, sans-serif;
5660
--ff-accent: Raleway, Inter, -apple-system, Roboto, Helvetica Neue, sans-serif;
@@ -104,6 +108,30 @@ textarea {
104108
--color-play-level-3: 229, 57, 53;
105109
}
106110

111+
/* Dark theme overrides — invert the neutral scale */
112+
html[data-theme='dark'] {
113+
--color-neutral-10: #0b1120;
114+
--color-neutral-20: #111827;
115+
--color-neutral-30: #1e293b;
116+
--color-neutral-40: #334155;
117+
--color-neutral-50: #64748b;
118+
--color-neutral-60: #94a3b8;
119+
--color-neutral-70: #cbd5e1;
120+
--color-neutral-80: #e2e8f0;
121+
--color-neutral-90: #f1f5f9;
122+
--color-neutral-100: #ffffff;
123+
124+
--color-neutral-90-rgb: 241, 245, 249;
125+
--color-neutral-10-rgb: 11, 17, 32;
126+
--color-neutral-100-rgb: 255, 255, 255;
127+
128+
--color-brand-primary: #22d3ee;
129+
--color-brand-primary-rgb: 34, 211, 238;
130+
--color-brand-primary-alt: #67e8f9;
131+
--color-brand-primary-dark: #06b6d4;
132+
}
133+
134+
107135
html,
108136
body {
109137
height: auto;
@@ -115,6 +143,14 @@ body {
115143
-webkit-font-smoothing: antialiased;
116144
-moz-osx-font-smoothing: grayscale;
117145
scroll-behavior: smooth;
146+
overflow-x: clip;
147+
background-color: var(--color-neutral-20);
148+
color: var(--color-neutral-80);
149+
transition: background-color 0.3s ease, color 0.3s ease;
150+
}
151+
152+
#root {
153+
min-height: 100%;
118154
}
119155

120156
body * {
@@ -558,13 +594,17 @@ small {
558594
}
559595

560596
::-webkit-scrollbar-thumb {
561-
background-color: #00f2fe;
597+
background-color: var(--color-brand-primary);
562598
border-radius: 20px;
563-
border: 6px solid transparent;
599+
border: 3px solid transparent;
564600
background-clip: content-box;
565-
height: 100px;
566601
}
567602

568603
::-webkit-scrollbar {
569-
width: 25px;
604+
width: var(--scrollbar-size);
605+
}
606+
607+
* {
608+
scrollbar-width: thin;
609+
scrollbar-color: var(--color-brand-primary) transparent;
570610
}

‎src/ErrorBoundary/ErrorFallback.jsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ const useStyle = makeStyles({
1010
fontWeight: 600
1111
},
1212
Button: {
13-
background: '#00f2fe',
13+
background: 'var(--color-brand-primary)',
1414
color: '#ffffff',
1515
'&:hover': {
16-
background: '#00f2fe',
16+
background: 'var(--color-brand-primary)',
1717
color: '#ffffff'
1818
}
1919
}

‎src/common/components/BackToTop.css‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
height: 56px;
1010
border-radius: 50%;
1111
background: var(--color-brand-primary);
12-
border: 3px solid #fff;
13-
color: #fff;
12+
border: 3px solid var(--color-neutral-10);
13+
color: var(--color-neutral-10);
1414
cursor: pointer;
1515
display: flex;
1616
align-items: center;
1717
justify-content: center;
1818
font-size: 1.5rem;
1919
line-height: 1;
2020
padding: 0;
21-
box-shadow: 0 8px 24px rgba(0, 242, 254, 0.35), inset 0 0 20px rgba(255, 255, 255, 0.1);
21+
box-shadow: 0 8px 24px rgba(var(--color-brand-primary-rgb), 0.35), inset 0 0 20px rgba(var(--color-neutral-10-rgb), 0.1);
2222
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
2323
animation: slideUpButton 0.4s ease-out;
2424
flex-shrink: 0;
@@ -49,9 +49,9 @@
4949

5050
.back-to-top:hover {
5151
background: var(--color-brand-primary);
52-
box-shadow: 0 12px 32px rgba(0, 242, 254, 0.5), inset 0 0 20px rgba(255, 255, 255, 0.2);
52+
box-shadow: 0 12px 32px rgba(var(--color-brand-primary-rgb), 0.5), inset 0 0 20px rgba(var(--color-neutral-10-rgb), 0.2);
5353
transform: translateY(-6px) scale(1.08);
54-
border-color: #00f2fe;
54+
border-color: var(--color-brand-primary);
5555
}
5656

5757
.back-to-top--footer:hover {
@@ -60,7 +60,7 @@
6060

6161
.back-to-top:active {
6262
transform: translateY(-2px) scale(0.96);
63-
box-shadow: 0 4px 16px rgba(0, 242, 254, 0.4), inset 0 0 20px rgba(255, 255, 255, 0.1);
63+
box-shadow: 0 4px 16px rgba(var(--color-brand-primary-rgb), 0.4), inset 0 0 20px rgba(var(--color-neutral-10-rgb), 0.1);
6464
}
6565

6666
/* Footer back-to-top container */
@@ -86,13 +86,13 @@
8686

8787
/* Home Page Specific Styles */
8888
body.home-page .back-to-top {
89-
background: rgba(0, 242, 254, 0.95);
90-
box-shadow: 0 6px 20px rgba(0, 242, 254, 0.4);
89+
background: rgba(var(--color-brand-primary-rgb), 0.95);
90+
box-shadow: 0 6px 20px rgba(var(--color-brand-primary-rgb), 0.4);
9191
}
9292

9393
body.home-page .back-to-top:hover {
9494
background: var(--color-brand-primary);
95-
box-shadow: 0 10px 28px rgba(0, 242, 254, 0.55);
95+
box-shadow: 0 10px 28px rgba(var(--color-brand-primary-rgb), 0.55);
9696
}
9797

9898
@media screen and (max-width: 768px) {
@@ -116,7 +116,7 @@ body.home-page .back-to-top:hover {
116116
width: 48px;
117117
height: 48px;
118118
font-size: 1.1rem;
119-
border: 2px solid #fff;
119+
border: 2px solid var(--color-neutral-10);
120120
}
121121

122122
.back-to-top--footer {

‎src/common/header/HeaderNav.jsx‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import { GoX } from 'react-icons/go';
1212
import { Modal, Box, Typography, Menu } from '@mui/material';
1313
import { useSearchContext } from 'common/search/search-context';
1414
import { PLAY_DOC_LINK, UMAMI_EVENTS } from 'constants';
15+
import { useThemeMode } from 'common/theme/theme-context';
16+
import { BsMoonStarsFill, BsSunFill } from 'react-icons/bs';
1517

1618
const HeaderNav = ({ showBrowse }) => {
1719
const { showShareModal, setShowShareModal } = useSearchContext();
20+
const { theme, toggleTheme } = useThemeMode();
1821

1922
const [showToggleMenu, setShowToggleMenu] = useState(false);
2023
const menuRef = useRef(null);
@@ -185,6 +188,23 @@ const HeaderNav = ({ showBrowse }) => {
185188
</Link>
186189
</li>
187190
)}
191+
<li>
192+
<button
193+
aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
194+
className="app-header-btn app-header-btn--secondary app-header-btn--theme"
195+
data-testid="theme-toggle-btn"
196+
onClick={toggleTheme}
197+
title={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
198+
type="button"
199+
>
200+
{theme === 'dark' ? (
201+
<BsSunFill className="icon" />
202+
) : (
203+
<BsMoonStarsFill className="icon" />
204+
)}
205+
<span className="btn-label">{theme === 'dark' ? 'Light' : 'Dark'}</span>
206+
</button>
207+
</li>
188208
<li className="menu-events">
189209
<a
190210
className="app-header-btn app-header-btn--secondary"

‎src/common/header/header.css‎

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
top: 0;
44
right: 0;
55
left: 0; */
6-
transition: transform 0.3s ease;
6+
transition: transform 0.3s ease, background-color 0.2s ease, color 0.2s ease;
77
z-index: 10;
88
display: flex;
99
justify-content: space-between;
1010
align-items: center;
11-
/* background: rgba(var(--color-brand-primary-rgb), 0.08); */
12-
background: var(--color-neutral-90);
13-
color: #fff;
11+
background: var(--color-neutral-10);
12+
color: var(--color-neutral-80);
1413
height: 64px;
1514
padding: 0 1rem 0 0.6rem;
1615
}
@@ -191,7 +190,7 @@
191190
}
192191

193192
.header-links > li > a {
194-
color: #fff;
193+
color: var(--color-neutral-80);
195194
margin-left: 0;
196195
display: block;
197196
width: var(--navbar-icon-size-rg);
@@ -339,6 +338,17 @@ background-color: var(--color-neutral-10);
339338
margin-left: 0.4rem;
340339
}
341340

341+
.header-links > li > .app-header-btn.app-header-btn--theme {
342+
display: inline-flex;
343+
align-items: center;
344+
gap: 0.4rem;
345+
}
346+
347+
.header-links > li > .app-header-btn.app-header-btn--theme .icon {
348+
fill: var(--color-brand-primary);
349+
color: var(--color-brand-primary);
350+
}
351+
342352
.header-links > li > .app-header-btn.app-header-btn--secondary:hover,
343353
.header-links > li > .app-header-btn.app-header-btn--secondary:focus {
344354
background-color: rgba(var(--color-neutral-10-rgb), 0.1);
@@ -443,7 +453,7 @@ background-color: var(--color-neutral-10);
443453

444454
transform: translate(-50%, -50%);
445455

446-
background: white;
456+
background: var(--color-neutral-10);
447457
box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
448458
-webkit-box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
449459
-moz-box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
@@ -575,3 +585,8 @@ background-color: var(--color-neutral-10);
575585
margin-left: 5px;
576586
cursor: pointer;
577587
}
588+
589+
/* Dark mode header stays dark */
590+
html[data-theme='dark'] .app-header {
591+
background: #0b1120;
592+
}

‎src/common/home/Home.jsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ const Home = () => {
1313
return (
1414
<main>
1515
<section className="app-home-body" id="hero">
16-
<DefaultBanner />
16+
<div className="app-home-body-content">
17+
<DefaultBanner />
18+
</div>
1719
</section>
1820
<section className="home-features">
1921
<HomeFeatures />

0 commit comments

Comments
 (0)