1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

feat: (preferences) migrate display settings to react components

This commit is contained in:
Grady Hallenbeck 2023-10-17 17:54:55 -07:00
parent 0c7fdd671d
commit ce4c7aed5e
11 changed files with 443 additions and 7 deletions

View file

@ -8,5 +8,6 @@ export const ASYNC_USER_ROUTES: AsyncRoute[] = [
{ path: 'movies.html', page: 'movies', type: AsyncRouteType.Experimental },
{ path: 'tv.html', page: 'shows', type: AsyncRouteType.Experimental },
{ path: 'music.html', page: 'music', type: AsyncRouteType.Experimental },
{ path: 'livetv.html', page: 'livetv', type: AsyncRouteType.Experimental }
{ path: 'livetv.html', page: 'livetv', type: AsyncRouteType.Experimental },
{ path: 'mypreferencesdisplay.html', page: 'user/display', type: AsyncRouteType.Experimental }
];

View file

@ -25,12 +25,6 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [
controller: 'user/controls/index',
view: 'user/controls/index.html'
}
}, {
path: 'mypreferencesdisplay.html',
pageProps: {
controller: 'user/display/index',
view: 'user/display/index.html'
}
}, {
path: 'mypreferenceshome.html',
pageProps: {

View file

@ -0,0 +1,95 @@
import Checkbox from '@mui/material/Checkbox';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import React from 'react';
import globalize from 'scripts/globalize';
export function DisplayPreferences() {
return (
<Stack spacing={2}>
<Typography variant='h2'>{globalize.translate('Display')}</Typography>
<FormControl fullWidth>
<Select
aria-describedby='display-settings-layout-description'
label={globalize.translate('LabelDisplayMode')}
>
<MenuItem value='auto'>{globalize.translate('Auto')}</MenuItem>
<MenuItem value='desktop'>{globalize.translate('Desktop')}</MenuItem>
<MenuItem value='mobile'>{globalize.translate('Mobile')}</MenuItem>
<MenuItem value='tv'>{globalize.translate('TV')}</MenuItem>
<MenuItem value='experimental'>{globalize.translate('Experimental')}</MenuItem>
</Select>
<FormHelperText component={Stack} id='display-settings-layout-description'>
<span>{globalize.translate('DisplayModeHelp')}</span>
<span>{globalize.translate('LabelPleaseRestart')}</span>
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<Select label={globalize.translate('LabelTheme')}>
</Select>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-disable-css-description'
control={<Checkbox />}
label={globalize.translate('DisableCustomCss')}
/>
<FormHelperText id='display-settings-disable-css-description'>
{globalize.translate('LabelDisableCustomCss')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<TextField
aria-describedby='display-settings-custom-css-description'
label={globalize.translate('LabelCustomCss')}
multiline
/>
<FormHelperText id='display-settings-custom-css-description'>
{globalize.translate('LabelLocalCustomCss')}
</FormHelperText>
</FormControl>
{/* TODO: There are some admin-only options here */}
{/* Server Dashboard Theme */}
<FormControl fullWidth>
<Select label={globalize.translate('LabelScreensaver')}></Select>
</FormControl>
{/* TODO: There are some extra options here related to screensavers */}
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-faster-animations-description'
control={<Checkbox />}
label={globalize.translate('EnableFasterAnimations')}
/>
<FormHelperText id='display-settings-faster-animations-description'>
{globalize.translate('EnableFasterAnimationsHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-blurhash-description'
control={<Checkbox />}
label={globalize.translate('EnableBlurHash')}
/>
<FormHelperText id='display-settings-blurhash-description'>
{globalize.translate('EnableBlurHashHelp')}
</FormHelperText>
</FormControl>
</Stack>
);
}

View file

@ -0,0 +1,28 @@
import Checkbox from '@mui/material/Checkbox';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import React from 'react';
import globalize from 'scripts/globalize';
export function ItemDetailPreferences() {
return (
<Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('ItemDetails')}</Typography>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-item-details-banner-description'
control={<Checkbox />}
label={globalize.translate('EnableDetailsBanner')}
/>
<FormHelperText id='display-settings-item-details-banner-description'>
{globalize.translate('EnableDetailsBannerHelp')}
</FormHelperText>
</FormControl>
</Stack>
);
}

View file

@ -0,0 +1,81 @@
import Checkbox from '@mui/material/Checkbox';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import React from 'react';
import globalize from 'scripts/globalize';
export function LibraryPreferences() {
return (
<Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('HeaderLibraries')}</Typography>
<FormControl fullWidth>
<TextField
aria-describedby='display-settings-lib-pagesize-description'
inputProps={{
type: 'number',
inputMode: 'numeric',
max: '1000',
min: '0',
pattern: '[0-9]',
required: true,
step: '1'
}}
label={globalize.translate('LabelLibraryPageSize')}
/>
<FormHelperText id='display-settings-lib-pagesize-description'>
{globalize.translate('LabelLibraryPageSizeHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-lib-backdrops-description'
control={<Checkbox />}
label={globalize.translate('Backdrops')}
/>
<FormHelperText id='display-settings-lib-backdrops-description'>
{globalize.translate('EnableBackdropsHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-lib-theme-songs-description'
control={<Checkbox />}
label={globalize.translate('ThemeSongs')}
/>
<FormHelperText id='display-settings-lib-theme-songs-description'>
{globalize.translate('EnableThemeSongsHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-lib-theme-videos-description'
control={<Checkbox />}
label={globalize.translate('ThemeVideos')}
/>
<FormHelperText id='display-settings-lib-theme-videos-description'>
{globalize.translate('EnableThemeVideosHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-show-missing-episodes-description'
control={<Checkbox />}
label={globalize.translate('DisplayMissingEpisodesWithinSeasons')}
/>
<FormHelperText id='display-settings-show-missing-episodes-description'>
{globalize.translate('DisplayMissingEpisodesWithinSeasonsHelp')}
</FormHelperText>
</FormControl>
</Stack>
);
}

View file

@ -0,0 +1,48 @@
import FormControl from '@mui/material/FormControl';
import FormHelperText from '@mui/material/FormHelperText';
import Link from '@mui/material/Link';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import React from 'react';
import globalize from 'scripts/globalize';
import { DATE_LOCALE_OPTIONS, LANGUAGE_OPTIONS } from './constants';
export function LocalizationPreferences() {
return (
<Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('Localization')}</Typography>
<FormControl fullWidth>
<Select
aria-describedby='display-settings-language-description'
label={globalize.translate('LabelDisplayLanguage')}
>
{ ...LANGUAGE_OPTIONS.map(({ value, label }) => (
<MenuItem key={value } value={value}>{ label }</MenuItem>
))}
</Select>
<FormHelperText component={Stack} id='display-settings-language-description'>
<span>{globalize.translate('LabelDisplayLanguageHelp')}</span>
<Link
href='https://github.com/jellyfin/jellyfin'
rel='noopener noreferrer'
target='_blank'
>
{globalize.translate('LearnHowYouCanContribute')}
</Link>
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<Select label={globalize.translate('LabelDateTimeLocale')}>
{...DATE_LOCALE_OPTIONS.map(({ value, label }) => (
<MenuItem key={value} value={value}>{label}</MenuItem>
))}
</Select>
</FormControl>
</Stack>
);
}

View file

@ -0,0 +1,59 @@
import Checkbox from '@mui/material/Checkbox';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import React from 'react';
import globalize from 'scripts/globalize';
export function NextUpPreferences() {
return (
<Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('NextUp')}</Typography>
<FormControl fullWidth>
<TextField
aria-describedby='display-settings-max-days-next-up-description'
inputProps={{
type: 'number',
inputMode: 'numeric',
max: '1000',
min: '0',
pattern: '[0-9]',
required: true,
step: '1'
}}
label={globalize.translate('LabelMaxDaysForNextUp')}
/>
<FormHelperText id='display-settings-max-days-next-up-description'>
{globalize.translate('LabelMaxDaysForNextUpHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-next-up-rewatching-description'
control={<Checkbox />}
label={globalize.translate('EnableRewatchingNextUp')}
/>
<FormHelperText id='display-settings-next-up-rewatching-description'>
{globalize.translate('EnableRewatchingNextUpHelp')}
</FormHelperText>
</FormControl>
<FormControl fullWidth>
<FormControlLabel
aria-describedby='display-settings-next-up-images-description'
control={<Checkbox />}
label={globalize.translate('UseEpisodeImagesInNextUp')}
/>
<FormHelperText id='display-settings-next-up-images-description'>
{globalize.translate('UseEpisodeImagesInNextUpHelp')}
</FormHelperText>
</FormControl>
</Stack>
);
}

View file

@ -0,0 +1,79 @@
import globalize from 'scripts/globalize';
export const LANGUAGE_OPTIONS = [
{ value: 'auto', label: globalize.translate('Auto') },
{ value: 'af', label: 'Afrikaans' },
{ value: 'ar', label: 'العربية' },
{ value: 'be-BY', label: 'Беларуская' },
{ value: 'bg-BG', label: 'Български' },
{ value: 'bn_BD', label: 'বাংলা (বাংলাদেশ)' },
{ value: 'ca', label: 'Català' },
{ value: 'cs', label: 'Čeština' },
{ value: 'cy', label: 'Cymraeg' },
{ value: 'da', label: 'Dansk' },
{ value: 'de', label: 'Deutsch' },
{ value: 'el', label: 'Ελληνικά' },
{ value: 'en-GB', label: 'English (United Kingdom)' },
{ value: 'en-US', label: 'English' },
{ value: 'eo', label: 'Esperanto' },
{ value: 'es', label: 'Español' },
{ value: 'es_419', label: 'Español americano' },
{ value: 'es-AR', label: 'Español (Argentina)' },
{ value: 'es_DO', label: 'Español (Dominicana)' },
{ value: 'es-MX', label: 'Español (México)' },
{ value: 'et', label: 'Eesti' },
{ value: 'eu', label: 'Euskara' },
{ value: 'fa', label: 'فارسی' },
{ value: 'fi', label: 'Suomi' },
{ value: 'fil', label: 'Filipino' },
{ value: 'fr', label: 'Français' },
{ value: 'fr-CA', label: 'Français (Canada)' },
{ value: 'gl', label: 'Galego' },
{ value: 'gsw', label: 'Schwiizerdütsch' },
{ value: 'he', label: 'עִבְרִית' },
{ value: 'hi-IN', label: 'हिन्दी' },
{ value: 'hr', label: 'Hrvatski' },
{ value: 'hu', label: 'Magyar' },
{ value: 'id', label: 'Bahasa Indonesia' },
{ value: 'is-IS', label: 'Íslenska' },
{ value: 'it', label: 'Italiano' },
{ value: 'ja', label: '日本語' },
{ value: 'kk', label: 'Qazaqşa' },
{ value: 'ko', label: '한국어' },
{ value: 'lt-LT', label: 'Lietuvių' },
{ value: 'lv', label: 'Latviešu' },
{ value: 'mk', label: 'Македонски' },
{ value: 'ml', label: 'മലയാളം' },
{ value: 'mr', label: 'मराठी' },
{ value: 'ms', label: 'Bahasa Melayu' },
{ value: 'nb', label: 'Norsk bokmål' },
{ value: 'ne', label: 'नेपाली' },
{ value: 'nl', label: 'Nederlands' },
{ value: 'nn', label: 'Norsk nynorsk' },
{ value: 'pa', label: 'ਪੰਜਾਬੀ' },
{ value: 'pl', label: 'Polski' },
{ value: 'pr', label: 'Pirate' },
{ value: 'pt', label: 'Português' },
{ value: 'pt-BR', label: 'Português (Brasil)' },
{ value: 'pt-PT', label: 'Português (Portugal)' },
{ value: 'ro', label: 'Românește' },
{ value: 'ru', label: 'Русский' },
{ value: 'sk', label: 'Slovenčina' },
{ value: 'sl-SI', label: 'Slovenščina' },
{ value: 'sq', label: 'Shqip' },
{ value: 'sr', label: 'Српски' },
{ value: 'sv', label: 'Svenska' },
{ value: 'ta', label: 'தமிழ்' },
{ value: 'te', label: 'తెలుగు' },
{ value: 'th', label: 'ภาษาไทย' },
{ value: 'tr', label: 'Türkçe' },
{ value: 'uk', label: 'Українська' },
{ value: 'ur_PK', label: ' اُردُو' },
{ value: 'vi', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '汉语 (简化字)' },
{ value: 'zh-TW', label: '漢語 (繁体字)' },
{ value: 'zh-HK', label: '廣東話 (香港)' }
];
// NOTE: Option `Euskara` (eu) does not exist in legacy date locale options.
export const DATE_LOCALE_OPTIONS = LANGUAGE_OPTIONS.filter(({ value }) => value !== 'eu');

View file

@ -0,0 +1,43 @@
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import React from 'react';
import Page from 'components/Page';
import globalize from 'scripts/globalize';
import theme from 'themes/theme';
import { DisplayPreferences } from './DisplayPreferences';
import { LibraryPreferences } from './LibraryPreferences';
import { LocalizationPreferences } from './LocalizationPreferences';
import { NextUpPreferences } from './NextUpPreferences';
export default function UserDisplayPreferences() {
return (
<Page
className='libraryPage userPreferencesPage noSecondaryNavPage'
id='displayPreferencesPage'
title={globalize.translate('Display')}
>
<div className='settingsContainer padded-left padded-right padded-bottom-page'>
<form style={{ margin: 'auto' }}>
<Stack spacing={4}>
<LocalizationPreferences />
<DisplayPreferences />
<LibraryPreferences />
<NextUpPreferences />
<Button
type='submit'
sx={{
color: theme.palette.text.primary,
fontSize: theme.typography.htmlFontSize,
fontWeight: theme.typography.fontWeightBold
}}
>
{globalize.translate('Save')}
</Button>
</Stack>
</form>
</div>
</Page>
);
}

View file

@ -39,6 +39,7 @@ body {
right: 0;
bottom: 0;
contain: strict;
z-index: -1;
}
.layout-mobile,

View file

@ -62,6 +62,13 @@ const theme = createTheme({
variant: 'filled'
}
},
MuiFormHelperText: {
styleOverrides: {
root: {
fontSize: '1rem'
}
}
},
MuiTextField: {
defaultProps: {
variant: 'filled'