Skip to content

Commit

Permalink
Merge pull request #107 from karlromets/fix/theme-state
Browse files Browse the repository at this point in the history
Fix theme state
  • Loading branch information
joshzcold authored Jan 2, 2025
2 parents 73bb9b7 + 16d3aaa commit 48c8349
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 179 deletions.
87 changes: 87 additions & 0 deletions components/Admin/ThemeSwitcher.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Palette } from "lucide-react";
import { useTheme } from 'next-themes';
import { useTranslation } from "react-i18next";

const ThemeSwitcher = ({game, setGame, send}) => {
const { t } = useTranslation();
const { theme, setTheme } = useTheme();

const availableThemes = {
default: {
bgcolor: "white",
fgcolor: "text-black",
title: "default",
},
darkTheme: {
bgcolor: "#18181B",
fgcolor: "text-white",
title: "dark theme",
},
slate: {
bgcolor: "#18181B",
fgcolor: "text-white",
title: "slate",
},
educational: {
bgcolor: "#fffbf0",
fgcolor: "text-black",
title: "educational",
},
red: {
bgcolor: "#7B2C35",
fgcolor: "text-white",
title: "red",
},
};

const handleThemeChange = (newTheme) => {
try {
setTheme(newTheme);

// Create deep copy of game state
const updatedGame = JSON.parse(JSON.stringify(game));
updatedGame.settings.theme = newTheme;

// Update local state
setGame(updatedGame);

// Send update to server
send({
action: "data",
data: updatedGame
});
} catch (error) {
console.error('Error updating theme:', error);
// Revert theme on error
setTheme(game.settings.theme);
}
}

return (
<div className="flex flex-row space-x-5 items-center">
<Palette color="gray" />
<select
id="themeSwitcherInput"
className="bg-secondary-300 text-foreground rounded-lg p-2 capitalize w-full sm:w-fit"
value={theme || 'default'}
onChange={(e) => handleThemeChange(e.target.value)}
aria-label={t("Select theme")}
>
{Object.keys(availableThemes).map((key) => (
<option
value={key}
key={`theme-${key}`}
style={{
backgroundColor: availableThemes[key].bgcolor
}}
className={`${availableThemes[key].fgcolor} capitalize`}
>
{availableThemes[key].title}
</option>
))}
</select>
</div>
);
}

export default ThemeSwitcher;
71 changes: 2 additions & 69 deletions components/Admin/settings.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useTranslation } from "react-i18next";
import "i18n/i18n";
import "tailwindcss/tailwind.css";
import ThemeSwitcher from "./ThemeSwitcher";
import InfoTooltip from "../ui/tooltip";

function debounce(callback, wait = 400) {
Expand All @@ -13,75 +14,7 @@ function debounce(callback, wait = 400) {
};
}

export function ThemeSwitcher(props) {
const availableThemes = {
default: {
bgcolor: "white",
fgcolor: "text-black",
title: "default",
},
darkTheme: {
bgcolor: "#18181B",
fgcolor: "text-white",
title: "dark theme",
},
slate: {
bgcolor: "#18181B",
fgcolor: "text-white",
title: "slate",
},
educational: {
bgcolor: "#fffbf0",
fgcolor: "text-black",
title: "educational",
},
red: {
bgcolor: "#7B2C35",
fgcolor: "text-white",
title: "red",
},
};
return (
<div className="flex flex-row space-x-5 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
role="img"
width="32"
height="32"
viewBox="0 0 16 16"
>
<path
d="M8 1.002v2.5a.5.5 0 0 0 1 0v-2.5h1v3.494a.5.5 0 0 0 1 0V1.002h1.5V7h-9V1.002H8ZM3.5 8v.5a2 2 0 0 0 2 2h1v2.999a1.5 1.5 0 0 0 3 0v-3h1a2 2 0 0 0 2-2V8h-9Z"
fill="gray"
/>
</svg>
<select
id="themeSwitcherInput"
className="bg-secondary-300 text-foreground rounded-lg p-2"
value={props.game.settings.theme}
onChange={(e) => {
props.game.settings.theme = e.target.value;
props.setGame((prv) => ({ ...prv }));
props.send({ action: "data", data: props.game });
}}
>
{Object.keys(availableThemes).map((key, index) => (
<option
value={key}
key={`theme-${index}`}
style={{
backgroundColor: availableThemes[key].bgcolor
}}
className={`${availableThemes[key].fgcolor}`}
>
{availableThemes[key].title}
</option>
))}
</select>
</div>
);
}


function FinalRoundTitleChanger(props) {
const { i18n, t } = useTranslation();
Expand Down
61 changes: 61 additions & 0 deletions components/Login/Footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useTranslation } from "react-i18next";
import "i18n/i18n";
import { Coffee, Mail } from "lucide-react";

const Donate = () => {
const { t } = useTranslation();
return (
<div className="flex flex-row items-center space-x-4">
<a href="https://liberapay.com/joshuaCold" target="blank" rel="noopener noreferrer" className="flex gap-2 items-center">
<p className="text-secondary-900 text-sm capitalize">{t("donate")}</p>
<Coffee color="gray" />
</a>
</div>
);
}
const Email = () => {
const { t } = useTranslation();
return (
<div className="flex flex-row items-center space-x-4">
<a href="mailto: joshzcold@gmail.com" className="flex gap-2 items-center">
<p className="text-secondary-900 text-sm capitalize">{t("email")}</p>
<Mail color="gray" />
</a>
</div>
);
}

const SourceCode = () => {
const { t } = useTranslation();
return (
<div className="flex flex-row items-center space-x-4">
<a href="https://github.com/joshzcold/Cold-Friendly-Feud" target="_blank" rel="noopener noreferrer" className="flex gap-2 items-center">
<p className="text-secondary-900 text-sm capitalize">{t("source code")}</p>
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="gray"
width="24"
height="24"
>
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
</svg>
</a>
</div>
);
}

export default function Footer(props) {
return (
<div className="absolute bottom-0 left-0 min-w-full bg-background">
<hr />
<div className="flex flex-row items-center justify-evenly py-3">
<SourceCode />
<Email />
<Donate />
</div>
</div>
);
}
78 changes: 0 additions & 78 deletions components/Login/footer.js

This file was deleted.

31 changes: 31 additions & 0 deletions components/ThemeProvider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { useEffect, useState } from 'react';

const ThemeProvider = ({ children }) => {
const [mounted, setMounted] = useState(false);

useEffect(() => {
setMounted(true);
}, []);

if (!mounted) return null;

return (
<NextThemesProvider
attribute="class"
defaultTheme="default"
value={{
default: "default",
darkTheme: "darkTheme",
slate: "slate",
educational: "educational",
red: "red"
}}
storageKey="theme"
>
{children}
</NextThemesProvider>
);
};

export default ThemeProvider;
20 changes: 4 additions & 16 deletions components/language.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
import { Languages } from "lucide-react";
import React from "react";
import { useTranslation } from "react-i18next";

export default function LanguageSwitcher(props) {
const { i18n, t } = useTranslation();
return (
<div className="flex flex-row space-x-5">
<svg
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
role="img"
width="2em"
height="2em"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10s10-4.486 10-10S17.514 2 12 2zM4 12c0-.899.156-1.762.431-2.569L6 11l2 2v2l2 2l1 1v1.931C7.061 19.436 4 16.072 4 12zm14.33 4.873C17.677 16.347 16.687 16 16 16v-1a2 2 0 0 0-2-2h-4v-3a2 2 0 0 0 2-2V7h1a2 2 0 0 0 2-2v-.411C17.928 5.778 20 8.65 20 12a7.947 7.947 0 0 1-1.67 4.873z"
fill="gray"
/>
</svg>
<div className="flex items-center gap-4 ">
<Languages color="gray" />
<select
id="languageInput"
className="bg-secondary-300 text-foreground"
className="bg-secondary-300 text-foreground rounded-lg p-2 capitalize w-full sm:w-fit"
value={i18n.language}
onChange={
props.onChange
Expand Down
Loading

0 comments on commit 48c8349

Please sign in to comment.