Skip to content

Commit

Permalink
fix: custom theme persisting after signing out (#1780)
Browse files Browse the repository at this point in the history
* fix: custom theme persistence

* chore: remove console logs

* fix: build error

* fix: change theme from command k
  • Loading branch information
aaryan610 authored Aug 3, 2023
1 parent 5aad6c7 commit 97c3fb4
Show file tree
Hide file tree
Showing 17 changed files with 287 additions and 307 deletions.
38 changes: 33 additions & 5 deletions apps/app/components/command-palette/change-interface-theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,59 @@ import { Command } from "cmdk";
import { THEMES_OBJ } from "constants/themes";
import { useTheme } from "next-themes";
import { SettingIcon } from "components/icons";
import userService from "services/user.service";
import useUser from "hooks/use-user";

type Props = {
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
};

export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
const [mounted, setMounted] = useState(false);

const { setTheme } = useTheme();

const { user, mutateUser } = useUser();

const updateUserTheme = (newTheme: string) => {
if (!user) return;

setTheme(newTheme);

mutateUser((prevData) => {
if (!prevData) return prevData;

return {
...prevData,
theme: {
...prevData.theme,
theme: newTheme,
},
};
}, false);

userService.updateUser({
theme: {
...user.theme,
theme: newTheme,
},
});
};

// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
setMounted(true);
}, []);

if (!mounted) {
return null;
}
if (!mounted) return null;

return (
<>
{THEMES_OBJ.map((theme) => (
{THEMES_OBJ.filter((t) => t.value !== "custom").map((theme) => (
<Command.Item
key={theme.value}
onSelect={() => {
setTheme(theme.value);
updateUserTheme(theme.value);
setIsPaletteOpen(false);
}}
className="focus:outline-none"
Expand Down
2 changes: 2 additions & 0 deletions apps/app/components/core/theme/custom-theme-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const defaultValues: ICustomTheme = {
sidebarText: "#c5c5c5",
darkPalette: false,
palette: "",
theme: "custom",
};

export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
Expand Down Expand Up @@ -56,6 +57,7 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
sidebarText: formData.sidebarText,
darkPalette: darkPalette,
palette: `${formData.background},${formData.text},${formData.primary},${formData.sidebarBackground},${formData.sidebarText}`,
theme: "custom",
};

await userService
Expand Down
221 changes: 120 additions & 101 deletions apps/app/components/core/theme/theme-switch.tsx
Original file line number Diff line number Diff line change
@@ -1,142 +1,161 @@
import { useState, useEffect, Dispatch, SetStateAction } from "react";
import { useState, useEffect } from "react";

// next-themes
import { useTheme } from "next-themes";

// services
import userService from "services/user.service";
// hooks
import useUser from "hooks/use-user";
// constants
import { THEMES_OBJ } from "constants/themes";
// ui
import { CustomSelect } from "components/ui";
// types
import { ICustomTheme, IUser } from "types";
import { ICustomTheme } from "types";
import { unsetCustomCssVariables } from "helpers/theme.helper";

type Props = {
user: IUser | undefined;
setPreLoadedData: Dispatch<SetStateAction<ICustomTheme | null>>;
setPreLoadedData: React.Dispatch<React.SetStateAction<ICustomTheme | null>>;
customThemeSelectorOptions: boolean;
setCustomThemeSelectorOptions: Dispatch<SetStateAction<boolean>>;
setCustomThemeSelectorOptions: React.Dispatch<React.SetStateAction<boolean>>;
};

export const ThemeSwitch: React.FC<Props> = ({
user,
setPreLoadedData,
customThemeSelectorOptions,
setCustomThemeSelectorOptions,
}) => {
const [mounted, setMounted] = useState(false);

const { theme, setTheme } = useTheme();

const { user, mutateUser } = useUser();

const updateUserTheme = (newTheme: string) => {
if (!user) return;

setTheme(newTheme);

mutateUser((prevData) => {
if (!prevData) return prevData;

return {
...prevData,
theme: {
...prevData.theme,
theme: newTheme,
},
};
}, false);

userService.updateUser({
theme: {
...user.theme,
theme: newTheme,
},
});
};

// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
setMounted(true);
}, []);

if (!mounted) {
return null;
}
if (!mounted) return null;

const currentThemeObj = THEMES_OBJ.find((t) => t.value === theme);

return (
<>
<CustomSelect
value={theme}
label={
currentThemeObj ? (
<div className="flex items-center gap-2">
<CustomSelect
value={theme}
label={
currentThemeObj ? (
<div className="flex items-center gap-2">
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
borderColor: currentThemeObj.icon.border,
}}
>
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
className="h-full w-1/2 rounded-l-full"
style={{
borderColor: currentThemeObj.icon.border,
background: currentThemeObj.icon.color1,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: currentThemeObj.icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: currentThemeObj.icon.border,
background: currentThemeObj.icon.color2,
}}
/>
</div>
{currentThemeObj.label}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: currentThemeObj.icon.border,
background: currentThemeObj.icon.color2,
}}
/>
</div>
) : (
"Select your theme"
)
}
onChange={({ value, type }: { value: string; type: string }) => {
if (value === "custom") {
if (user?.theme.palette) {
setPreLoadedData({
background: user.theme.background !== "" ? user.theme.background : "#0d101b",
text: user.theme.text !== "" ? user.theme.text : "#c5c5c5",
primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff",
sidebarBackground:
user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b",
sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5",
darkPalette: false,
palette:
user.theme.palette !== ",,,,"
? user.theme.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
});
}

if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);

for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
document.documentElement.style.removeProperty(`--color-background-${i}`);
document.documentElement.style.removeProperty(`--color-text-${i}`);
document.documentElement.style.removeProperty(`--color-border-${i}`);
document.documentElement.style.removeProperty(`--color-primary-${i}`);
document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`);
document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`);
document.documentElement.style.removeProperty(`--color-sidebar-border-${i}`);
}
{currentThemeObj.label}
</div>
) : (
"Select your theme"
)
}
onChange={({ value, type }: { value: string; type: string }) => {
if (value === "custom") {
if (user?.theme.palette) {
setPreLoadedData({
background: user.theme.background !== "" ? user.theme.background : "#0d101b",
text: user.theme.text !== "" ? user.theme.text : "#c5c5c5",
primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff",
sidebarBackground:
user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b",
sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5",
darkPalette: false,
palette:
user.theme.palette !== ",,,,"
? user.theme.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
theme: "custom",
});
}

setTheme(value);
document.documentElement.style.setProperty("color-scheme", type);
}}
input
width="w-full"
position="right"
>
{THEMES_OBJ.map(({ value, label, type, icon }) => (
<CustomSelect.Option key={value} value={{ value, type }}>
<div className="flex items-center gap-2">
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
unsetCustomCssVariables();
}

updateUserTheme(value);
document.documentElement.style.setProperty("--color-scheme", type);
}}
input
width="w-full"
position="right"
>
{THEMES_OBJ.map(({ value, label, type, icon }) => (
<CustomSelect.Option key={value} value={{ value, type }}>
<div className="flex items-center gap-2">
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
borderColor: icon.border,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: icon.color1,
}}
/>
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderColor: icon.border,
borderLeftColor: icon.border,
background: icon.color2,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: icon.border,
background: icon.color2,
}}
/>
</div>
{label}
/>
</div>
</CustomSelect.Option>
))}
</CustomSelect>
</>
{label}
</div>
</CustomSelect.Option>
))}
</CustomSelect>
);
};
6 changes: 3 additions & 3 deletions apps/app/components/workspace/sidebar-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { Fragment } from "react";
import { useRouter } from "next/router";
import Link from "next/link";

// next-themes
import { useTheme } from "next-themes";
// headless ui
import { Menu, Transition } from "@headlessui/react";
// next-themes
import { useTheme } from "next-themes";
// hooks
import useUser from "hooks/use-user";
import useThemeHook from "hooks/use-theme";
Expand Down Expand Up @@ -91,7 +91,7 @@ export const WorkspaceSidebarDropdown = () => {
.then(() => {
mutateUser(undefined);
router.push("/");
setTheme("dark");
setTheme("system");
})
.catch(() =>
setToastAlert({
Expand Down
10 changes: 10 additions & 0 deletions apps/app/constants/themes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
export const THEMES = ["light", "dark", "light-contrast", "dark-contrast", "custom"];

export const THEMES_OBJ = [
{
value: "system",
label: "System Preference",
type: "light",
icon: {
border: "#DEE2E6",
color1: "#FAFAFA",
color2: "#3F76FF",
},
},
{
value: "light",
label: "Light",
Expand Down
Loading

1 comment on commit 97c3fb4

@vercel
Copy link

@vercel vercel bot commented on 97c3fb4 Aug 3, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

plane-dev – ./apps/app

plane-dev-plane.vercel.app
plane-dev.vercel.app
plane-dev-git-develop-plane.vercel.app

Please sign in to comment.