mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 13:00:13 +02:00
Add image URL generation at runtime to allow for dynamic image sizes (#1439)
* add getImageUrl to domain endpoints * add new ItemImage component and hooks to generate image url * add configuration for image resolution based on types
This commit is contained in:
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import i18n, { languages } from '/@/i18n/i18n';
|
||||
import { ImageResolutionSettings } from '/@/renderer/features/settings/components/general/art-resolution-settings';
|
||||
import { ArtistSettings } from '/@/renderer/features/settings/components/general/artist-settings';
|
||||
import { HomeSettings } from '/@/renderer/features/settings/components/general/home-settings';
|
||||
import {
|
||||
@@ -575,37 +576,13 @@ export const ApplicationSettings = () => {
|
||||
isHidden: false,
|
||||
title: t('setting.playerbarOpenDrawer', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
defaultValue={settings.albumArtRes || undefined}
|
||||
hideControls={false}
|
||||
max={2500}
|
||||
onBlur={(e) => {
|
||||
const newVal =
|
||||
e.currentTarget.value !== '0'
|
||||
? Math.min(Math.max(Number(e.currentTarget.value), 175), 2500)
|
||||
: null;
|
||||
setSettings({ general: { ...settings, albumArtRes: newVal } });
|
||||
}}
|
||||
placeholder="0"
|
||||
value={settings.albumArtRes ?? 0}
|
||||
width={75}
|
||||
/>
|
||||
),
|
||||
description: t('setting.playerAlbumArtResolution', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
isHidden: false,
|
||||
title: t('setting.playerAlbumArtResolution', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<SettingsSection
|
||||
extra={
|
||||
<>
|
||||
<ImageResolutionSettings />
|
||||
<HomeSettings />
|
||||
<ArtistSettings />
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option';
|
||||
import { useGeneralSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { NumberInput } from '/@/shared/components/number-input/number-input';
|
||||
import { Table } from '/@/shared/components/table/table';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: i18n.t('setting.imageResolution_optionTable', { postProcess: 'sentenceCase' }),
|
||||
value: 'table',
|
||||
},
|
||||
{
|
||||
label: i18n.t('setting.imageResolution_optionItemCard', { postProcess: 'sentenceCase' }),
|
||||
value: 'itemCard',
|
||||
},
|
||||
{
|
||||
label: i18n.t('setting.imageResolution_optionSidebar', { postProcess: 'sentenceCase' }),
|
||||
value: 'sidebar',
|
||||
},
|
||||
{
|
||||
label: i18n.t('setting.imageResolution_optionHeader', { postProcess: 'sentenceCase' }),
|
||||
value: 'header',
|
||||
},
|
||||
{
|
||||
label: i18n.t('setting.imageResolution_optionFullScreenPlayer', {
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
value: 'fullScreenPlayer',
|
||||
},
|
||||
];
|
||||
|
||||
export const ImageResolutionSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const { setSettings } = useSettingsStoreActions();
|
||||
const settings = useGeneralSettings();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const descriptionText = t('setting.imageResolution', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
});
|
||||
|
||||
const titleText = t('setting.imageResolution', { postProcess: 'sentenceCase' });
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsOptions
|
||||
control={
|
||||
<>
|
||||
<Button
|
||||
onClick={() => setOpen(!open)}
|
||||
size="compact-md"
|
||||
variant={open ? 'subtle' : 'filled'}
|
||||
>
|
||||
{t(open ? 'common.close' : 'common.edit', { postProcess: 'titleCase' })}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
description={descriptionText}
|
||||
title={titleText}
|
||||
/>
|
||||
{open && (
|
||||
<Table withRowBorders={false}>
|
||||
<Table.Tbody>
|
||||
{options.map((option) => (
|
||||
<Table.Tr key={option.value}>
|
||||
<Table.Th key={option.value}>
|
||||
<Text>{option.label}</Text>
|
||||
</Table.Th>
|
||||
<Table.Td align="right" key={option.value}>
|
||||
<NumberInput
|
||||
max={2000}
|
||||
min={0}
|
||||
onChange={(e) => {
|
||||
if (!e) return;
|
||||
|
||||
if (typeof e === 'string') return;
|
||||
|
||||
setSettings({
|
||||
general: {
|
||||
...settings,
|
||||
imageRes: {
|
||||
...settings.imageRes,
|
||||
[option.value]: e,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
rightSection={
|
||||
<Text isMuted isNoSelect pr="lg" size="sm">
|
||||
px
|
||||
</Text>
|
||||
}
|
||||
value={settings.imageRes[option.value]}
|
||||
width={90}
|
||||
/>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
))}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user