Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
<title>ReactPlay - One app to learn, create, and share ReactJS projects.</title>
</head>
<body>
<script>
(function() {
var t = localStorage.getItem('reactplay.theme');
if (t !== 'light' && t !== 'dark') {
t = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
Comment on lines +39 to +41
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline anti-FOUC script assumes localStorage access always succeeds. In some environments (e.g., privacy modes or restricted storage), localStorage.getItem can throw and break the script. Wrap the localStorage read in a try/catch (and fall back to prefers-color-scheme) so a storage exception doesn’t prevent the theme attribute from being set.

Suggested change
var t = localStorage.getItem('reactplay.theme');
if (t !== 'light' && t !== 'dark') {
t = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
var t = null;
try {
t = localStorage.getItem('reactplay.theme');
} catch (e) {
t = null;
}
if (t !== 'light' && t !== 'dark') {
var m = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
t = m && m.matches ? 'dark' : 'light';

Copilot uses AI. Check for mistakes.
}
document.documentElement.setAttribute('data-theme', t);
})();
</script>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root" class="app-container"></div>
<!--
Expand Down
48 changes: 44 additions & 4 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ textarea {
--color-neutral-10-rgb: 255, 255, 255;
--color-neutral-100-rgb: 0, 0, 0;

--scrollbar-size: 12px;
--scrollbar-track: rgba(var(--color-neutral-10-rgb), 0.08);
--scrollbar-thumb: var(--color-brand-primary);

Comment on lines +54 to +57
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--scrollbar-track and --scrollbar-thumb are defined here but the scrollbar rules below use transparent / var(--color-brand-primary) directly instead of these variables. Either wire the rules to the variables or remove the unused tokens to avoid confusion about the source of truth.

Suggested change
--scrollbar-size: 12px;
--scrollbar-track: rgba(var(--color-neutral-10-rgb), 0.08);
--scrollbar-thumb: var(--color-brand-primary);

Copilot uses AI. Check for mistakes.
/* Font Family */
--ff-default: Poppins, -apple-system, Roboto, Helvetica Neue, sans-serif;
--ff-accent: Raleway, Inter, -apple-system, Roboto, Helvetica Neue, sans-serif;
Expand Down Expand Up @@ -104,6 +108,30 @@ textarea {
--color-play-level-3: 229, 57, 53;
}

/* Dark theme overrides — invert the neutral scale */
html[data-theme='dark'] {
--color-neutral-10: #0b1120;
--color-neutral-20: #111827;
--color-neutral-30: #1e293b;
--color-neutral-40: #334155;
--color-neutral-50: #64748b;
--color-neutral-60: #94a3b8;
--color-neutral-70: #cbd5e1;
--color-neutral-80: #e2e8f0;
--color-neutral-90: #f1f5f9;
--color-neutral-100: #ffffff;

--color-neutral-90-rgb: 241, 245, 249;
--color-neutral-10-rgb: 11, 17, 32;
--color-neutral-100-rgb: 255, 255, 255;

--color-brand-primary: #22d3ee;
--color-brand-primary-rgb: 34, 211, 238;
--color-brand-primary-alt: #67e8f9;
--color-brand-primary-dark: #06b6d4;
}


html,
body {
height: auto;
Expand All @@ -115,6 +143,14 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
overflow-x: clip;
background-color: var(--color-neutral-20);
color: var(--color-neutral-80);
transition: background-color 0.3s ease, color 0.3s ease;
}

#root {
min-height: 100%;
}

body * {
Expand Down Expand Up @@ -558,13 +594,17 @@ small {
}

::-webkit-scrollbar-thumb {
background-color: #00f2fe;
background-color: var(--color-brand-primary);
border-radius: 20px;
border: 6px solid transparent;
border: 3px solid transparent;
background-clip: content-box;
height: 100px;
}

::-webkit-scrollbar {
width: 25px;
width: var(--scrollbar-size);
}

* {
scrollbar-width: thin;
scrollbar-color: var(--color-brand-primary) transparent;
}
4 changes: 2 additions & 2 deletions src/ErrorBoundary/ErrorFallback.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ const useStyle = makeStyles({
fontWeight: 600
},
Button: {
background: '#00f2fe',
background: 'var(--color-brand-primary)',
color: '#ffffff',
'&:hover': {
background: '#00f2fe',
background: 'var(--color-brand-primary)',
color: '#ffffff'
Comment on lines +13 to 17
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With dark mode enabled, --color-brand-primary is a light cyan, but this button text stays hardcoded to #ffffff, which will likely fail contrast requirements (light text on light background). Consider switching the text color to a theme-aware variable (e.g., an “on-brand-primary” token) so the button remains readable in both themes.

Copilot uses AI. Check for mistakes.
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/common/components/BackToTop.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
height: 56px;
border-radius: 50%;
background: var(--color-brand-primary);
border: 3px solid #fff;
color: #fff;
border: 3px solid var(--color-neutral-10);
color: var(--color-neutral-10);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
line-height: 1;
padding: 0;
box-shadow: 0 8px 24px rgba(0, 242, 254, 0.35), inset 0 0 20px rgba(255, 255, 255, 0.1);
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);
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
animation: slideUpButton 0.4s ease-out;
flex-shrink: 0;
Expand Down Expand Up @@ -49,9 +49,9 @@

.back-to-top:hover {
background: var(--color-brand-primary);
box-shadow: 0 12px 32px rgba(0, 242, 254, 0.5), inset 0 0 20px rgba(255, 255, 255, 0.2);
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);
transform: translateY(-6px) scale(1.08);
border-color: #00f2fe;
border-color: var(--color-brand-primary);
}

.back-to-top--footer:hover {
Expand All @@ -60,7 +60,7 @@

.back-to-top:active {
transform: translateY(-2px) scale(0.96);
box-shadow: 0 4px 16px rgba(0, 242, 254, 0.4), inset 0 0 20px rgba(255, 255, 255, 0.1);
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);
}

/* Footer back-to-top container */
Expand All @@ -86,13 +86,13 @@

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

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

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

.back-to-top--footer {
Expand Down
20 changes: 20 additions & 0 deletions src/common/header/HeaderNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import { GoX } from 'react-icons/go';
import { Modal, Box, Typography, Menu } from '@mui/material';
import { useSearchContext } from 'common/search/search-context';
import { PLAY_DOC_LINK, UMAMI_EVENTS } from 'constants';
import { useThemeMode } from 'common/theme/theme-context';
import { BsMoonStarsFill, BsSunFill } from 'react-icons/bs';

const HeaderNav = ({ showBrowse }) => {
const { showShareModal, setShowShareModal } = useSearchContext();
const { theme, toggleTheme } = useThemeMode();

const [showToggleMenu, setShowToggleMenu] = useState(false);
const menuRef = useRef(null);
Expand Down Expand Up @@ -185,6 +188,23 @@ const HeaderNav = ({ showBrowse }) => {
</Link>
</li>
)}
<li>
<button
aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
className="app-header-btn app-header-btn--secondary app-header-btn--theme"
data-testid="theme-toggle-btn"
onClick={toggleTheme}
title={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
type="button"
>
{theme === 'dark' ? (
<BsSunFill className="icon" />
) : (
<BsMoonStarsFill className="icon" />
)}
<span className="btn-label">{theme === 'dark' ? 'Light' : 'Dark'}</span>
</button>
</li>
<li className="menu-events">
<a
className="app-header-btn app-header-btn--secondary"
Expand Down
27 changes: 21 additions & 6 deletions src/common/header/header.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
top: 0;
right: 0;
left: 0; */
transition: transform 0.3s ease;
transition: transform 0.3s ease, background-color 0.2s ease, color 0.2s ease;
z-index: 10;
display: flex;
justify-content: space-between;
align-items: center;
/* background: rgba(var(--color-brand-primary-rgb), 0.08); */
background: var(--color-neutral-90);
color: #fff;
background: var(--color-neutral-10);
color: var(--color-neutral-80);
height: 64px;
padding: 0 1rem 0 0.6rem;
}
Expand Down Expand Up @@ -191,7 +190,7 @@
}

.header-links > li > a {
color: #fff;
color: var(--color-neutral-80);
margin-left: 0;
display: block;
width: var(--navbar-icon-size-rg);
Expand Down Expand Up @@ -339,6 +338,17 @@ background-color: var(--color-neutral-10);
margin-left: 0.4rem;
}

.header-links > li > .app-header-btn.app-header-btn--theme {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}

.header-links > li > .app-header-btn.app-header-btn--theme .icon {
fill: var(--color-brand-primary);
color: var(--color-brand-primary);
}

.header-links > li > .app-header-btn.app-header-btn--secondary:hover,
.header-links > li > .app-header-btn.app-header-btn--secondary:focus {
background-color: rgba(var(--color-neutral-10-rgb), 0.1);
Expand Down Expand Up @@ -443,7 +453,7 @@ background-color: var(--color-neutral-10);

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

background: white;
background: var(--color-neutral-10);
box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
-webkit-box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
-moz-box-shadow: 0px 0 26px 0px rgba(var(--color-neutral-90-rgb), 0.62);
Expand Down Expand Up @@ -575,3 +585,8 @@ background-color: var(--color-neutral-10);
margin-left: 5px;
cursor: pointer;
}

/* Dark mode header stays dark */
html[data-theme='dark'] .app-header {
background: #0b1120;
}
Comment on lines +588 to +592
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dark-mode override hardcodes #0b1120, which duplicates the --color-neutral-10 value already set under html[data-theme='dark'] in App.css (and the header background is already var(--color-neutral-10)). Consider removing this rule or switching it to background: var(--color-neutral-10) to avoid redundant/duplicated theme constants.

Suggested change
/* Dark mode header stays dark */
html[data-theme='dark'] .app-header {
background: #0b1120;
}

Copilot uses AI. Check for mistakes.
4 changes: 3 additions & 1 deletion src/common/home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const Home = () => {
return (
<main>
<section className="app-home-body" id="hero">
<DefaultBanner />
<div className="app-home-body-content">
<DefaultBanner />
</div>
</section>
<section className="home-features">
<HomeFeatures />
Expand Down
Loading
Loading