-
-
Notifications
You must be signed in to change notification settings - Fork 432
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add "Appearance" pane to preferences (#816)
Co-authored-by: Mo <[email protected]>
- Loading branch information
1 parent
c232a5e
commit da1d4f7
Showing
11 changed files
with
307 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
196 changes: 196 additions & 0 deletions
196
app/assets/javascripts/preferences/panes/Appearance.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import { Dropdown, DropdownItem } from '@/components/Dropdown'; | ||
import { PremiumModalProvider, usePremiumModal } from '@/components/Premium'; | ||
import { sortThemes } from '@/components/QuickSettingsMenu/QuickSettingsMenu'; | ||
import { HorizontalSeparator } from '@/components/shared/HorizontalSeparator'; | ||
import { Switch } from '@/components/Switch'; | ||
import { WebApplication } from '@/ui_models/application'; | ||
import { Features } from '@standardnotes/features'; | ||
import { | ||
ContentType, | ||
FeatureIdentifier, | ||
FeatureStatus, | ||
PrefKey, | ||
SNTheme, | ||
} from '@standardnotes/snjs'; | ||
import { observer } from 'mobx-react-lite'; | ||
import { FunctionComponent } from 'preact'; | ||
import { useEffect, useState } from 'preact/hooks'; | ||
import { | ||
PreferencesGroup, | ||
PreferencesPane, | ||
PreferencesSegment, | ||
Subtitle, | ||
Title, | ||
Text, | ||
} from '../components'; | ||
|
||
type Props = { | ||
application: WebApplication; | ||
}; | ||
|
||
const AppearancePane: FunctionComponent<Props> = observer(({ application }) => { | ||
const premiumModal = usePremiumModal(); | ||
const isEntitledToMidnightTheme = | ||
application.getFeatureStatus(FeatureIdentifier.MidnightTheme) === | ||
FeatureStatus.Entitled; | ||
|
||
const [themeItems, setThemeItems] = useState<DropdownItem[]>([]); | ||
const [autoLightTheme, setAutoLightTheme] = useState<string>( | ||
() => | ||
application.getPreference( | ||
PrefKey.AutoLightThemeIdentifier, | ||
'Default' | ||
) as string | ||
); | ||
const [autoDarkTheme, setAutoDarkTheme] = useState<string>( | ||
() => | ||
application.getPreference( | ||
PrefKey.AutoDarkThemeIdentifier, | ||
isEntitledToMidnightTheme ? FeatureIdentifier.MidnightTheme : 'Default' | ||
) as string | ||
); | ||
const [useDeviceSettings, setUseDeviceSettings] = useState( | ||
() => | ||
application.getPreference(PrefKey.UseSystemColorScheme, false) as boolean | ||
); | ||
|
||
useEffect(() => { | ||
const themesAsItems: DropdownItem[] = ( | ||
application.getDisplayableItems(ContentType.Theme) as SNTheme[] | ||
) | ||
.filter((theme) => !theme.isLayerable()) | ||
.sort(sortThemes) | ||
.map((theme) => { | ||
return { | ||
label: theme.name, | ||
value: theme.identifier as string, | ||
}; | ||
}); | ||
|
||
Features.filter( | ||
(feature) => | ||
feature.content_type === ContentType.Theme && !feature.layerable | ||
).forEach((theme) => { | ||
if ( | ||
themesAsItems.findIndex((item) => item.value === theme.identifier) === | ||
-1 | ||
) { | ||
themesAsItems.push({ | ||
label: theme.name as string, | ||
value: theme.identifier, | ||
icon: 'premium-feature', | ||
}); | ||
} | ||
}); | ||
|
||
themesAsItems.unshift({ | ||
label: 'Default', | ||
value: 'Default', | ||
}); | ||
|
||
setThemeItems(themesAsItems); | ||
}, [application]); | ||
|
||
const toggleUseDeviceSettings = () => { | ||
application.setPreference(PrefKey.UseSystemColorScheme, !useDeviceSettings); | ||
if (!application.getPreference(PrefKey.AutoLightThemeIdentifier)) { | ||
application.setPreference( | ||
PrefKey.AutoLightThemeIdentifier, | ||
autoLightTheme as FeatureIdentifier | ||
); | ||
} | ||
if (!application.getPreference(PrefKey.AutoDarkThemeIdentifier)) { | ||
application.setPreference( | ||
PrefKey.AutoDarkThemeIdentifier, | ||
autoDarkTheme as FeatureIdentifier | ||
); | ||
} | ||
setUseDeviceSettings(!useDeviceSettings); | ||
}; | ||
|
||
const changeAutoLightTheme = (value: string, item: DropdownItem) => { | ||
if (item.icon === 'premium-feature') { | ||
premiumModal.activate(`${item.label} theme`); | ||
} else { | ||
application.setPreference( | ||
PrefKey.AutoLightThemeIdentifier, | ||
value as FeatureIdentifier | ||
); | ||
setAutoLightTheme(value); | ||
} | ||
}; | ||
|
||
const changeAutoDarkTheme = (value: string, item: DropdownItem) => { | ||
if (item.icon === 'premium-feature') { | ||
premiumModal.activate(`${item.label} theme`); | ||
} else { | ||
application.setPreference( | ||
PrefKey.AutoDarkThemeIdentifier, | ||
value as FeatureIdentifier | ||
); | ||
setAutoDarkTheme(value); | ||
} | ||
}; | ||
|
||
return ( | ||
<PreferencesPane> | ||
<PreferencesGroup> | ||
<PreferencesSegment> | ||
<Title>Themes</Title> | ||
<div className="mt-2"> | ||
<div className="flex items-center justify-between"> | ||
<div className="flex flex-col"> | ||
<Subtitle>Use system color scheme</Subtitle> | ||
<Text> | ||
Automatically change active theme based on your system settings. | ||
</Text> | ||
</div> | ||
<Switch | ||
onChange={toggleUseDeviceSettings} | ||
checked={useDeviceSettings} | ||
/> | ||
</div> | ||
<HorizontalSeparator classes="mt-5 mb-3" /> | ||
<div> | ||
<Subtitle>Automatic Light Theme</Subtitle> | ||
<Text>Theme to be used for system light mode:</Text> | ||
<div className="mt-2"> | ||
<Dropdown | ||
id="auto-light-theme-dropdown" | ||
label="Select the automatic light theme" | ||
items={themeItems} | ||
value={autoLightTheme} | ||
onChange={changeAutoLightTheme} | ||
disabled={!useDeviceSettings} | ||
/> | ||
</div> | ||
</div> | ||
<HorizontalSeparator classes="mt-5 mb-3" /> | ||
<div> | ||
<Subtitle>Automatic Dark Theme</Subtitle> | ||
<Text>Theme to be used for system dark mode:</Text> | ||
<div className="mt-2"> | ||
<Dropdown | ||
id="auto-dark-theme-dropdown" | ||
label="Select the automatic dark theme" | ||
items={themeItems} | ||
value={autoDarkTheme} | ||
onChange={changeAutoDarkTheme} | ||
disabled={!useDeviceSettings} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</PreferencesSegment> | ||
</PreferencesGroup> | ||
</PreferencesPane> | ||
); | ||
}); | ||
|
||
export const Appearance: FunctionComponent<Props> = observer( | ||
({ application }) => ( | ||
<PremiumModalProvider state={application.getAppState().features}> | ||
<AppearancePane application={application} /> | ||
</PremiumModalProvider> | ||
) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.