|
|
|
@@ -1,7 +1,8 @@
|
|
|
|
|
import { css } from '@emotion/css';
|
|
|
|
|
|
|
|
|
|
import { GrafanaTheme2, ThemeRegistryItem } from '@grafana/data';
|
|
|
|
|
import { Drawer, RadioButtonDot, TextLink, useStyles2, useTheme2 } from '@grafana/ui';
|
|
|
|
|
import { FeatureState, GrafanaTheme2, ThemeRegistryItem } from '@grafana/data';
|
|
|
|
|
import { config, reportInteraction } from '@grafana/runtime';
|
|
|
|
|
import { Drawer, FeatureBadge, RadioButtonDot, TextLink, useStyles2, useTheme2 } from '@grafana/ui';
|
|
|
|
|
import { t, Trans } from 'app/core/internationalization';
|
|
|
|
|
import { changeTheme } from 'app/core/services/theme';
|
|
|
|
|
|
|
|
|
@@ -19,12 +20,16 @@ export function ThemeSelectorDrawer({ onClose }: Props) {
|
|
|
|
|
const currentTheme = useTheme2();
|
|
|
|
|
|
|
|
|
|
const onChange = (theme: ThemeRegistryItem) => {
|
|
|
|
|
reportInteraction('grafana_preferences_theme_changed', {
|
|
|
|
|
toTheme: theme.id,
|
|
|
|
|
preferenceType: 'user',
|
|
|
|
|
});
|
|
|
|
|
changeTheme(theme.id, false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const subTitle = (
|
|
|
|
|
<Trans i18nKey="shared-preferences.fields.theme-description">
|
|
|
|
|
Enjoying the limited edition themes? Tell us what you'd like to see{' '}
|
|
|
|
|
Enjoying the experimental themes? Tell us what you'd like to see{' '}
|
|
|
|
|
<TextLink
|
|
|
|
|
variant="bodySmall"
|
|
|
|
|
external
|
|
|
|
@@ -36,11 +41,17 @@ export function ThemeSelectorDrawer({ onClose }: Props) {
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Drawer title={t('profile.change-theme', 'Change theme')} onClose={onClose} size="md" subtitle={subTitle}>
|
|
|
|
|
<Drawer
|
|
|
|
|
title={t('profile.change-theme', 'Change theme')}
|
|
|
|
|
onClose={onClose}
|
|
|
|
|
size="md"
|
|
|
|
|
subtitle={config.feedbackLinksEnabled ? subTitle : undefined}
|
|
|
|
|
>
|
|
|
|
|
<div className={styles.grid} role="radiogroup">
|
|
|
|
|
{themes.map((themeOption) => (
|
|
|
|
|
<ThemeCard
|
|
|
|
|
themeOption={themeOption}
|
|
|
|
|
isExperimental={themeOption.isExtra}
|
|
|
|
|
key={themeOption.id}
|
|
|
|
|
onSelect={() => onChange(themeOption)}
|
|
|
|
|
isSelected={currentTheme.name === themeOption.name}
|
|
|
|
@@ -53,11 +64,12 @@ export function ThemeSelectorDrawer({ onClose }: Props) {
|
|
|
|
|
|
|
|
|
|
interface ThemeCardProps {
|
|
|
|
|
themeOption: ThemeRegistryItem;
|
|
|
|
|
isExperimental?: boolean;
|
|
|
|
|
isSelected?: boolean;
|
|
|
|
|
onSelect: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ThemeCard({ themeOption, isSelected, onSelect }: ThemeCardProps) {
|
|
|
|
|
function ThemeCard({ themeOption, isExperimental, isSelected, onSelect }: ThemeCardProps) {
|
|
|
|
|
const theme = themeOption.build();
|
|
|
|
|
const label = getTranslatedThemeName(themeOption);
|
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
@@ -72,6 +84,7 @@ function ThemeCard({ themeOption, isSelected, onSelect }: ThemeCardProps) {
|
|
|
|
|
onChange={onSelect}
|
|
|
|
|
checked={isSelected}
|
|
|
|
|
/>
|
|
|
|
|
{isExperimental && <FeatureBadge featureState={FeatureState.experimental} />}
|
|
|
|
|
</div>
|
|
|
|
|
<ThemePreview theme={theme} />
|
|
|
|
|
</div>
|
|
|
|
@@ -91,13 +104,17 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|
|
|
|
borderRadius: theme.shape.radius.default,
|
|
|
|
|
display: 'flex',
|
|
|
|
|
flexDirection: 'column',
|
|
|
|
|
overflow: 'hidden',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
'&:hover': {
|
|
|
|
|
border: `1px solid ${theme.colors.border.medium}`,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
header: css({
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
borderBottom: `1px solid ${theme.colors.border.weak}`,
|
|
|
|
|
display: 'flex',
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
padding: theme.spacing(1),
|
|
|
|
|
// The RadioButtonDot is not correctly implemented at the moment, missing cursor (And click ability for the label and input)
|
|
|
|
|
'> label': {
|
|
|
|
|