From a5541745c3e5bf8a667b275f136f34b9d8c670ce Mon Sep 17 00:00:00 2001 From: jeffvli Date: Thu, 22 Jan 2026 01:18:34 -0800 Subject: [PATCH] add toggle for single/multiple home feature carousel (#1581) (#1412) --- src/i18n/locales/en.json | 4 ++ .../features/home/routes/home-route.tsx | 11 ++++- .../general/application-settings.tsx | 42 +++++++++++++++++++ src/renderer/store/settings.store.ts | 10 +++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index ab9fd13de..b51da305d 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -796,6 +796,10 @@ "homeConfiguration": "home page configuration", "homeFeature_description": "controls whether to show the large featured carousel on the home page", "homeFeature": "home featured carousel", + "homeFeatureStyle_description": "controls the style of the home featured carousel", + "homeFeatureStyle": "home featured carousel style", + "homeFeatureStyle_optionMultiple": "multiple", + "homeFeatureStyle_optionSingle": "single", "hotkey_browserBack": "browser back", "hotkey_browserForward": "browser forward", "hotkey_favoriteCurrentSong": "favorite $t(common.currentSong)", diff --git a/src/renderer/features/home/routes/home-route.tsx b/src/renderer/features/home/routes/home-route.tsx index d87ac370d..ae51b4763 100644 --- a/src/renderer/features/home/routes/home-route.tsx +++ b/src/renderer/features/home/routes/home-route.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import { useGridCarouselContainerQuery } from '/@/renderer/components/grid-carousel/grid-carousel-v2'; import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area'; import { AlbumInfiniteCarousel } from '/@/renderer/features/albums/components/album-infinite-carousel'; +import { AlbumInfiniteFeatureCarousel } from '/@/renderer/features/home/components/album-infinite-feature-carousel'; import { AlbumInfiniteSingleFeatureCarousel } from '/@/renderer/features/home/components/album-infinite-single-feature-carousel'; import { FeaturedGenres } from '/@/renderer/features/home/components/featured-genres'; import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; @@ -12,9 +13,11 @@ import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary'; import { SongInfiniteCarousel } from '/@/renderer/features/songs/components/song-infinite-carousel'; import { + HomeFeatureStyle, HomeItem, useCurrentServer, useHomeFeature, + useHomeFeatureStyle, useHomeItems, useWindowSettings, } from '/@/renderer/store'; @@ -35,6 +38,7 @@ const HomeRoute = () => { const server = useCurrentServer(); const { windowBarStyle } = useWindowSettings(); const homeFeature = useHomeFeature(); + const homeFeatureStyle = useHomeFeatureStyle(); const homeItems = useHomeItems(); const containerQuery = useGridCarouselContainerQuery(); @@ -116,7 +120,12 @@ const HomeRoute = () => { px="2rem" ref={containerQuery.ref} > - {homeFeature && } + {homeFeature && homeFeatureStyle === HomeFeatureStyle.SINGLE && ( + + )} + {homeFeature && homeFeatureStyle === HomeFeatureStyle.MULTIPLE && ( + + )} {sortedItems.map((item) => { if (item.id === HomeItem.GENRES) { return ; diff --git a/src/renderer/features/settings/components/general/application-settings.tsx b/src/renderer/features/settings/components/general/application-settings.tsx index 6b804adea..048773728 100644 --- a/src/renderer/features/settings/components/general/application-settings.tsx +++ b/src/renderer/features/settings/components/general/application-settings.tsx @@ -18,6 +18,7 @@ import { SettingsSection, } from '/@/renderer/features/settings/components/settings-section'; import { + HomeFeatureStyle, SideQueueType, useFontSettings, useGeneralSettings, @@ -26,6 +27,7 @@ import { import { type Font, FONT_OPTIONS } from '/@/renderer/types/fonts'; import { FileInput } from '/@/shared/components/file-input/file-input'; import { NumberInput } from '/@/shared/components/number-input/number-input'; +import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control'; import { Select } from '/@/shared/components/select/select'; import { Slider } from '/@/shared/components/slider/slider'; import { Switch } from '/@/shared/components/switch/switch'; @@ -37,6 +39,23 @@ const ipc = isElectron() ? window.api.ipc : null; // Electron 32+ removed file.path, use this which is exposed in preload to get real path const webUtils = isElectron() ? window.electron.webUtils : null; +const HOME_FEATURE_STYLE_OPTIONS = [ + { + label: t('setting.homeFeatureStyle', { + context: 'optionSingle', + postProcess: 'sentenceCase', + }), + value: HomeFeatureStyle.SINGLE, + }, + { + label: t('setting.homeFeatureStyle', { + context: 'optionMultiple', + postProcess: 'sentenceCase', + }), + value: HomeFeatureStyle.MULTIPLE, + }, +]; + const SIDE_QUEUE_OPTIONS = [ { label: t('setting.sidePlayQueueStyle', { @@ -356,6 +375,29 @@ export const ApplicationSettings = memo(() => { isHidden: false, title: t('setting.homeFeature', { postProcess: 'sentenceCase' }), }, + { + control: ( + + setSettings({ + general: { + ...settings, + homeFeatureStyle: e as HomeFeatureStyle, + }, + }) + } + /> + ), + description: t('setting.homeFeature', { + context: 'description', + postProcess: 'sentenceCase', + }), + isHidden: false, + title: t('setting.homeFeature', { postProcess: 'sentenceCase' }), + }, { control: ( export const useHomeFeature = () => useSettingsStore((state) => state.general.homeFeature, shallow); +export const useHomeFeatureStyle = () => + useSettingsStore((state) => state.general.homeFeatureStyle); + export const useHomeItems = () => useSettingsStore((state) => state.general.homeItems, shallow); export const useArtistItems = () => useSettingsStore((state) => state.general.artistItems, shallow);