Skip to content

Commit

Permalink
Add support for custom themes
Browse files Browse the repository at this point in the history
  • Loading branch information
pimterry committed Sep 9, 2024
1 parent ac5a7f9 commit f545851
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
26 changes: 21 additions & 5 deletions src/components/settings/settings-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SubscriptionPlans } from '@httptoolkit/accounts';
import { WithInjected } from '../../types';
import { styled, Theme, ThemeName } from '../../styles';
import { Icon, WarningIcon } from '../../icons';
import { uploadFile } from '../../util/ui';

import { AccountStore } from '../../model/account/account-store';
import { UiStore } from '../../model/ui/ui-store';
Expand Down Expand Up @@ -290,14 +291,23 @@ class SettingsPage extends React.Component<SettingsPageProps> {
</header>
<TabbedOptionsContainer>
<TabsContainer
onClick={(value: ThemeName | 'automatic' | Theme) => uiStore.setTheme(value)}
isSelected={(value: ThemeName | 'automatic' | Theme) => {
if (typeof value === 'string') {
return uiStore.themeName === value;
onClick={async (value: ThemeName | 'automatic' | 'custom') => {
if (value === 'custom') {
const themeFile = await uploadFile('text', ['.htktheme', '.htk-theme', '.json']);
if (!themeFile) return;
try {
const customTheme = uiStore.buildCustomTheme(themeFile);
uiStore.setTheme(customTheme);
} catch (e: any) {
alert(e.message || e);
}
} else {
return _.isEqual(value, uiStore.theme);
uiStore.setTheme(value);
}
}}
isSelected={(value: ThemeName | 'automatic' | 'custom') =>
uiStore.themeName === value
}
>
<Tab
icon='MagicWand'
Expand All @@ -323,6 +333,12 @@ class SettingsPage extends React.Component<SettingsPageProps> {
>
High Contrast
</Tab>
<Tab
icon='Swatches'
value='custom'
>
Custom
</Tab>
</TabsContainer>
<ThemeColors>
<ThemeColorBlock themeColor='mainColor' />
Expand Down
6 changes: 4 additions & 2 deletions src/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
MagicWand,
Sun,
Moon,
CircleHalf
CircleHalf,
Swatches
} from '@phosphor-icons/react';

export type IconKey = keyof typeof Icons;
Expand Down Expand Up @@ -53,7 +54,8 @@ const Icons = {
MagicWand,
Sun,
Moon,
CircleHalf
CircleHalf,
Swatches
} as const;

// Import required FA icons:
Expand Down
20 changes: 20 additions & 0 deletions src/model/ui/ui-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ContextMenuOption,
buildNativeContextMenuItems
} from './context-menu';
import { tryParseJson } from '../../util';

const VIEW_CARD_KEYS = [
'api',
Expand Down Expand Up @@ -93,6 +94,11 @@ const SETTINGS_CARD_KEYS =[
] as const;
type SettingsCardKey = typeof SETTINGS_CARD_KEYS[number];

type CustomTheme = Partial<Theme> & {
name: string;
extends: ThemeName;
};

export class UiStore {

constructor(
Expand Down Expand Up @@ -146,6 +152,20 @@ export class UiStore {
}
}

buildCustomTheme(themeFile: string) {
const themeData: Partial<CustomTheme> | undefined = tryParseJson(themeFile);
if (!themeData) throw new Error("Could not parse theme JSON");

if (!themeData.name) throw new Error('Theme must contain a `name` field');
if (!themeData.extends) throw new Error('Theme must contain an `extends` field with a built-in theme name (dark/light/high-contrast)');

const baseTheme = Themes[themeData.extends];
return {
...baseTheme,
...themeData
} as Theme;
}

@persist @observable
private _themeName: ThemeName | 'automatic' | 'custom' = 'automatic';

Expand Down

0 comments on commit f545851

Please sign in to comment.