Repository: gitify-app/gitify (ts)

Issue:
feat: add support for GitHub Theme Color Schemes
### 📝 Provide a description of the new feature

Currently we support two color schemes (light and dark)

This enhancement suggestion is to expand this to support the 9 GitHub color schemes available

![Image](https://github.com/user-attachments/assets/345302a5-9fd6-4f41-8a55-b6a72af77dc4)

### ➕ Additional Information

See https://primer.style/guides/react/theming#color-modes-and-color-schemes


Pull request:
feat: primer color schemes
Closes #1748

![Screenshot 2025-01-22 at 2 39 47 PM](https://github.com/user-attachments/assets/7c85d259-fc43-41a4-9dbb-76d33d15028b)

TODO
- [x] update AppearanceSetting theme selection test

Patch:
diff --git a/package.json b/package.json
index 33aaf0ac..42c1bd9e 100644
--- a/package.json
+++ b/package.json
@@ -140,7 +140,7 @@
     "@discordapp/twemoji": "15.1.0",
     "@electron/notarize": "2.5.0",
     "@primer/octicons-react": "19.14.0",
-    "@primer/primitives": "^10.3.4",
+    "@primer/primitives": "10.3.4",
     "@primer/react": "36.27.0",
     "@testing-library/react": "16.2.0",
     "@types/jest": "29.5.14",
@@ -158,7 +158,7 @@
     "css-loader": "7.1.2",
     "css-minimizer-webpack-plugin": "7.0.0",
     "date-fns": "4.1.0",
-    "electron": "34.0.0",
+    "electron": "34.0.1",
     "electron-builder": "25.1.8",
     "final-form": "4.20.10",
     "graphql-tag": "2.12.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 830ba6a1..48ae6bb9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,7 +10,7 @@ importers:
     dependencies:
       '@electron/remote':
         specifier: 2.1.2
-        version: 2.1.2(electron@34.0.0)
+        version: 2.1.2(electron@34.0.1)
       electron-log:
         specifier: 5.2.4
         version: 5.2.4
@@ -19,7 +19,7 @@ importers:
         version: 6.3.9
       menubar:
         specifier: 9.5.1
-        version: 9.5.1(electron@34.0.0)
+        version: 9.5.1(electron@34.0.1)
       react:
         specifier: 19.0.0
         version: 19.0.0
@@ -46,7 +46,7 @@ importers:
         specifier: 19.14.0
         version: 19.14.0(react@19.0.0)
       '@primer/primitives':
-        specifier: ^10.3.4
+        specifier: 10.3.4
         version: 10.3.4
       '@primer/react':
         specifier: 36.27.0
@@ -100,8 +100,8 @@ importers:
         specifier: 4.1.0
         version: 4.1.0
       electron:
-        specifier: 34.0.0
-        version: 34.0.0
+        specifier: 34.0.1
+        version: 34.0.1
       electron-builder:
         specifier: 25.1.8
         version: 25.1.8(electron-builder-squirrel-windows@24.13.3)
@@ -1895,8 +1895,8 @@ packages:
   electron-updater@6.3.9:
     resolution: {integrity: sha512-2PJNONi+iBidkoC5D1nzT9XqsE8Q1X28Fn6xRQhO3YX8qRRyJ3mkV4F1aQsuRnYPqq6Hw+E51y27W75WgDoofw==}
 
-  electron@34.0.0:
-    resolution: {integrity: sha512-fpaPb0lifoUJ6UJa4Lk8/0B2Ku/xDZWdc1Gkj67jbygTCrvSon0qquju6Ltx1Kz23GRqqlIHXiy9EvrjpY7/Wg==}
+  electron@34.0.1:
+    resolution: {integrity: sha512-aArw5tAM80i3CKwEREnyZSM1SkARf5Jd1yBMTIdOL4pB1M+p/oDeyWSFI9Dl+vujyfJKiK4SS5+j19wna1onMw==}
     engines: {node: '>= 12.20.55'}
     hasBin: true
 
@@ -4781,9 +4781,9 @@ snapshots:
       - bluebird
       - supports-color
 
-  '@electron/remote@2.1.2(electron@34.0.0)':
+  '@electron/remote@2.1.2(electron@34.0.1)':
     dependencies:
-      electron: 34.0.0
+      electron: 34.0.1
 
   '@electron/universal@1.5.1':
     dependencies:
@@ -6609,7 +6609,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  electron@34.0.0:
+  electron@34.0.1:
     dependencies:
       '@electron/get': 2.0.3
       '@types/node': 20.17.1
@@ -7828,9 +7828,9 @@ snapshots:
 
   mdn-data@2.0.30: {}
 
-  menubar@9.5.1(electron@34.0.0):
+  menubar@9.5.1(electron@34.0.1):
     dependencies:
-      electron: 34.0.0
+      electron: 34.0.1
       electron-positioner: 4.1.0
 
   merge-stream@2.0.0: {}
diff --git a/src/main/main.ts b/src/main/main.ts
index 822d0a76..0f307a00 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -94,9 +94,15 @@ app.whenReady().then(async () => {
 
   nativeTheme.on('updated', () => {
     if (nativeTheme.shouldUseDarkColors) {
-      mb.window.webContents.send(namespacedEvent('update-theme'), 'DARK');
+      mb.window.webContents.send(
+        namespacedEvent('update-theme'),
+        'DARK_DEFAULT',
+      );
     } else {
-      mb.window.webContents.send(namespacedEvent('update-theme'), 'LIGHT');
+      mb.window.webContents.send(
+        namespacedEvent('update-theme'),
+        'LIGHT_DEFAULT',
+      );
     }
   });
 
diff --git a/src/renderer/App.css b/src/renderer/App.css
index 3cfdea64..112ddcde 100644
--- a/src/renderer/App.css
+++ b/src/renderer/App.css
@@ -9,9 +9,15 @@
 @import "@primer/primitives/dist/css/functional/typography/typography.css";
 
 /* Themes and Colors */
-/* TODO Add support for setting color modes (dark_dimmed) - see #1748 */
 @import "@primer/primitives/dist/css/functional/themes/light.css";
+@import "@primer/primitives/dist/css/functional/themes/light-tritanopia.css";
+@import "@primer/primitives/dist/css/functional/themes/light-high-contrast.css";
+@import "@primer/primitives/dist/css/functional/themes/light-colorblind.css";
 @import "@primer/primitives/dist/css/functional/themes/dark.css";
+@import "@primer/primitives/dist/css/functional/themes/dark-colorblind.css";
+@import "@primer/primitives/dist/css/functional/themes/dark-dimmed.css";
+@import "@primer/primitives/dist/css/functional/themes/dark-high-contrast.css";
+@import "@primer/primitives/dist/css/functional/themes/dark-tritanopia.css";
 
 html,
 body,
diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 34a75f1d..28da5949 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -21,6 +21,10 @@ import { NotificationsRoute } from './routes/Notifications';
 import { SettingsRoute } from './routes/Settings';
 
 import './App.css';
+import {
+  DEFAULT_DAY_COLOR_SCHEME,
+  DEFAULT_NIGHT_COLOR_SCHEME,
+} from './utils/theme';
 
 function RequireAuth({ children }) {
   const { isLoggedIn } = useContext(AppContext);
@@ -35,8 +39,11 @@ function RequireAuth({ children }) {
 
 export const App = () => {
   return (
-    // TODO Add support for setting color modes (dark_dimmed) - see #1748
-    <ThemeProvider dayScheme="light" nightScheme="dark">
+    <ThemeProvider
+      colorMode="auto"
+      dayScheme={DEFAULT_DAY_COLOR_SCHEME}
+      nightScheme={DEFAULT_NIGHT_COLOR_SCHEME}
+    >
       <BaseStyles>
         <AppProvider>
           <Router>
diff --git a/src/renderer/components/settings/AppearanceSettings.tsx b/src/renderer/components/settings/AppearanceSettings.tsx
index 506604cc..4567401e 100644
--- a/src/renderer/components/settings/AppearanceSettings.tsx
+++ b/src/renderer/components/settings/AppearanceSettings.tsx
@@ -13,24 +13,34 @@ import {
   TagIcon,
   XCircleIcon,
 } from '@primer/octicons-react';
-import { Button, ButtonGroup, IconButton, useTheme } from '@primer/react';
+import {
+  Button,
+  ButtonGroup,
+  IconButton,
+  Select,
+  useTheme,
+} from '@primer/react';
 
 import { namespacedEvent } from '../../../shared/events';
 import { AppContext } from '../../context/App';
 import { Size, Theme } from '../../types';
 import { hasMultipleAccounts } from '../../utils/auth/utils';
-import { getColorModeFromTheme, setTheme } from '../../utils/theme';
+import {
+  DEFAULT_DAY_COLOR_SCHEME,
+  DEFAULT_NIGHT_COLOR_SCHEME,
+  isDayScheme,
+  setScrollbarTheme,
+} from '../../utils/theme';
 import { zoomLevelToPercentage, zoomPercentageToLevel } from '../../utils/zoom';
 import { Checkbox } from '../fields/Checkbox';
 import { FieldLabel } from '../fields/FieldLabel';
-import { RadioGroup } from '../fields/RadioGroup';
 import { Title } from '../primitives/Title';
 
 let timeout: NodeJS.Timeout;
 const DELAY = 200;
 
 export const AppearanceSettings: FC = () => {
-  const { setColorMode } = useTheme();
+  const { setColorMode, setDayScheme, setNightScheme } = useTheme();
   const { auth, settings, updateSetting } = useContext(AppContext);
   const [zoomPercentage, setZoomPercentage] = useState(
     zoomLevelToPercentage(webFrame.getZoomLevel()),
@@ -41,14 +51,15 @@ export const AppearanceSettings: FC = () => {
       namespacedEvent('update-theme'),
       (_, updatedTheme: Theme) => {
         if (settings.theme === Theme.SYSTEM) {
-          const mode = getColorModeFromTheme(updatedTheme);
-
-          setTheme(updatedTheme);
-          setColorMode(mode);
+          const mode = isDayScheme(updatedTheme) ? 'day' : 'night';
+          setColorMode('auto');
+          setDayScheme(DEFAULT_DAY_COLOR_SCHEME);
+          setNightScheme(DEFAULT_NIGHT_COLOR_SCHEME);
+          setScrollbarTheme(mode);
         }
       },
     );
-  }, [settings.theme, setColorMode]);
+  }, [settings.theme, setColorMode, setDayScheme, setNightScheme]);
 
   window.addEventListener('resize', () => {
     // clear the timeout
@@ -65,20 +76,48 @@ export const AppearanceSettings: FC = () => {
     <fieldset>
       <Title icon={PaintbrushIcon}>Appearance</Title>
 
-      <RadioGroup
-        name="theme"
-        label="Theme:"
-        value={settings.theme}
-        options={[
-          { label: 'System', value: Theme.SYSTEM },
-          { label: 'Light', value: Theme.LIGHT },
-          { label: 'Dark', value: Theme.DARK },
-        ]}
-        onChange={(evt) => updateSetting('theme', evt.target.value as Theme)}
-      />
+      <div className="flex items-center mt-3 mb-2 text-sm">
+        <FieldLabel name="theme" label="Theme:" />
+
+        <Select
+          id="theme"
+          value={settings.theme}
+          onChange={(evt) => updateSetting('theme', evt.target.value as Theme)}
+          data-testid="settings-theme"
+        >
+          <Select.OptGroup label="System">
+            <Select.Option value={Theme.SYSTEM}>System</Select.Option>
+          </Select.OptGroup>
+          <Select.OptGroup label="Light">
+            <Select.Option value={Theme.LIGHT}>Light default</Select.Option>
+            <Select.Option value={Theme.LIGHT_HIGH_CONTRAST}>
+              Light high contrast
+            </Select.Option>
+            <Select.Option value={Theme.LIGHT_COLORBLIND}>
+              Light Protanopia & Deuteranopia
+            </Select.Option>
+            <Select.Option value={Theme.LIGHT_TRITANOPIA}>
+              Light Tritanopia
+            </Select.Option>
+          </Select.OptGroup>
+          <Select.OptGroup label="Dark">
+            <Select.Option value={Theme.DARK}>Dark default</Select.Option>
+            <Select.Option value={Theme.DARK_HIGH_CONTRAST}>
+              Dark high contrast
+            </Select.Option>
+            <Select.Option value={Theme.DARK_COLORBLIND}>
+              Dark Protanopia & Deuteranopia
+            </Select.Option>
+            <Select.Option value={Theme.DARK_TRITANOPIA}>
+              Dark Tritanopia
+            </Select.Option>
+            <Select.Option value={Theme.DARK_DIMMED}>Dark dimmed</Select.Option>
+          </Select.OptGroup>
+        </Select>
+      </div>
 
       <div className="flex items-center mt-3 mb-2 text-sm">
-        <FieldLabel name="zoom" label="Zoom" />
+        <FieldLabel name="zoom" label="Zoom:" />
 
         <ButtonGroup>
           <IconButton
diff --git a/src/renderer/context/App.tsx b/src/renderer/context/App.tsx
index 83fe0563..eff22983 100644
--- a/src/renderer/context/App.tsx
+++ b/src/renderer/context/App.tsx
@@ -49,7 +49,13 @@ import {
 import { Constants } from '../utils/constants';
 import { getNotificationCount } from '../utils/notifications/notifications';
 import { clearState, loadState, saveState } from '../utils/storage';
-import { getColorModeFromTheme, setTheme } from '../utils/theme';
+import {
+  DEFAULT_DAY_COLOR_SCHEME,
+  DEFAULT_NIGHT_COLOR_SCHEME,
+  isDayScheme,
+  mapThemeModeToColorScheme,
+  setScrollbarTheme,
+} from '../utils/theme';
 import { zoomPercentageToLevel } from '../utils/zoom';
 
 export const defaultAuth: AuthState = {
@@ -125,7 +131,7 @@ interface AppContextState {
 export const AppContext = createContext<Partial<AppContextState>>({});
 
 export const AppProvider = ({ children }: { children: ReactNode }) => {
-  const { setColorMode } = useTheme();
+  const { setColorMode, setDayScheme, setNightScheme } = useTheme();
   const [auth, setAuth] = useState<AuthState>(defaultAuth);
   const [settings, setSettings] = useState<SettingsState>(defaultSettings);
   const {
@@ -144,11 +150,18 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
   }, []);
 
   useEffect(() => {
-    const mode = getColorModeFromTheme(settings.theme);
-    setColorMode(mode);
+    const colorScheme = mapThemeModeToColorScheme(settings.theme);
 
-    setTheme(settings.theme); // TODO - Replace fully with Primer design tokens and components
-  }, [settings.theme, setColorMode]);
+    if (isDayScheme(settings.theme)) {
+      setDayScheme(colorScheme ?? DEFAULT_DAY_COLOR_SCHEME);
+      setColorMode('day');
+      setScrollbarTheme('day');
+    } else {
+      setNightScheme(colorScheme ?? DEFAULT_NIGHT_COLOR_SCHEME);
+      setColorMode('night');
+      setScrollbarTheme('night');
+    }
+  }, [settings.theme, setColorMode, setDayScheme, setNightScheme]);
 
   // biome-ignore lint/correctness/useExhaustiveDependencies: We only want fetchNotifications to be called for account changes
   useEffect(() => {
diff --git a/src/renderer/routes/Filters.tsx b/src/renderer/routes/Filters.tsx
index c6c03b3f..9996608f 100644
--- a/src/renderer/routes/Filters.tsx
+++ b/src/renderer/routes/Filters.tsx
@@ -22,7 +22,7 @@ export const FiltersRoute: FC = () => {
   const { settings, clearFilters, updateSetting } = useContext(AppContext);
 
   const updateReasonFilter = (reason: Reason, checked: boolean) => {
-    let reasons: Reason[] = settings.filterReasons;
+    let reasons: Reason[] = [...settings.filterReasons];
 
     if (checked) {
       reasons.push(reason);
diff --git a/src/renderer/types.ts b/src/renderer/types.ts
index a8cfe9d6..b0ee83ec 100644
--- a/src/renderer/types.ts
+++ b/src/renderer/types.ts
@@ -107,7 +107,14 @@ export interface GitifyState {
 export enum Theme {
   SYSTEM = 'SYSTEM',
   LIGHT = 'LIGHT',
+  LIGHT_HIGH_CONTRAST = 'LIGHT_HIGH_CONTRAST',
+  LIGHT_COLORBLIND = 'LIGHT_COLORBLIND',
+  LIGHT_TRITANOPIA = 'LIGHT_TRITANOPIA',
   DARK = 'DARK',
+  DARK_HIGH_CONTRAST = 'DARK_HIGH_CONTRAST',
+  DARK_COLORBLIND = 'DARK_COLORBLIND',
+  DARK_TRITANOPIA = 'DARK_TRITANOPIA',
+  DARK_DIMMED = 'DARK_DIMMED',
 }
 
 export enum OpenPreference {
diff --git a/src/renderer/utils/theme.ts b/src/renderer/utils/theme.ts
index 1e765a97..eb8fccf6 100644
--- a/src/renderer/utils/theme.ts
+++ b/src/renderer/utils/theme.ts
@@ -1,9 +1,9 @@
 import type { ColorModeWithAuto } from '@primer/react/lib/ThemeProvider';
 import { Theme } from '../types';
 
-// TODO Add support for setting color modes (dark_dimmed) - see #1748
+export const DEFAULT_DAY_COLOR_SCHEME = 'light';
+export const DEFAULT_NIGHT_COLOR_SCHEME = 'dark';
 
-// TODO - Replace fully with Octicon primer theme provider
 /**
  * @deprecated
  */
@@ -29,16 +29,19 @@ export function setDarkMode() {
   document.querySelector('html').classList.add('dark');
 }
 
-export function setTheme(theme?: Theme) {
-  switch (theme) {
-    case Theme.LIGHT:
+/**
+ * @deprecated
+ */
+export function setScrollbarTheme(mode?: ColorModeWithAuto) {
+  switch (mode) {
+    case 'day':
+    case 'light':
       setLightMode();
       break;
-
-    case Theme.DARK:
+    case 'night':
+    case 'dark':
       setDarkMode();
       break;
-
     default:
       if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
         setDarkMode();
@@ -48,13 +51,39 @@ export function setTheme(theme?: Theme) {
   }
 }
 
-export function getColorModeFromTheme(theme: Theme): ColorModeWithAuto {
-  switch (theme) {
+export function isDayScheme(themeMode: Theme) {
+  switch (themeMode) {
+    case Theme.LIGHT:
+    case Theme.LIGHT_HIGH_CONTRAST:
+    case Theme.LIGHT_COLORBLIND:
+    case Theme.LIGHT_TRITANOPIA:
+      return true;
+    default:
+      return false;
+  }
+}
+
+export function mapThemeModeToColorScheme(themeMode: Theme): string | null {
+  switch (themeMode) {
     case Theme.LIGHT:
-      return 'day';
+      return 'light';
+    case Theme.LIGHT_HIGH_CONTRAST:
+      return 'light_high_contrast';
+    case Theme.LIGHT_COLORBLIND:
+      return 'light_colorblind';
+    case Theme.LIGHT_TRITANOPIA:
+      return 'light_tritanopia';
     case Theme.DARK:
-      return 'night';
+      return 'dark';
+    case Theme.DARK_HIGH_CONTRAST:
+      return 'dark_high_contrast';
+    case Theme.DARK_COLORBLIND:
+      return 'dark_colorblind';
+    case Theme.DARK_TRITANOPIA:
+      return 'dark_tritanopia';
+    case Theme.DARK_DIMMED:
+      return 'dark_dimmed';
     default:
-      return 'auto';
+      return null;
   }
 }


Test patch:
diff --git a/src/renderer/components/settings/AppearanceSettings.test.tsx b/src/renderer/components/settings/AppearanceSettings.test.tsx
index fd35625f..5864e591 100644
--- a/src/renderer/components/settings/AppearanceSettings.test.tsx
+++ b/src/renderer/components/settings/AppearanceSettings.test.tsx
@@ -17,7 +17,7 @@ describe('renderer/routes/components/settings/AppearanceSettings.tsx', () => {
     jest.clearAllMocks();
   });
 
-  it('should change the theme radio group', async () => {
+  it('should change the theme mode dropdown', async () => {
     await act(async () => {
       render(
         <AppContext.Provider
@@ -34,7 +34,8 @@ describe('renderer/routes/components/settings/AppearanceSettings.tsx', () => {
       );
     });
 
-    fireEvent.click(screen.getByLabelText('Light'));
+    const select = screen.getByTestId('settings-theme') as HTMLSelectElement;
+    fireEvent.change(select, { target: { value: 'LIGHT' } });
 
     expect(updateSetting).toHaveBeenCalledTimes(1);
     expect(updateSetting).toHaveBeenCalledWith('theme', 'LIGHT');
diff --git a/src/renderer/routes/__snapshots__/Settings.test.tsx.snap b/src/renderer/routes/__snapshots__/Settings.test.tsx.snap
index 8a398bd1..69b4ec59 100644
--- a/src/renderer/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/renderer/routes/__snapshots__/Settings.test.tsx.snap
@@ -126,7 +126,7 @@ exports[`renderer/routes/Settings.tsx should render itself & its children 1`] =
           </div>
         </legend>
         <div
-          class="flex items-start my-2 text-sm font-medium"
+          class="flex items-center mt-3 mb-2 text-sm"
         >
           <label
             class="mr-3 font-medium cursor-pointer"
@@ -134,64 +134,93 @@ exports[`renderer/routes/Settings.tsx should render itself & its children 1`] =
           >
             Theme:
           </label>
-          <div
-            aria-labelledby="theme"
-            class="flex items-center space-x-4"
-            role="group"
+          <span
+            class="TextInputWrapper__TextInputBaseWrapper-sc-1mqhpbi-0 TextInputWrapper-sc-1mqhpbi-1 gSHUap iCKcNi"
+            sx="[object Object]"
           >
-            <div
-              class="flex items-center gap-2"
+            <select
+              aria-invalid="false"
+              class="Select__StyledSelect-sc-li6bhs-0 gdxHkq"
+              data-hasplaceholder="false"
+              data-testid="settings-theme"
+              id="theme"
             >
-              <input
-                checked=""
-                class="size-4 cursor-pointer"
-                id="theme_system"
-                name="theme"
-                type="radio"
-                value="SYSTEM"
-              />
-              <label
-                class="mr-3 font-medium cursor-pointer"
-                for="theme_system"
+              <optgroup
+                label="System"
               >
-                System
-              </label>
-            </div>
-            <div
-              class="flex items-center gap-2"
-            >
-              <input
-                class="size-4 cursor-pointer"
-                id="theme_light"
-                name="theme"
-                type="radio"
-                value="LIGHT"
-              />
-              <label
-                class="mr-3 font-medium cursor-pointer"
-                for="theme_light"
+                <option
+                  value="SYSTEM"
+                >
+                  System
+                </option>
+              </optgroup>
+              <optgroup
+                label="Light"
               >
-                Light
-              </label>
-            </div>
-            <div
-              class="flex items-center gap-2"
+                <option
+                  value="LIGHT"
+                >
+                  Light default
+                </option>
+                <option
+                  value="LIGHT_HIGH_CONTRAST"
+                >
+                  Light high contrast
+                </option>
+                <option
+                  value="LIGHT_COLORBLIND"
+                >
+                  Light Protanopia & Deuteranopia
+                </option>
+                <option
+                  value="LIGHT_TRITANOPIA"
+                >
+                  Light Tritanopia
+                </option>
+              </optgroup>
+              <optgroup
+                label="Dark"
+              >
+                <option
+                  value="DARK"
+                >
+                  Dark default
+                </option>
+                <option
+                  value="DARK_HIGH_CONTRAST"
+                >
+                  Dark high contrast
+                </option>
+                <option
+                  value="DARK_COLORBLIND"
+                >
+                  Dark Protanopia & Deuteranopia
+                </option>
+                <option
+                  value="DARK_TRITANOPIA"
+                >
+                  Dark Tritanopia
+                </option>
+                <option
+                  value="DARK_DIMMED"
+                >
+                  Dark dimmed
+                </option>
+              </optgroup>
+            </select>
+            <svg
+              aria-hidden="true"
+              class="Select__ArrowIndicator-sc-li6bhs-1 eMZdJP"
+              fill="currentColor"
+              height="16"
+              width="16"
+              xmlns="http://www.w3.org/2000/svg"
             >
-              <input
-                class="size-4 cursor-pointer"
-                id="theme_dark"
-                name="theme"
-                type="radio"
-                value="DARK"
+              <path
+                d="m4.074 9.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.043 9H4.251a.25.25 0 0 0-.177.427ZM4.074 7.47 7.47 4.073a.25.25 0 0 1 .354 0L11.22 7.47a.25.25 0 0 1-.177.426H4.251a.25.25 0 0 1-.177-.426Z"
               />
-              <label
-                class="mr-3 font-medium cursor-pointer"
-                for="theme_dark"
-              >
-                Dark
-              </label>
-            </div>
-          </div>
+            </svg>
+          </span>
         </div>
         <div
           class="flex items-center mt-3 mb-2 text-sm"
@@ -200,7 +229,7 @@ exports[`renderer/routes/Settings.tsx should render itself & its children 1`] =
             class="mr-3 font-medium cursor-pointer"
             for="zoom"
           >
-            Zoom
+            Zoom:
           </label>
           <div
             class="ButtonGroup-sc-1gxhls1-0 jXbkKi"
diff --git a/src/renderer/utils/storage.test.ts b/src/renderer/utils/storage.test.ts
index 8e08972c..f61e892f 100644
--- a/src/renderer/utils/storage.test.ts
+++ b/src/renderer/utils/storage.test.ts
@@ -18,7 +18,7 @@ describe('renderer/utils/storage.ts', () => {
             },
           ],
         },
-        settings: { theme: 'DARK' },
+        settings: { theme: 'DARK_DEFAULT' },
       }),
     );
     const result = loadState();
@@ -35,7 +35,7 @@ describe('renderer/utils/storage.ts', () => {
     expect(result.auth.token).toBeUndefined();
     expect(result.auth.enterpriseAccounts).toBeUndefined();
     expect(result.auth.user).toBeUndefined();
-    expect(result.settings.theme).toBe('DARK');
+    expect(result.settings.theme).toBe('DARK_DEFAULT');
   });
 
   it('should load the state from localstorage - empty', () => {
diff --git a/src/renderer/utils/theme.test.ts b/src/renderer/utils/theme.test.ts
index a203ea98..e353d13f 100644
--- a/src/renderer/utils/theme.test.ts
+++ b/src/renderer/utils/theme.test.ts
@@ -1,5 +1,9 @@
 import { Theme } from '../types';
-import { getColorModeFromTheme, getTheme, setTheme } from './theme';
+import {
+  getTheme,
+  mapThemeModeToColorScheme,
+  setScrollbarTheme,
+} from './theme';
 
 describe('renderer/utils/theme.ts', () => {
   const htmlElement = document.createElement('html');
@@ -9,12 +13,12 @@ describe('renderer/utils/theme.ts', () => {
   });
 
   it('should change to light mode', () => {
-    setTheme(Theme.LIGHT);
+    setScrollbarTheme('day');
     expect(getTheme()).toBe(Theme.LIGHT);
   });
 
   it('should change to dark mode', () => {
-    setTheme(Theme.DARK);
+    setScrollbarTheme('night');
     expect(getTheme()).toBe(Theme.DARK);
   });
 
@@ -25,7 +29,7 @@ describe('renderer/utils/theme.ts', () => {
         matches: false,
       })),
     });
-    setTheme();
+    setScrollbarTheme();
     expect(getTheme()).toBe(Theme.LIGHT);
   });
 
@@ -36,13 +40,32 @@ describe('renderer/utils/theme.ts', () => {
         matches: true,
       })),
     });
-    setTheme();
+    setScrollbarTheme();
     expect(getTheme()).toBe(Theme.DARK);
   });
 
-  it('should get color mode from theme', () => {
-    expect(getColorModeFromTheme(Theme.LIGHT)).toBe('day');
-    expect(getColorModeFromTheme(Theme.DARK)).toBe('night');
-    expect(getColorModeFromTheme(Theme.SYSTEM)).toBe('auto');
+  it('should map theme mode to github primer provider', () => {
+    expect(mapThemeModeToColorScheme(Theme.LIGHT)).toBe('light');
+    expect(mapThemeModeToColorScheme(Theme.LIGHT_HIGH_CONTRAST)).toBe(
+      'light_high_contrast',
+    );
+    expect(mapThemeModeToColorScheme(Theme.LIGHT_COLORBLIND)).toBe(
+      'light_colorblind',
+    );
+    expect(mapThemeModeToColorScheme(Theme.LIGHT_TRITANOPIA)).toBe(
+      'light_tritanopia',
+    );
+    expect(mapThemeModeToColorScheme(Theme.DARK)).toBe('dark');
+    expect(mapThemeModeToColorScheme(Theme.DARK_HIGH_CONTRAST)).toBe(
+      'dark_high_contrast',
+    );
+    expect(mapThemeModeToColorScheme(Theme.DARK_COLORBLIND)).toBe(
+      'dark_colorblind',
+    );
+    expect(mapThemeModeToColorScheme(Theme.DARK_TRITANOPIA)).toBe(
+      'dark_tritanopia',
+    );
+    expect(mapThemeModeToColorScheme(Theme.DARK_DIMMED)).toBe('dark_dimmed');
+    expect(mapThemeModeToColorScheme(Theme.SYSTEM)).toBe(null);
   });
 });