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
29 changes: 23 additions & 6 deletions frontend/src/components/theme/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,27 @@ const ThemeSwitcher: React.FC = () => {
// Don't render until mounted to prevent SSR issues
if (!mounted) {
return (
<div className="grid grid-cols-1">
<div className="relative z-0 inline-grid grid-cols-2 md:grid-cols-3 gap-0.5 rounded-full bg-gray-950/5 p-0.75 text-gray-950 dark:bg-white/10 dark:text-white">
<div className="relative rounded-full p-1.5 *:size-7 bg-white ring ring-gray-950/10 sm:p-0">
{themeConfigs[1].icon}
<div id="theme-switcher-container" className="grid grid-cols-1">
<div className="relative z-0 inline-grid grid-cols-2 gap-0.5 rounded-full bg-gray-950/5 p-0.5 sm:p-0.75 text-gray-950 dark:bg-white/10 dark:text-white">
<div className="relative rounded-full p-0.5 sm:p-1 lg:p-1 theme-active">
<svg viewBox="0 0 28 28" fill="none" className="size-4 sm:size-5 lg:size-6">
Copy link
Contributor

@lovestaco lovestaco Oct 16, 2025

Choose a reason for hiding this comment

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

Is hardcoding the svg in file required? We have many lucide icons,
if its absolutely required, pls put it in public dir and use its url
<img src="/freedevtools/svg_icons/comet/moon.svg">

Ex: https://hexmos.com/freedevtools/svg_icons/comet/moon.svg

<circle cx="14" cy="14" r="3.5" stroke="currentColor"></circle>
<path d="M14 8.5V6.5" stroke="currentColor" strokeLinecap="round"></path>
<path d="M17.889 10.1115L19.3032 8.69727" stroke="currentColor" strokeLinecap="round"></path>
<path d="M19.5 14L21.5 14" stroke="currentColor" strokeLinecap="round"></path>
<path d="M17.889 17.8885L19.3032 19.3027" stroke="currentColor" strokeLinecap="round"></path>
<path d="M14 21.5V19.5" stroke="currentColor" strokeLinecap="round"></path>
<path d="M8.69663 19.3029L10.1108 17.8887" stroke="currentColor" strokeLinecap="round"></path>
<path d="M6.5 14L8.5 14" stroke="currentColor" strokeLinecap="round"></path>
<path d="M8.69663 8.69711L10.1108 10.1113" stroke="currentColor" strokeLinecap="round"></path>
</svg>
</div>
<div className="relative rounded-full p-0.5 sm:p-1 lg:p-1">
<svg viewBox="0 0 28 28" fill="none" className="size-4 sm:size-5 lg:size-6">
<path d="M10.5 9.99914C10.5 14.1413 13.8579 17.4991 18 17.4991C19.0332 17.4991 20.0176 17.2902 20.9132 16.9123C19.7761 19.6075 17.109 21.4991 14 21.4991C9.85786 21.4991 6.5 18.1413 6.5 13.9991C6.5 10.8902 8.39167 8.22304 11.0868 7.08594C10.7089 7.98159 10.5 8.96597 10.5 9.99914Z" stroke="currentColor" strokeLinejoin="round"></path>
<path d="M16.3561 6.50754L16.5 5.5L16.6439 6.50754C16.7068 6.94752 17.0525 7.29321 17.4925 7.35607L18.5 7.5L17.4925 7.64393C17.0525 7.70679 16.7068 8.05248 16.6439 8.49246L16.5 9.5L16.3561 8.49246C16.2932 8.05248 15.9475 7.70679 15.5075 7.64393L14.5 7.5L15.5075 7.35607C15.9475 7.29321 16.2932 6.94752 16.3561 6.50754Z" fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M20.3561 11.5075L20.5 10.5L20.6439 11.5075C20.7068 11.9475 21.0525 12.2932 21.4925 12.3561L22.5 12.5L21.4925 12.6439C21.0525 12.7068 20.7068 13.0525 20.6439 13.4925L20.5 14.5L20.3561 13.4925C20.2932 13.0525 19.9475 12.7068 19.5075 12.6439L18.5 12.5L19.5075 12.3561C19.9475 12.2932 20.2932 11.9475 20.3561 11.5075Z" fill="currentColor" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"></path>
</svg>
</div>
</div>
</div>
Expand All @@ -165,7 +182,7 @@ const ThemeSwitcher: React.FC = () => {
// );

return (
<div className="grid grid-cols-1">
<div id="theme-switcher-container" className="grid grid-cols-1">
<div
className="relative z-0 inline-grid gap-0.5 rounded-full bg-gray-950/5 p-0.5 sm:p-0.75 text-gray-950 dark:bg-white/10 dark:text-white"
style={{
Expand All @@ -180,7 +197,7 @@ const ThemeSwitcher: React.FC = () => {
"p-0.5 *:size-4 sm:p-1 sm:*:size-5 lg:p-1 lg:*:size-6"
} ${
theme === config.type
? "bg-white ring ring-gray-950/10 dark:bg-gray-600 dark:ring-white/10"
? "theme-active bg-white ring ring-gray-950/10 dark:bg-gray-600 dark:ring-white/10"
: "hover:bg-gray-100 dark:hover:bg-gray-700"
}`}
onClick={() => handleThemeChange(config.type)}
Expand Down
72 changes: 72 additions & 0 deletions frontend/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,78 @@ const GA_MEASUREMENT_ID = 'G-WXSDF484XZ';
<link rel="stylesheet" href="/freedevtools/fonts/fonts.css">


<!-- Critical CSS for Theme Switcher to prevent FOUC -->
<style>
/* Prevent theme toggle FOUC by inlining critical styles */
#theme-switcher-container {
display: grid;
grid-template-columns: 1fr;
}

#theme-switcher-container > div {
position: relative;
z-index: 0;
display: inline-grid;
gap: 0.125rem;
border-radius: 9999px;
background-color: rgba(0, 0, 0, 0.05);
padding: 0.125rem;
color: rgb(9, 9, 11);
}

.dark #theme-switcher-container > div {
background-color: rgba(255, 255, 255, 0.1);
color: rgb(255, 255, 255);
}

#theme-switcher-container button,
#theme-switcher-container > div > div {
position: relative;
border-radius: 9999px;
cursor: pointer;
transition: all 0.2s;
padding: 0.125rem;
}

#theme-switcher-container svg {
width: 1rem;
height: 1rem;
}

@media (min-width: 640px) {
#theme-switcher-container > div {
padding: 0.1875rem;
}

#theme-switcher-container button,
#theme-switcher-container > div > div {
padding: 0.25rem;
}

#theme-switcher-container svg {
width: 1.25rem;
height: 1.25rem;
}
}

@media (min-width: 1024px) {
#theme-switcher-container svg {
width: 1.5rem;
height: 1.5rem;
}
}

#theme-switcher-container .theme-active {
background-color: rgb(255, 255, 255);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
}

.dark #theme-switcher-container .theme-active {
background-color: rgb(75, 85, 99);
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1);
}
</style>

<!-- Theme initialization script -->
<script>
(function() {
Expand Down