Skip to content
Draft
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
37 changes: 37 additions & 0 deletions client/src/components/ThemeSync.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { gql } from '@apollo/client';
import { useTheme } from 'next-themes';
import { useEffect } from 'react';

import { useGQLUserThemePreferenceQuery } from '../graphql/generated';
import { NEXT_THEME_FOR_PREFERENCE } from '../models/theme';

gql`
query UserThemePreference {
me {
id
interfacePreferences {
themePreference
}
}
}
`;

/**
* Applies the signed-in user's persisted theme preference to next-themes.
* Renders nothing; mount once inside the authenticated shell so it never
* runs on the login/signup pages (those follow the system scheme).
*/
export default function ThemeSync() {
const { setTheme } = useTheme();
const { data } = useGQLUserThemePreferenceQuery();

const themePreference = data?.me?.interfacePreferences?.themePreference;

useEffect(() => {
if (themePreference) {
setTheme(NEXT_THEME_FOR_PREFERENCE[themePreference]);
}
}, [themePreference, setTheme]);

return null;
}
181 changes: 181 additions & 0 deletions client/src/graphql/generated.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 17 additions & 4 deletions client/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@apollo/client';
import { KeyFieldsContext } from '@apollo/client/cache/inmemory/policies';
import { RetryLink } from '@apollo/client/link/retry';
import { ThemeProvider } from 'next-themes';
import { createRoot } from 'react-dom/client';
import { HelmetProvider } from 'react-helmet-async';
import stringify from 'safe-stable-stringify';
Expand Down Expand Up @@ -148,10 +149,22 @@ const root = createRoot(document.getElementById('root')!);
root.render(
<HelmetProvider>
<ApolloProvider client={client}>
<TooltipProvider>
<App />
<Toast position="bottom-right" />
</TooltipProvider>
{/* defaultTheme is "light" (not "system") until the app-wide dark
restyle lands — otherwise every dark-OS user gets unconverted
components on day one. Users can still opt into System/Dark in
account settings. */}
<ThemeProvider
attribute="class"
defaultTheme="light"
enableSystem
enableColorScheme
disableTransitionOnChange
>
<TooltipProvider>
<App />
<Toast position="bottom-right" />
</TooltipProvider>
</ThemeProvider>
</ApolloProvider>
</HelmetProvider>,
);
Expand Down
22 changes: 22 additions & 0 deletions client/src/models/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { GQLThemePreference } from '../graphql/generated';

export const THEME_PREFERENCES = [
GQLThemePreference.System,
GQLThemePreference.Light,
GQLThemePreference.Dark,
] as const;

export const THEME_PREFERENCE_LABELS: Record<GQLThemePreference, string> = {
[GQLThemePreference.System]: 'System',
[GQLThemePreference.Light]: 'Light',
[GQLThemePreference.Dark]: 'Dark',
};

export const NEXT_THEME_FOR_PREFERENCE: Record<
GQLThemePreference,
'system' | 'light' | 'dark'
> = {
[GQLThemePreference.System]: 'system',
[GQLThemePreference.Light]: 'light',
[GQLThemePreference.Dark]: 'dark',
};
2 changes: 1 addition & 1 deletion client/src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ body {

@layer base {
:root {
--background: 0 0% 100%;
--background: 0 0% 97.6%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
Expand Down
2 changes: 1 addition & 1 deletion client/src/webpages/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default function App() {
);

return (
<div className="bg-[#F9F9F9] flex flex-col w-full h-full bottom-0 relative">
<div className="bg-background flex flex-col w-full h-full bottom-0 relative">
<RouterProvider router={router} />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion client/src/webpages/dashboard/Dashboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ body {

@layer base {
:root {
--background: 0 0% 100%;
--background: 0 0% 97.6%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
Expand Down
8 changes: 6 additions & 2 deletions client/src/webpages/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import useDynamicLegacyCSS from '@/hooks/useDynamicLegacyCSS';

import ErrorBoundary from '@/components/ErrorBoundary';
import Sidebar, { MenuItem } from '@/components/Sidebar';
import ThemeSync from '@/components/ThemeSync';

import {
GQLUserPermission,
Expand Down Expand Up @@ -704,11 +705,14 @@ export default function Dashboard() {

return (
<div
className={`flex w-full h-screen${isUsingLegacyCSS ? '' : ' bg-slate-50'}`}
className={`flex w-full h-screen${
isUsingLegacyCSS ? '' : ' bg-slate-50 dark:bg-neutral-950'
}`}
>
<Helmet>
<title>Home</title>
</Helmet>
<ThemeSync />
<Sidebar
menuItems={menuItems}
settingsMenuItems={settingsMenuItems}
Expand All @@ -720,7 +724,7 @@ export default function Dashboard() {
/>
{isUsingLegacyCSS ? (
<>
<div className="w-px h-full bg-[#e5e7eb]" />
<div className="w-px h-full bg-[#e5e7eb] dark:bg-neutral-800" />
<div className="flex justify-center w-full px-12 py-8 overflow-auto">
<ErrorBoundary
key={pathname}
Expand Down
Loading
Loading