From 1482187a9bac0a175bb27edf29c3975ca8c1d7e5 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Sat, 7 Oct 2023 21:47:00 -0500 Subject: [PATCH] Add dracula theme (#754) --- .../appearance/themes/appTheme/AppTheme.tsx | 35 +++++++++++++++++-- .../themes/appTheme/AppThemePreview.tsx | 31 ++++++++++++++-- src/services/db.ts | 1 + src/theme/AppThemes.ts | 15 ++++++++ src/theme/variables.ts | 23 +++++++++++- 5 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/features/settings/appearance/themes/appTheme/AppTheme.tsx b/src/features/settings/appearance/themes/appTheme/AppTheme.tsx index 5e0bfa10ec..3770626d88 100644 --- a/src/features/settings/appearance/themes/appTheme/AppTheme.tsx +++ b/src/features/settings/appearance/themes/appTheme/AppTheme.tsx @@ -1,10 +1,19 @@ -import { IonLabel, IonList, IonRadio, IonRadioGroup } from "@ionic/react"; +import { + IonLabel, + IonList, + IonRadio, + IonRadioGroup, + useIonAlert, +} from "@ionic/react"; import { InsetIonItem, ListHeader } from "../../../shared/formatting"; import AppThemePreview from "./AppThemePreview"; import { AppThemeType, OAppThemeType } from "../../../../../services/db"; import { useAppDispatch, useAppSelector } from "../../../../../store"; import { setTheme } from "../../../settingsSlice"; import styled from "@emotion/styled"; +import { getTheme } from "../../../../../theme/AppThemes"; +import { capitalize } from "lodash"; +import { useTheme } from "@emotion/react"; const Description = styled.div` font-size: 0.76em; @@ -14,6 +23,24 @@ const Description = styled.div` export default function AppTheme() { const theme = useAppSelector((state) => state.settings.appearance.theme); const dispatch = useAppDispatch(); + const [presentAlert] = useIonAlert(); + const userTheme = useTheme(); + + function onChangeTheme(themeName: AppThemeType) { + dispatch(setTheme(themeName)); + + const theme = getTheme(themeName); + + if (theme.dark.background && !theme.light.background && !userTheme.dark) { + presentAlert({ + header: `${capitalize(themeName)} Looks Best Dark`, + message: `Just as a heads up, you're in the light theme currently but ${capitalize( + themeName, + )} looks best with a darker theme. You might want to change it to get the full effect, or you do you!`, + buttons: ["OK"], + }); + } + } return ( <> @@ -22,7 +49,7 @@ export default function AppTheme() { dispatch(setTheme(e.detail.value))} + onIonChange={(e) => onChangeTheme(e.detail.value)} > {Object.values(OAppThemeType).map((theme) => ( @@ -55,6 +82,8 @@ function getThemeName(appTheme: AppThemeType): string { return "Ultraviolet"; case "mint": return "Mint"; + case "dracula": + return "Dracula"; } } @@ -72,5 +101,7 @@ function getThemeDescription(appTheme: AppThemeType): string { return "Windows logo jack-o-lantern?"; case "mint": return "Life is mint to be refreshing!"; + case "dracula": + return "Your Phone, Now Undeadly Cool"; } } diff --git a/src/features/settings/appearance/themes/appTheme/AppThemePreview.tsx b/src/features/settings/appearance/themes/appTheme/AppThemePreview.tsx index b010a52dd5..d139829841 100644 --- a/src/features/settings/appearance/themes/appTheme/AppThemePreview.tsx +++ b/src/features/settings/appearance/themes/appTheme/AppThemePreview.tsx @@ -1,16 +1,43 @@ import styled from "@emotion/styled"; import { AppThemeType } from "../../../../../services/db"; import { getThemeByStyle } from "../../../../../theme/AppThemes"; +import { css } from "@emotion/react"; const Container = styled.div<{ appTheme: AppThemeType }>` - width: 22px; - height: 22px; + --size: 22px; + + width: var(--size); + height: var(--size); border-radius: 6px; margin-right: 16px; background: ${({ appTheme, theme }) => getThemeByStyle(appTheme, theme.dark ? "dark" : "light").primary}; + + position: relative; + overflow: hidden; + + ${({ appTheme, theme }) => + getThemeByStyle(appTheme, theme.dark ? "dark" : "light").background + ? css` + &:after { + content: ""; + position: absolute; + top: 0; + left: 0; + + width: 0; + height: 0; + border-left: var(--size) solid transparent; + border-right: var(--size) solid transparent; + + border-bottom: var(--size) solid + ${getThemeByStyle(appTheme, theme.dark ? "dark" : "light") + .background}; + } + ` + : ""}; `; interface AppThemePreviewProps { diff --git a/src/services/db.ts b/src/services/db.ts index fecc62afe1..fe7329fafb 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -15,6 +15,7 @@ export const OAppThemeType = { SpookyPumpkin: "pumpkin", UV: "uv", Mint: "mint", + Dracula: "dracula", } as const; export type AppThemeType = (typeof OAppThemeType)[keyof typeof OAppThemeType]; diff --git a/src/theme/AppThemes.ts b/src/theme/AppThemes.ts index 3135c5dea5..1926a25cc7 100644 --- a/src/theme/AppThemes.ts +++ b/src/theme/AppThemes.ts @@ -7,6 +7,9 @@ interface Theme { interface Colors { primary: string; + background?: string; + insetItemBackground?: string; + tabBarBackground?: string; } export function getTheme(appTheme: AppThemeType): Theme { @@ -65,6 +68,18 @@ export function getTheme(appTheme: AppThemeType): Theme { primary: "#53C391", }, }; + case "dracula": + return { + light: { + primary: "#AD81FF", + }, + dark: { + primary: "#AD81FF", + background: "#1A1D29", + insetItemBackground: "#12141C", + tabBarBackground: "#12141C", + }, + }; } } diff --git a/src/theme/variables.ts b/src/theme/variables.ts index a4b29b1670..51abf19af6 100644 --- a/src/theme/variables.ts +++ b/src/theme/variables.ts @@ -146,7 +146,8 @@ export const buildDarkVariables = ( appTheme: AppThemeType, pureBlack: boolean, ) => { - const { primary } = getThemeByStyle(appTheme, "dark"); + const { primary, background, insetItemBackground, tabBarBackground } = + getThemeByStyle(appTheme, "dark"); return css` // Dark Colors @@ -361,5 +362,25 @@ export const buildDarkVariables = ( --ion-toolbar-border-color: var(--ion-color-step-150); } } + + ${background + ? css` + .ios body, + .md body { + --ion-background-color: ${background}; + --ion-item-background: ${background}; + --ion-color-step-50: ${insetItemBackground}; + --ion-color-step-100: ${tabBarBackground}; + --ion-tab-bar-background: ${tabBarBackground}; + --ion-toolbar-background: ${tabBarBackground}; + } + + .ios ion-modal:not(.small) { + --ion-background-color: ${background}; + --ion-toolbar-background: ${tabBarBackground}; + --ion-toolbar-border-color: var(--ion-color-step-150); + } + ` + : ""} `; };